社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

从Python交互运行多个Bash命令

Vainmonde De Courtenay • 3 年前 • 1218 次点击  

我刚刚遇到 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)

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

现在,上述方法奏效了。信息技术 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 价值——但不确定是否有更好的实践。)

重写上述代码的最佳方式是什么?我把这两个问题归为一个问题,因为我想有一个更好的使用方法 预期 ,这可以解决这两个问题(可能还有其他我还不知道的问题!),总的来说,我会邀请大家展示完成这类任务的最佳方式。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/131399
 
1218 次点击  
文章 [ 1 ]  |  最新文章 3 年前
Barmar
Reply   •   1 楼
Barmar    4 年前

你不需要等待 # 在每个命令之间。您可以发送所有命令,忽略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 timeout with large block of data from child

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

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() 呼叫