使用shell = True w / list时,subprocess.call()参数被忽略

时间:2014-10-17 03:59:46

标签: python bash shell subprocess call

我试图让python的subprocess.call方法通过列表(由一系列字符串组成)接受一些args命令,如python文档中所建议的那样。为了在将它放入我的实际脚本之前探索这种行为,我打开了IPython,运行了一些涉及shell设置和args命令的不同组合的命令,并得到以下行为:

In [3]: subprocess.call(['ls', '-%sl' %'a'])
total 320
drwxr-xr-x  20 Kohaugustine  staff   680 Oct 15 16:55 .
drwxr-xr-x   5 Kohaugustine  staff   170 Sep 12 17:16 ..
-rwxr-xr-x   1 Kohaugustine  staff  8544 Oct 15 16:55 a.out
-rwxr-xr-x   1 Kohaugustine  staff  8544 Oct  3 10:28 ex1-6
-rw-r--r--@  1 Kohaugustine  staff   204 Oct  3 10:28 ex1-6.c
-rwxr-xr-x   1 Kohaugustine  staff  8496 Oct  3 10:15 ex1-7
-rw-r--r--@  1 Kohaugustine  staff    71 Oct  3 10:15 ex1-7.c
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 12 16:22 hello
-rw-r--r--@  1 Kohaugustine  staff    58 Sep 12 16:27 hello.c
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 12 16:24 hello.o
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 12 16:24 hello_1.o
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 12 16:27 hello_2.o
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 12 16:27 hello_3.o
-rwxr-xr-x   1 Kohaugustine  staff  8544 Oct 15 16:55 lesson_1-5
-rw-r--r--@  1 Kohaugustine  staff   185 Sep 28 10:35 lesson_1-5.c
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 21 10:06 temperature.o
-rw-r--r--@  1 Kohaugustine  staff   406 Sep 21 09:54 temperature_ex1-3.c
-rw-r--r--@  1 Kohaugustine  staff   582 Sep 21 10:06 temperature_ex1-4.c
-rw-r--r--@  1 Kohaugustine  staff   178 Sep 23 17:21 temperature_ex1-5.c
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 23 17:21 temperature_ex1-5.o
Out[3]: 0

In [4]: subprocess.call(['ls', '-%sl' %'a'], shell=True)
a.out           ex1-7           hello.c         hello_2.o       lesson_1-5.c            temperature_ex1-4.c
ex1-6           ex1-7.c         hello.o         hello_3.o       temperature.o           temperature_ex1-5.c
ex1-6.c         hello           hello_1.o       lesson_1-5      temperature_ex1-3.c     temperature_ex1-5.o
Out[4]: 0

In [6]: subprocess.call(['ls', '-al'])    
total 320
drwxr-xr-x  20 Kohaugustine  staff   680 Oct 15 16:55 .
drwxr-xr-x   5 Kohaugustine  staff   170 Sep 12 17:16 ..
-rwxr-xr-x   1 Kohaugustine  staff  8544 Oct 15 16:55 a.out
-rwxr-xr-x   1 Kohaugustine  staff  8544 Oct  3 10:28 ex1-6
-rw-r--r--@  1 Kohaugustine  staff   204 Oct  3 10:28 ex1-6.c
-rwxr-xr-x   1 Kohaugustine  staff  8496 Oct  3 10:15 ex1-7
-rw-r--r--@  1 Kohaugustine  staff    71 Oct  3 10:15 ex1-7.c
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 12 16:22 hello
-rw-r--r--@  1 Kohaugustine  staff    58 Sep 12 16:27 hello.c
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 12 16:24 hello.o
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 12 16:24 hello_1.o
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 12 16:27 hello_2.o
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 12 16:27 hello_3.o
-rwxr-xr-x   1 Kohaugustine  staff  8544 Oct 15 16:55 lesson_1-5
-rw-r--r--@  1 Kohaugustine  staff   185 Sep 28 10:35 lesson_1-5.c
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 21 10:06 temperature.o
-rw-r--r--@  1 Kohaugustine  staff   406 Sep 21 09:54 temperature_ex1-3.c
-rw-r--r--@  1 Kohaugustine  staff   582 Sep 21 10:06 temperature_ex1-4.c
-rw-r--r--@  1 Kohaugustine  staff   178 Sep 23 17:21 temperature_ex1-5.c
-rwxr-xr-x   1 Kohaugustine  staff  8496 Sep 23 17:21 temperature_ex1-5.o
Out[6]: 0

