【问题标题】:Issue with subprocess.Popen and executing ssh commandsubprocess.Popen 和执行 ssh 命令的问题
【发布时间】:2014-07-29 17:22:03
【问题描述】:

我正在使用 subprocess.Popen 来执行操作系统命令。这是我试图在我的代码中模拟的内容:

ssh -T myhost < /path/to/some/file

它可以像这样正常工作:

def runWorkerCode(filer, filename):
    command = "/usr/bin/ssh -T " + filer + " < /devel/myscript"
    try:
        p = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True)
        out, _ = p.communicate()
    except Exception:
        print "Error: %s" % Exception
        sys.exit(1)
    return out.rstrip().split('\n')

但以下对 Popen 的调用不起作用:

        p = subprocess.Popen(["/usr/bin/ssh", "-T", filer, "<", "/devel/myscript"], stdout=subprocess.PIPE, shell=True)
        p = subprocess.Popen(["/usr/bin/ssh -T", filer, "< /devel/myscript"], stdout=subprocess.PIPE, shell=True)

我尝试了其他一些组合,但我可以开始工作的唯一方法是定义命令变量并仅将其提供给Popen()。我也试过shell=False

第一种方法有效,但后一种方法对我来说似乎“更干净”。

为什么Popen 不允许我在列表中指定参数?

【问题讨论】:

  • 这将在 Linux 和 Solaris(sparc 和 x86)主机上运行。

标签: python python-2.7 subprocess


【解决方案1】:

当您在 UNIX 上使用 shell=True 时,您应该以字符串的形式提供参数。当您提供一个列表时,subprocess 将列表中的第一项解释为您的整个命令字符串,并将列表中的其余项解释为传递给 shell 本身的参数,而不是您的命令。所以在你上面的例子中,你最终会得到这样的结果:

/bin/sh -T filer < /dev/myscript -c "/usr/sbin/ssh"

绝对不是你的意思!

相反,当您使用shell=False 时,您只能在运行没有参数的单个命令时传递一个字符串。如果您确实有参数,则必须将命令作为序列传递。您也不能通过 &lt; 字符使用 shell 重定向,因为不涉及 shell。

如果要使用shell=False,可以使用stdin关键字参数将文件句柄传递给/dev/myscript

 f = open("/dev/myscript")
 p = subprocess.Popen(["/usr/bin/ssh", "-T", filer], stdout=subprocess.PIPE, stdin=f, shell=False)

何时传递字符串与何时传递序列的规则相当混乱,尤其是当您将 Windows 也纳入其中时。我会仔细阅读documentation 以尝试理解这一切。查看args 部分和shell 部分。

【讨论】:

  • 这不是文档所说的,“args 是所有调用所必需的,并且应该是一个字符串,或者一系列程序参数。通常首选提供一系列参数,因为它允许模块处理任何所需的转义和引用参数(例如,允许文件名中的空格)。如果传递单个字符串,shell 必须是 True(见下文),否则字符串必须简单地将程序命名为在不指定任何参数的情况下执行。"
  • @wnnmaw 我觉得这个比较相关 "在shell=True的Unix上,shell默认为/bin/sh。如果args是字符串,字符串指定要通过的命令执行shell。这意味着字符串的格式必须与在 shell 提示符下键入时的格式完全相同。这包括,例如,引用或反斜杠转义带有空格的文件名。如果 args 是一个序列,则第一个item 指定命令字符串,任何附加的项目都将被视为 shell 本身的附加参数。"。因为它建议您可以使用shell=True 传递一个序列。
  • @wnnmaw 但是,文档也这样说:“如果 shell 为 True,建议将 args 作为字符串而不是序列传递。”我将编辑我的答案以澄清事情。
  • @wnnmaw 实际上,现在我再次阅读它的意思是,如果您提供带有shell=True 的序列,则第一个元素是命令字符串,其余的是传递给 的参数外壳。所以你真的应该传递一个字符串 if shell=True 除非你想将参数传递给/bin/sh
猜你喜欢
  • 2019-06-10
  • 2012-02-28
  • 2021-10-13
  • 2019-04-30
  • 2011-03-20
  • 1970-01-01
  • 2010-12-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多