简体   繁体   English

subprocess.Popen和执行ssh命令的问题

[英]Issue with subprocess.Popen and executing ssh command

I am using subprocess.Popen to execute an OS command. 我正在使用subprocess.Popen执行OS命令。 Here is what I am trying to emulate in my code: 这是我尝试在代码中模仿的内容:

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

It works fine like this: 它的工作原理如下:

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')

But the following calls to Popen do not work: 但是以下对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)

I tried a few other combinations but only method I can get to work is defining the command variable and only providing it to Popen() . 我尝试了其他几种组合,但是唯一可以使用的方法是定义命令变量并将其仅提供给Popen() I've also tried shell=False . 我也尝试过shell=False

The first method works but the latter approach seems "cleaner" to me. 第一种方法可行,但后一种方法对我来说似乎“更干净”。

Why doesn't Popen allow me to specify the arguments in a list? 为什么Popen不允许我在列表中指定参数?

When you use shell=True on UNIX, you should provide your arguments as a string. 在UNIX上使用shell=True时,应将参数作为字符串提供。 When you provide a list, subprocess interprets the first item in the list as your entire command string, and the rest of the items in the list as arguments passed to the shell itself, rather than your command. 提供列表时, subprocess将列表中的第一项解释为整个命令字符串,并将列表中的其余项解释为传递给Shell本身而不是命令的参数。 So in your example above, you're ending up with something like this: 因此,在上面的示例中,您将得到如下结果:

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

Definitely not what you meant! 绝对不是你的意思!

Conversely, when you use shell=False , you can only pass a string if you're running a single command with no arguments. 相反,当您使用shell=False ,只有在运行不带参数的单个命令时,才可以传递字符串。 If you do have arguments, have to pass the comamnd as a sequence. 如果确实有参数,则必须将comamnd作为序列传递。 You also can't use shell redirection via the < character, because there is no shell involved. 您也不能通过<字符使用shell重定向,因为不涉及shell。

If you want to use shell=False , you can use the stdin keyword argument to pass a file handle to /dev/myscript : 如果要使用shell=False ,则可以使用stdin关键字参数将文件句柄传递给/dev/myscript

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

The rules for when to pass a string vs. when to pass a sequence are pretty confusing, especially when you bring Windows into the mix as well. 何时传递字符串与何时传递序列的规则非常令人困惑,尤其是当您也将Windows引入混合时。 I would read the documentation carefully to try to understand it all. 我会仔细阅读文档以尝试理解所有内容。 Check out both the section on args and the section on shell . 检查有关args的部分和有关shell的部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM