繁体   English   中英

从 Python 以交互方式运行多个 Bash 命令

[英]Running multiple Bash commands interactively from Python

我刚刚遇到pexpect并且一直在研究如何使用它来自动化各种实践,否则我将不得不在命令 shell 中手动填写。

这是一个示例脚本:

import pexpect, sys

child = pexpect.spawn("bash", timeout=60)
child.logfile = sys.stdout
child.sendline("cd /workspace/my_notebooks/code_files")
child.expect('#')
child.sendline('ls')
child.expect('#')
child.sendline('git add .')
child.expect('#')
child.sendline('git commit')
child.expect('#')
child.sendline('git push origin main')
child.expect('Username .*:')
child.sendline(<my_github_username>)
child.expect('Password .*:')
child.sendline(<my_github_password>)
child.expect('#')
child.expect(pexpect.EOF)

(我知道这些特定任务不一定需要pexpect ,只是想了解它的最佳实践。)

现在,上述工作。 cd到我的本地 repo 文件夹,在那里列出文件,暂存我的提交,并通过身份验证推送到 Github,同时向 ZA7F5F35426B92741738 stdout1B563 提供实时 output。 但我有两个方面需要改进:

首先,我将在 Bash(不需要交互性)中运行的每一行之间.expect('#')有点乏味。 (而且我不确定它是否/为什么似乎总是有效,无论标准输出中的 output 是什么——尽管到目前为止它确实有效。)理想情况下,我可以将它们聚集成一个多行字符串并省去所有那些expect s。 难道没有更自然的方法来自动化脚本的某些部分,例如,一个多行字符串,其中 Bash 命令用“;”分隔或'&&'或'||'?

其次,如果你像上面那样运行一个脚本,你会看到它在 60 秒后超时,然后在 Python 中产生一个 TimeoutError。 虽然 - 假设工作在 60 秒内完成 - 它可以完成,但我更喜欢(1)不会花费不必要的时间,(2)不会冒中途中断 > 60 秒过程的风险,(3)不会t 结束整个事情给我 Python 的错误。 我们是否可以让它自然结束,即当 shell 进程完成时,它也停止在 Python 中运行? (如果可以解决(2)和(3),我可能只设置一个巨大的timeout值 - 但不确定是否有更好的做法。)

重写上面代码的最佳方法是什么? 我将这两个问题归为一个问题,因为我的猜测是通常有一种更好的使用pexpect的方法,它可以解决这两个问题(可能还有其他我什至不知道的问题)。 总的来说,我会邀请他们展示完成此类任务的最佳方式。

您无需在每个命令之间等待# 您可以只发送所有命令而忽略 shell 提示。 shell 缓冲所有输入。

您只需要等待用户名和密码提示,然后在最后一个命令之后的最后一个#

最后还需要发送exit命令,否则不会得到EOF。

import pexpect, sys

child = pexpect.spawn("bash", timeout=60)
child.logfile = sys.stdout
child.sendline("cd /workspace/my_notebooks/code_files")
child.sendline('ls')
child.sendline('git add .')
child.sendline('git commit')
child.sendline('git push origin main')
child.expect('Username .*:')
child.sendline(<my_github_username>)
child.expect('Password .*:')
child.sendline(<my_github_password>)
child.expect('#')
child.sendline('exit')
child.expect(pexpect.EOF)

如果您遇到 60 秒超时,您可以使用timeout=None禁用此功能。 看到来自孩子的大块数据的 pexpect 超时

您还可以在一行中组合多个命令:

import pexpect, sys

child = pexpect.spawn("bash", timeout=60)
child.logfile = sys.stdout
child.sendline("cd /workspace/my_notebooks/code_files && ls && git add . && git commit && git push origin main')
child.expect('Username .*:')
child.sendline(<my_github_username>)
child.expect('Password .*:')
child.sendline(<my_github_password>)
child.expect('#')
child.sendline('exit')
child.expect(pexpect.EOF)

在命令之间使用&&可确保在其中任何一个失败时停止。

一般来说,我根本不建议使用pexpect 制作一个 shell 脚本来执行您想要的所有操作,然后使用单个subprocess.Popen()调用运行该脚本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM