【问题标题】:Passing List to subprocess.run将列表传递给 subprocess.run
【发布时间】:2018-09-17 09:28:22
【问题描述】:

我有一个脚本,其中包含一个列表 - 该列表只是我想像这样传递给 subprocess.run 的一些参数

commands = ["bash command 1", "bash command 2",..]

这是我的代码

commands = ["bash command 1", "bash command 2",..]
process = subprocess.run([commands], stdout = subprocess.PIPE, shell = True)

如何将列表传递给我的 subprocess.run?

这是回溯

Traceback (most recent call last):
  File "./retesting.py", line 18, in <module>
    process = subprocess.run([commands], stdout = subprocess.PIPE, shell = True)
  File "/usr/lib/python3.5/subprocess.py", line 383, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/usr/lib/python3.5/subprocess.py", line 676, in __init__
    restore_signals, start_new_session)
  File "/usr/lib/python3.5/subprocess.py", line 1221, in _execute_child
    restore_signals, start_new_session, preexec_fn)
TypeError: Can't convert 'list' object to str implicitly

我不知道我做错了什么,我尝试了各种方法,所以我非常感谢任何帮助

【问题讨论】:

  • 当你需要一个列表(使用[])时,为什么你将你的命令定义为set(使用{})?
  • 对不起,这实际上是我在输入问题时遇到的错误,编辑了我的问题
  • 只需从.run([commands], 中删除[]
  • @Rakesh 感谢您的反馈,我将代码更改为您建议的内容,但没有收到任何错误,只是现在它似乎将第一个参数传递给 bash 并忽略了其余的。我做错了什么?非常感谢!
  • @skdadle 不要不要使用shell=True。它改变了命令列表的解释方式。

标签: python python-3.x bash subprocess


【解决方案1】:

在使用shell=True 之前,您必须了解它的作用。采取the documentation for Popen。它指出:

shell 参数(默认为False)指定是否使用 shell 作为要执行的程序。 如果shell是True,它是 建议将 args 作为字符串而不是序列传递。

在带有shell=True 的Unix 上,shell 默认为/bin/sh。如果args 是 string,字符串指定要通过shell执行的命令。 这意味着字符串必须完全按照它的格式进行格式化 在 shell 提示符下键入时。这包括,例如,引用或 反斜杠转义带有空格的文件名。 如果args 是 序列,第一项指定命令字符串,任何 附加项将被视为 shell 的附加参数 也就是说,Popen 相当于:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

在 Windows 上 shell=TrueCOMSPEC 环境变量指定默认 壳。您需要在 Windows 上指定 shell=True 的唯一时间是 您希望执行的命令内置在 shell 中(例如 dircopy)。您不需要shell=True 来运行批处理文件或基于控制台的 可执行文件。

没有办法一次性执行一系列命令,您要做的是执行第一个命令和传递的所有其他命令当生成 shell 作为该 shell 的选项时

您想改为这样做:

for command in commands:
    subprocess.run(command, shell=True)

或者:您希望将命令序列作为单个脚本执行:

subprocess.run(';'.join(commands), shell=True)

这就是说:如果 command 里面的命令只是可执行文件,你真的应该避免使用shell=True 并使用shlex.split 来提供解析的参数列表。如果您需要指定执行命令的目录,您可以使用cwd 参数到Popen(或任何类似函数)。

在你的情况下,你想要这样的东西:

import os, subprocess

subprocess.run(['app', '--email', 'some-email', '--password', 'somepassword'], cwd=os.path.expanduser('~/app-cli'))

【讨论】:

  • 感谢您的回答!,但是现在我在列表的第一个字符串中遇到了一个无效的语法错误,但是当我通常将它作为像这样的一个参数传递时 subprocess.run("the exact same string like my first one in the list", shell = true) 它可以工作,有什么想法吗?
  • 在你的回答中,你告诉我如何将一个参数传递给 subprocess.run,我不能传递一个依次执行的参数序列/列表吗?
  • @skdadle subprocess.run 总是执行 one 的事情。这个东西可以是一个可执行文件(当shell=False),在这种情况下,参数是一个指定命令行的字符串列表,或者它可以执行单个shell脚本(当shell=True )。一个 shell 脚本可以由多个 shell 命令组成。在 UNIX 样式的 shell 中,您可以使用 ;(或换行符)分隔多个命令。正如我所说:我认为您应该避免shell=True 或尽可能执行多个命令。如果您有更多问题,请编辑您的问题以包含您遇到的错误。
  • 嗨,感谢您的回答,我尝试了您的解决方案 - 使用 (';'.join(commands), shell = True) 但我遇到了无效的语法错误,我很困惑,因为每个命令都用双引号括起来,用逗号分隔,我认为我们应该像在 shell 中编写命令一样编写命令。我不能使用你建议的第二个答案,因为我有更多的命令,我不想单独输入每个命令,这也是为什么我想首先使用列表,我还需要 shell = true 因为我没有运行可执行文件。非常感谢!
  • @skdadle 如果不提​​供您要运行的确切命令列表,我们必须知道为什么会出现语法错误。如果您想要更好的答案,您应该尝试在您的问题中提供尽可能多的信息。如果您提供通用信息,您将收到通用答案。有时这就足够了,有时它们不是最理想的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多