使用带有列表的 shell=True 时忽略 subprocess.call() 参数 [重复]

Posted

技术标签:

【中文标题】使用带有列表的 shell=True 时忽略 subprocess.call() 参数 [重复]【英文标题】:subprocess.call() arguments ignored when using shell=True w/ list [duplicate] 【发布时间】:2022-01-19 23:24:56 【问题描述】:

我正在尝试让 python 的 subprocess.call 方法按照 python 文档中的建议通过列表(由一系列字符串组成)接受一些 args 命令。为了在将其放入我的实际脚本之前探索这种行为,我打开了 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=True 时,这意味着我指定的命令将通过 shell 执行,所以这应该意味着 ls -a 被馈送到 shell 并由 shell 执行。那么为什么会出现 [4] 和 [7] 中的行为? pydocs 也没有直接解释它(尽管它确实说明了当我们设置 shell=False 时 subpprocess 不会做的事情);当我们让 shell=False 时是什么意思?是否在 OS 中生成了一个新进程,而没有 shell 实际控制它?

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

非常感谢!

【问题讨论】:

您可以选择一个包含较少文件的目录,以使您的示例在此处更加紧凑和可读:) 相关 Python 问题:Don't use a list argument together with shell=True in subprocess' docs 【参考方案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/shbash

【讨论】:

非常感谢您的帮助!我想我会在不使用 shell=True 的情况下保持简单,但有趣的是,仍然可以使用它并让 shell 解释列表中的所有参数。唯一的问题是它会打印出所有的“\”反斜杠字符,这并不好,因为我需要将命令放在一个由空格分隔的连续行中。【参考方案2】:

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

【讨论】:

非常感谢!这现在更有意义了!这应该包含在文档中。

以上是关于使用带有列表的 shell=True 时忽略 subprocess.call() 参数 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

linux下su 与su -的区别

如何在 adb shell 上使用 su 命令?

为啥带有 shell=True 的 subprocess.Popen() 在 Linux 和 Windows 上的工作方式不同?

执行 chmod 时 ADB Shell 给出错误模式(在 su 下)

2016-6-21 知识点总结

python:子进程模块中带有shell = True或shell = False的stderr