【问题标题】:Multiple shell commands in python (Windows)python中的多个shell命令(Windows)
【发布时间】:2018-08-22 14:43:10
【问题描述】:

我正在使用 Windows 机器,我想在 shell 中设置一个变量,并希望将它与另一个 shell 命令一起使用,例如:

set variable = abc
echo %variable%

我知道我可以使用os.system(com1 && com2) 来做到这一点,但我也知道,这被认为是“糟糕的风格”,应该可以通过使用 subprocess 模块来实现,但我不明白怎么做。 这是我到目前为止得到的:

proc = Popen('set variable=abc', shell=True, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
proc.communicate(input=b'echo %variable%)

但是这两行似乎都不起作用,两个命令都没有执行。此外,如果我输入不存在的命令,我不会收到错误消息。正确的做法是怎样的?

【问题讨论】:

  • Popen 启动的 shell 不等待其标准输入; set 命令运行,然后 shell 退出而不尝试从标准输入中读取任何内容。在这种情况下,您的命令(从 Python 脚本的角度来看)是一个单独的 shell 脚本,恰好由两个 shell 命令组成,而不是一对 shell 命令。
  • 我强烈建议在标题和标签中更明确地说明 Windows。在 UNIX 上你会得到一个非常不同的答案。
  • ...不过,一般来说,您所依赖的东西(设置和扩展 shell 变量)依赖于拥有一个 shell,所以在 UNIX 世界中,最佳做法是将您正在做的事情完全重新设计,使其完全不依赖于 shell 变量。

标签: python windows python-3.x subprocess popen


【解决方案1】:

Popen 只能执行一个命令或 shell 脚本。您可以简单地使用; 将整个 shell 脚本作为单个参数提供来分隔不同的命令:

proc = Popen('set variable=abc;echo %variable%', shell=True)

或者你实际上可以只使用多行字符串:

>>> from subprocess import call
>>> call('''echo 1
... echo 2
... ''', shell=True)
1
2
0

最后的0是进程的返回码

communicate 方法用于写入进程的标准输入。在您的情况下,该过程在运行 set variable 后立即结束,因此对 communicate 的调用实际上并没有做任何事情。

您可以生成一个 shell,然后使用 communicate 编写命令:

>>> proc = Popen(['sh'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
>>> proc.communicate('echo 1; echo 2\n')
('1\n2\n', '')

请注意,communicate 在完成时也会关闭流,因此您不能多次调用它。如果您想要一个交互式会话,您可以直接写信到proc.stdin 并从proc.stdout 读取。


顺便说一句:您可以为Popen 指定一个env 参数,因此根据具体情况您可能想要这样做:

proc = Popen(['echo', '%variable%'], env={'variable': 'abc'})

显然这将使用echo 可执行文件而不是shell 内置,但它避免使用shell=True

【讨论】:

  • 这不起作用(对我来说)。如果我输入: proc = Popen('echo abc;echo 123', shell=True) output=proc.communicate()[0] print(output) 我得到abc;echo123,所以它不会读取为 2 行/命令
  • @AracKnight >>> from subprocess import call >>> call('echo 1; echo 2', shell=True) 1 2 它对我有用。您应该准确指定您在问题中使用的代码。另外,你是在windows还是linux上? ; 适用于 linux,我不确定 powershell/batch 文件是否使用不同的分隔符。但是:你也可以使用多行字符串作为命令call('echo 1\necho 2', shell=True)
  • 我正在使用 Windows 10 64 位。我在第一行为数据库连接设置密码作为环境变量,这样我就可以在下一行调用 psql 并连接到数据库。使用call('echo abc\necho 123', shell=True) 我得到abc 作为输出,所以第二个命令仍然不起作用。
  • 当我为 Popen 指定一个 env 参数时,我无法在不知道 psql.exe 的确切路径的情况下再调用 psql,因为我通常从 PATH 变量中运行它,它会被忽略如果它通过了env,则打开。此外,不过我可能能够解决我当前的问题,我真的很想知道这些目的一般是如何实现的,因为我将来可能会遇到类似的问题。
猜你喜欢
  • 1970-01-01
  • 2013-01-31
  • 2016-10-24
  • 1970-01-01
  • 2021-10-22
  • 2019-06-04
  • 2021-03-31
  • 2021-12-11
  • 2017-05-28
相关资源
最近更新 更多