In [7]: subprocess.call(['ls', '-al'], shell = True)
a.out           ex1-7           hello.c         hello_2.o       lesson_1-5.c            temperature_ex1-4.c
ex1-6           ex1-7.c         hello.o         hello_3.o       temperature.o           temperature_ex1-5.c
ex1-6.c         hello           hello_1.o       lesson_1-5      temperature_ex1-3.c     temperature_ex1-5.o
Out[7]: 0

似乎每当shell = True时,输出似乎与:

相同
In [9]: subprocess.call(['ls'])
a.out           ex1-7           hello.c         hello_2.o       lesson_1-5.c            temperature_ex1-4.c
ex1-6           ex1-7.c         hello.o         hello_3.o       temperature.o           temperature_ex1-5.c
ex1-6.c         hello           hello_1.o       lesson_1-5      temperature_ex1-3.c     temperature_ex1-5.o
Out[9]: 0

我很困惑;当我设置shell = True时,'-a'选项会发生什么? shell没有读过吗?我已经阅读了文档,并且它说当shell = True时,这意味着我的指定命令将通过shell执行,因此它应该意味着ls -a被送到shell并由shell执行。那么为什么[4]和[7]中的行为呢? pydocs也没有直接解释它(虽然它确实说明当我们设置shell = False时子进程不会做什么);当我们让shell = False时它意味着什么?是否在操作系统中生成了一个新进程而没有shell实际控制它?

另外,如果我在[3]和[4]中使用格式字符串看起来真的很尴尬,那因为在我的实际脚本中我将使用subprocess.call,我将不得不依赖在这些格式字符串上替换相应的命令选项。我无法硬编码某些命令行选项。对于args使用纯字符串也是不可能的,因为在我的脚本中将有一个方法必须对命令执行列表操作。我不知道是否有更好的方法可以解决这个问题,所以如果有人能提出不同的建议,那真的会有所帮助。

非常感谢!

2 个答案:

答案 0 :(得分:8)

shell为True时,第一个参数将附加到["/bin/sh", "-c"]。如果该参数是列表,则结果列表为

["/bin/sh", "-c", "ls", "-al"]

也就是说,只有ls,而不是ls -al被用作-c选项的参数。 -al用作shell本身的第一个参数,而不是ls

使用shell=True时,通常只想传递一个字符串,让shell根据shell的正常分词规则将其拆分。

# Produces ["/bin/sh", "-c", "ls -al"]
subprocess.call("ls -al", shell=True)

在您的情况下,您似乎根本不需要使用shell=True

答案 1 :(得分:1)

shell=True与列表一起使用时,会将额外的参数传递给shell本身,而不是传递给shell中运行的命令。然后可以在shell脚本中引用它们(作为argv[0]传递)为$0$1等。

最简单的答案是“不要那样做”:如果要传递列表,请不要使用shell=True;如果要传递字符串,请始终使用shell=True


也就是说, 可以以读取这些参数的方式形成你的命令。以下是违反上述规则的示例 - 没有shell=True(以及bash提供的/bin/sh)无法实现的命令,因为它依赖于bash的内置版本printf(支持%q作为扩展名):

subprocess.call([
    "printf '%q\\n' \"$0\" \"$@\"",
    'these strings are\r\n',
    '"shell escaped" in the output from this command',
    "so that they can *safely* be run through eval"
], shell=True)

[*] - 不是真的;可以使用/bin/bash argv[0]shell=False /bin/sh来更可靠地实现此目标,因为它将不再依赖于bash {{1}}。