如何使用Python Popen实现多个参数?

27

我正在尝试制作一个PyGtk GUI,其中包含一个按钮。 当用户按下此按钮时,gnome-terminal提示用户输入其密码。

然后,它将克隆这个Git仓库以获取gedit JQuery片段。

然后,将js.xml文件复制到/usr/share/gedit/plugins/snippets/js.xml

最后,强制删除Git仓库。

命令:

gnome-terminal -x sudo git clone git://github.com/pererinha/gedit-snippet-jquery.git && sudo cp -f gedit-snippet-jquery/js.xml /usr/share/gedit/plugins/snippets/js.xml && sudo rm -rf gedit-snippet-jquery

在我的终端中它可以正常工作。

但是通过GUI只是打开,我输入密码,按下回车,然后又关闭了。

我想要只执行第一个&&之前的命令。

这是我的Python函数(带有命令):

def on_install_jquery_code_snippet_for_gedit_activate(self, widget):
    """ Install Jquery code snippet for Gedit. """
    cmd="gnome-terminal -x sudo git clone git://github.com/pererinha/gedit-snippet-jquery.git && sudo cp -f gedit-snippet-jquery/js.xml /usr/share/gedit/plugins/snippets/js.xml && sudo rm -rf gedit-snippet-jquery"
    p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
             close_fds=False)
    self.status.set_text(p.stdout.read()) #show response in 'status
1个回答

75

直接回答你的问题,请往下看。但是你的程序存在很多问题,其中一些我在“最佳实践”中有所涉及。


默认情况下,subprocess.Popen 命令被提供为一个字符串列表。

然而,你也可以使用 shell 参数来执行一个命令,它“格式与在 shell 提示符下键入的完全相同。”

不推荐:

>>> p = Popen("cat -n file1 file2")

是的:

>>> p = Popen("cat -n file1 file2", shell=True)
>>> p = Popen(["cat", "-n", "file1", "file2"])

这两个选项之间有许多差异,每个都有其有效的使用案例。我不会试图总结这些差异 - Popen文档已经很好地完成了这项工作。


因此,在您的命令的情况下,您可以这样做:

cmd = "gnome-terminal -x sudo git clone git://github.com/pererinha/gedit-snippet-jquery.git && sudo cp -f gedit-snippet-jquery/js.xml /usr/share/gedit/plugins/snippets/js.xml && sudo rm -rf gedit-snippet-jquery"
p = Popen(cmd, shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT,
          close_fds=False)

更好的做法

然而,使用Python作为许多系统命令的包装器并不是一个好主意。至少,你应该将命令拆分为单独的Popens,以便可以充分处理非零退出。实际上,这个脚本似乎更适合作为shell脚本。但如果你坚持要用Python,有更好的做法。

os模块应该代替对rmcp的调用。另外,虽然我没有使用过,但你可能需要看一下像GitPython这样的工具来与Git存储库交互。

兼容性问题

最后,你应该小心地调用gnome-terminalsudo。并非所有GNU/Linux用户都在运行Ubuntu,也不是每个人都安装了sudo或GNOME终端仿真器。以当前形式,你的脚本会崩溃,并且没有提供帮助,如果:

  • sudo命令未安装
  • 用户不在sudoers组中
  • 用户不使用GNOME或其默认终端仿真器
  • Git未安装

如果你愿意假设你的用户在运行Ubuntu,调用x-terminal-emulator比直接调用gnome-terminal要好得多,因为它将调用他们安装的任何终端仿真器(例如Xubuntu用户使用xfce4-terminal)。


1
避免字符串分割,在shell命令中使用shlex.split。 - Massimo
另外,shlex.split()函数会保留引号中的参数,并将命令进行拆分。 - sandyp
1
不要在 POSIX 上使用 shell=True 传递列表参数(附加的列表项将传递给 /bin/sh,而不是命令)- 在大多数情况下,您不需要它。使用字符串代替(即,如果使用 shell=True,则删除 shlex.split())。 - jfs
已经注意到了,@J.F.Sebastian。我再次阅读了文档,并修改了我的答案以符合那里的建议。感谢您指出这一点。 - David Cain
这真的没有帮助。为什么我们不应该做你列出的任何示例?你没有提供任何实际的理由来支持你的说法,那我为什么要相信你所说的任何事情呢? - JamEngulfer
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接