Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从Python交互运行多个Bash命令_Python_Bash_Pexpect - Fatal编程技术网

从Python交互运行多个Bash命令

从Python交互运行多个Bash命令,python,bash,pexpect,Python,Bash,Pexpect,我刚刚遇到了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('#')

我刚刚遇到了
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)
导入预期,系统
child=pexpect.spawn(“bash”,超时=60)
child.logfile=sys.stdout
sendline(“cd/工作区/我的笔记本/代码文件”)
child.expect(“#”)
child.sendline('ls')
child.expect(“#”)
child.sendline('git add'))
child.expect(“#”)
sendline('git commit')
child.expect(“#”)
sendline('git push origin main')
expect('Username.*:')
child.sendline()
expect('Password.*:')
child.sendline()
child.expect(“#”)
child.expect(peexpect.EOF)
(我知道这些特定任务不一定需要
pexpect
,只是试图了解其最佳实践。)

现在,上面的工作。它
cd
s到我的本地repo文件夹,列出那里的文件,进行提交,并通过身份验证推送到Github,同时向Python标准输出提供实时输出。但我有两个方面需要改进:

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

其次,如果您运行像上面这样的脚本,您将看到它在60秒之后超时,然后在Python中产生一个TimeoutError。虽然-假设工作在60秒内完成-但我更喜欢(1)不会花费不必要的时间,(2)不会中途中断>60秒的进程,(3)不会结束整件事,给我一个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)
在命令之间使用
&&
可确保在任何命令失败时停止


一般来说,我根本不建议使用
pexpect
。制作一个可以执行所有操作的shell脚本,并通过一个
subprocess.Popen()
调用运行该脚本。

您不需要在每个命令之间等待
#
。您可以只发送所有命令而忽略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)
在命令之间使用
&&
可确保在任何命令失败时停止


一般来说,我根本不建议使用
pexpect
。制作一个可以执行所有操作的shell脚本,并通过一个
subprocess.Popen()
调用运行该脚本。

我认为最好的方法是根本不需要用户输入:,然后以非交互方式运行脚本。我的注释核心保持不变:如果可能,不要使用
pexpect
,因为找到需要交互的任务是非常罕见的;通常,仅执行带有适当标准输入的脚本就足够了。这几乎总是一个问题。正如我为
git
给出的解决方案一样,
pexpect
的大多数其他用例都可以通过其他方法解决,这些方法没有
pexpect
的缺点(您在帖子中正确地指出了这些缺点)。通常,最好的方法是不使用pexpect。命令输出很容易更改,并且没有记录编程使用。换句话说,很难提前计划所有可能的输出并正确处理它们。如果你正在寻找一个能解决你可能遇到的每一个问题的例子,特别是,这是一个对大量问题的大量答案的要求。当然,各种问题都有解决办法(生成UUID用作提示,f/e);但这些都是他们自己的问题,一般来说,最好的做法是不要使用pexpect,除非你没有其他选择。(从stdin发出提示的软件很少指定这些提示的形式和顺序,作为该程序兼容性保证的一部分,因为期望在另一端有一个人可以观察到新版本添加了一个额外的提示,在看到用户名或密码提示之前需要回答该提示,or一些罕见的运行时环境会改变提示,f/e;这是在我们开始担心语言和语言环境问题之前)。我认为最好的方法是根本不需要用户输入:,然后以非交互方式运行脚本。我的评论的核心仍然是:如果可能的话,不要使用
pexpect