如何用 Python Popen 做多个参数?

问题描述

我正在尝试制作一个带有按钮的 PyGtk Gui.当用户按下此按钮时,gnome-terminal 提示用户输入密码.

I am trying to make a PyGtk Gui, that has a button. When the user presses this button, gnome-terminal prompts the user to write their password.

然后它将为 gedit JQuery 片段.

Then it will clone this Git repository for gedit JQuery snippets.

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

And then, it copies the js.xml file to /usr/share/gedit/plugins/snippets/js.xml

最后,它强行删除了 Git 存储库.

In the end, it forcefully removes the Git repository.

命令:

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

它在我的终端上运行良好.

It works fine in my terminal.

但是, 通过它刚刚打开的 GUI,我添加了我的密码,按 Enter,然后它再次关闭.

But, via the GUI it just opens, I add my password, press enter, and then it closes again.

我只想将命令运行到第一个 &&

I'd like to only run the command to the first &&

这是我的 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


解决方案

要直接回答您的问题,请阅读下文.但是您的程序存在很多问题,其中一些我在更好的实践"中进行了介绍.

To directly answer your question, read below. But there's a lot of problems with your program, some of which I cover in "Better practice."

默认情况下,subprocess.Popen 命令以字符串列表的形式提供.

By default, subprocess.Popen commands are supplied as a list of strings.

但是,您也可以使用 shell 参数来执行格式与在 shell 提示符下键入时完全一样"的命令.

However, you can also you can use the shell argument to execute a command "formatted exactly as it would be when typed at the shell prompt."

否:

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

是的:

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

这两个选项之间存在许多差异,并且每个选项都有有效的用例.我不会试图总结差异 - Popen docs 在这方面已经做得很好了.

There are a number of differences between these two options, and valid use cases for each. I won't attempt to summarize the differences- the Popen docs already do an excellent job of that.

所以,对于你的命令,你会做这样的事情:

So, in the case of your commands, you'd do something like this:

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 作为许多系统命令的包装器并不是一个好主意.至少,您应该将命令分解为单独的 Popen,以便可以充分处理非零退出.实际上,这个脚本似乎更适合作为 shell 脚本.但如果你坚持使用 Python,还有更好的做法.

Better practice

However, using Python as a wrapper for many system commands is not really a good idea. At the very least, you should be breaking up your commands into separate Popens, so that non-zero exits can be handled adequately. In reality, this script seems like it'd be much better suited as a shell script. But if you insist on Python, there are better practices.

os 模块 应该代替调用到 rmcp.虽然我没有这方面的经验,但您可能想看看像 GitPython 这样的工具来与 Git 存储库交互.

The os module should take the place of calls to rm and cp. And while I have no experience with it, you might want to look at tools like GitPython to interact with Git repositories.

最后,你应该小心调用 gnome-terminalsudo.并非所有 GNU/Linux 用户都运行 Ubuntu,也不是每个人都安装了 sudo 或 GNOME 终端仿真器.在当前形式下,如果出现以下情况,您的脚本将会崩溃,而且毫无帮助:

Lastly, you should be careful about making calls to gnome-terminal and sudo. Not all GNU/Linux users run Ubuntu, and not everyone has sudo, or the GNOME terminal emulator installed. In its current form, your script will crash, rather unhelpfully, if:

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

如果您愿意假设您的用户正在运行 Ubuntu,那么调用 x-terminal-emulator 比直接调用 gnome-terminal 更好,因为它将调用他们安装的任何终端模拟器(例如,Xubuntu 用户的 xfce4-terminal).

If you're willing to assume your users are running Ubuntu, calling x-terminal-emulator is a much better option than calling gnome-terminal directly, as it will call whatever terminal emulator they've installed (e.g. xfce4-terminal for users of Xubuntu).

相关文章