繁体   English   中英

为什么我们不能在subprocess.Popen中合并参数?

[英]Why can't we combine arguments in subprocess.Popen?

使用subprocess.Popen ,我们必须编写

with subprocess.Popen(['ls', '-l', '-a'], stdout=subprocess.PIPE) as proc:
    print(proc.stdout.read())

代替

with subprocess.Popen(['ls', '-l -a'], stdout=subprocess.PIPE) as proc:
    print(proc.stdout.read())

为什么? 什么ls将在第二种情况下得到什么? 谢谢。

当您的操作系统启动可执行文件时,它通过类似于以下的调用来执行此操作:

execv('/usr/bin/ls', 'ls', '-l', '-a', NULL)

注意,在ls开始之前,参数已被拆分为单个单词; 如果您使用外壳运行程序,则外壳负责进行拆分; 如果通过允许您直接控制execv调用参数的编程语言运行它,那么您将决定如何自己拆分数组。

ls运行时,它会将这些参数传递给数组argv 见证在C中声明main功能的常用方法:

int main(int argc, char *argv[]) {
  ...
}

它在一个通常称为argv的变量中获取了一参数,这些参数已经分解成单个单词。

然后, ls的解析器可以期望在运行时将其传递给如下所示的数组:

argc = 3                   # three arguments, including our own name
argv = ['ls', '-l', '-a']  # first argument is our name, others follow

...因此,内置于ls的命令行解析器不需要在其参数内拆分空格-在启动ls命令之前,空格已被删除,并且语法引号已被接受和剥离。

现在,当您运行['ls', '-l -a'] ,您将显式指定一个argc为2,而不是3,以及一个包含单个字符串-l -a的单个参数。 要从外壳程序获得该行为,您需要使用引号或转义符:

ls "-l -a"
ls '-l -a'
ls -l\ -a

...并且您会发现ls失败的方式与您从具有任何这些用法的shell调用时得到的完全相同。

在第二种情况下, -l -a作为单个字符串将是ls的第一个参数,它将不知道该如何处理,或者至少不执行您想要的操作。 在第一种情况下, -l是第一个参数, -a是第二个参数。

如果要构建具有完整命令的字符串,可以使用shell=True标志来Popen,但是您的命令将是"ls -l -a"而不是['ls', '-l -a']

使用Popen ,列表中的每个参数都是传递给正在执行的命令的参数,它不是传递给要解释的shell的字符串,除非您要求将其传递给要解释的shell。

如果要使用命令的字符串表示形式执行,则shlex模块可能会有用。

shlex.split(s [,comments [,posix]])

使用类似于shell的语法拆分字符串。 如果注释为False(默认值),则将禁用对给定字符串中注释的解析(将shlex实例的commenters属性设置为空字符串)。 默认情况下,此函数在POSIX模式下运行,但如果posix参数为false,则使用非POSIX模式。

assert shlex.split("ls -a -l") == ['ls', '-a', '-l']
subprocess.Popen(shlex.split("ls -a -l"))

它还涵盖了更复杂的情况,例如转义字符或引号的用法:

assert shlex.split("cat 'file with space.txt'") == ['cat', 'file with space.txt']
assert shlex.split(r"cat file\ with\ space.txt") == ['cat', 'file with space.txt']

暂无
暂无

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

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