[英]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.