使用 shell=True w/list 时忽略 subprocess.call() 参数[重复]
- 2025-02-25 09:09:00
- admin 原创
- 34
问题描述:
我正在尝试让 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 时 subpprocess 不会做什么);当我们让 shell=False 时它意味着什么?操作系统中是否会生成一个新进程而不需要 shell 实际控制它?
另外,在 [3] 和 [4] 中使用格式字符串可能看起来非常尴尬,这是因为在我的实际脚本中,我将使用 subprocess.call,我必须依赖这些格式字符串来替换适当的命令选项。我无法对某些命令行选项进行硬编码。使用纯字符串作为参数也是不可能的,因为在我的脚本中将有一个方法必须对命令执行列表操作。我不知道是否有更好的方法来解决这个问题,所以如果有人能提出不同的建议,那将非常有帮助。
非常感谢!
解决方案 1:
当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
根本不需要使用。
解决方案 2:
当您使用shell=True
列表时,额外的参数将传递给 shell 本身,而不是传递给在 shell 中运行的命令。然后可以从 shell 脚本中引用它们(传递为argv[0]
)$0
,如$1
、 等。
最简单的答案是“不要那样做”:如果您想传递一个列表,请不要使用shell=True
;如果您想传递一个字符串,请始终使用shell=True
。
也就是说,可以以读取这些参数的方式形成命令。下面是一个违反我上述规则的示例——没有这个命令你就无法实现[*1]shell=True
(并且executable='/bin/bash'
要避免使用 bash for 依赖操作系统/bin/sh
),因为它依赖于 bash 的内置版本printf
(支持%q
作为扩展):
subprocess.call([
"printf '%q\\n' \"$0\" \"$@\"",
'these strings are
',
'"shell escaped" in the output from this command',
"so that the output can *safely* be run through eval",
"observe that no /tmp/owned file is created",
"including when the output of this script is run by bash as code:"
"$(touch /tmp/owned) \"$(touch /tmp/owned)\"",
'$(touch /tmp/owned) \'$(touch /tmp/owned)\'',
], shell=True, executable='/bin/bash')
[*1] - 如果忽略这一点,可以使用/bin/bash
as argv[0]
with shell=False
。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)