【问题标题】:Running Bash commands in Python在 Python 中运行 Bash 命令
【发布时间】:2011-05-14 10:55:54
【问题描述】:

在我的本地机器上,我运行一个包含这一行的 python 脚本

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
os.system(bashCommand)

这很好用。

然后我在服务器上运行相同的代码并收到以下错误消息

'import site' failed; use -v for traceback
Traceback (most recent call last):
File "/usr/bin/cwm", line 48, in <module>
from swap import  diag
ImportError: No module named swap

然后我所做的是我插入了一个print bashCommand,它比终端中的命令打印我,然后它使用os.system() 运行它。

当然,我再次收到错误(由os.system(bashCommand) 引起),但在该错误之前,它会在终端中打印命令。然后我只是复制了该输出并将复制粘贴到终端并按Enter键,它就可以工作了......

有人知道发生了什么吗?

【问题讨论】:

  • 环境似乎有所不同,具体取决于您运行cwm 的方式。也许您在 .bashrc 中有一些配置,用于设置交互式 bash 使用的环境?
  • 您是否在登录服务器时尝试从命令行运行命令?您的帖子只是说您“将 [它] 粘贴到终端中”。
  • @Sven: 是的,我的意思是我直接在服务器终端运行命令
  • PYTHONPATH 似乎有所不同,具体取决于您运行cwm 的方式。或者可能路径不同,并且调用了不同版本的cwm。或不同版本的 Python。如果不访问机器,真的很难解决这个问题......

标签: python bash


【解决方案1】:

不要使用os.system。它已被 subprocess 弃用。来自docs:“这个模块打算替换几个旧模块和功能:os.systemos.spawn”。

就像你的情况:

import subprocess

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)
output, error = process.communicate()

【讨论】:

  • 当我需要执行 cd 'path\to\somewhere' 后跟需要在某个地方运行的另一个 bash 命令时,这并没有达到我想要的效果。 @user225312
  • @AWrightIV 如果您需要在特定的工作目录中运行您的子进程,您可以使用 Popen 的 cwd 参数:subprocess.Popen(..., cwd='path\to\somewhere')
  • 对于我的命令,我需要 shell=True 在这里; stackoverflow.com/questions/18962785/…
  • 在这种情况下最好使用 shlex.split() 而不是 string.split()
  • ...(在这种情况下,stdout=file 将输出重定向到文件。它实现了&gt; file)。在期望重定向的最后一个命令中传递 ..., '&gt;', 'file'] 是错误的(如果没有 shell,它将无法工作,如果您使用 shell,则应该将命令作为字符串传递)
【解决方案2】:

为了稍微扩展这里早期的答案,有一些通常被忽略的细节。

  • 喜欢subprocess.run()而不是subprocess.check_call()和朋友超过subprocess.call()超过subprocess.Popen()超过os.system()超过os.popen()
  • 理解并可能使用text=True,又名universal_newlines=True
  • 了解shell=Trueshell=False 的含义以及它如何改变引用和shell 便利的可用性。
  • 了解sh 和 Bash 之间的区别
  • 了解子进程如何与其父进程分离,并且通常无法更改父进程。
  • 避免将 Python 解释器作为 Python 的子进程运行。

下面将更详细地介绍这些主题。

首选subprocess.run()subprocess.check_call()

subprocess.Popen() 函数是一个低级的主力,但正确使用它很棘手,你最终会复制/粘贴多行代码......这些代码已经作为一组更高级别的标准库方便地存在于标准库中用于各种目的的包装函数,下面将更详细地介绍。

这是documentation的一段话:

调用子流程的推荐方法是对它可以处理的所有用例使用run() 函数。对于更高级的用例,可以直接使用底层的Popen接口。

很遗憾,这些包装函数的可用性因 Python 版本而异。

  • subprocess.run() 在 Python 3.5 中正式引入。它旨在替换以下所有内容。
  • subprocess.check_output() 在 Python 2.7 / 3.1 中引入。基本相当于subprocess.run(..., check=True, stdout=subprocess.PIPE).stdout
  • subprocess.check_call() 在 Python 2.5 中引入。基本相当于subprocess.run(..., check=True)
  • subprocess.call() 是在 Python 2.4 的原始 subprocess 模块 (PEP-324) 中引入的。基本上相当于subprocess.run(...).returncode

高级 API 与 subprocess.Popen()

重构和扩展的subprocess.run() 比它取代的旧旧功能更合乎逻辑,更通用。它返回一个CompletedProcess 对象,该对象具有多种方法,可让您从已完成的子流程中检索退出状态、标准输出以及一些其他结果和状态指示符。

subprocess.run() 是如果您只需要一个程序来运行并将控制权返回给 Python 的方法。对于更多涉及的场景(后台进程,可能与 Python 父程序的交互式 I/O),您仍然需要使用 subprocess.Popen() 并自己处理所有管道。这需要对所有活动部件有相当复杂的了解,不应轻率地进行。更简单的Popen object 表示(可能仍在运行的)进程,需要在子进程的剩余生命周期内从您的代码中进行管理。

也许应该强调的是,subprocess.Popen() 只是创建了一个进程。如果你把它留在那里,你就会有一个子进程与 Python 一起同时运行,因此是一个“后台”进程。如果它不需要输入或输出或以其他方式与您协调,它可以与您的 Python 程序并行执行有用的工作。

避免使用os.system()os.popen()

从永恒以来(好吧,从 Python 2.5 开始)os module documentation 包含了更喜欢 subprocess 而不是 os.system() 的建议:

subprocess 模块为生成新进程和检索其结果提供了更强大的工具;使用那个模块比使用这个函数更可取。

system() 的问题在于它显然依赖于系统并且不提供与子进程交互的方法。它只是运行,标准输出和标准错误超出了 Python 的范围。 Python 收到的唯一信息是命令的退出状态(零表示成功,尽管非零值的含义在某种程度上也取决于系统)。

PEP-324(上面已经提到过)包含更详细的理由说明为什么os.system 存在问题以及subprocess 如何尝试解决这些问题。

os.popen() 曾经更多的是strongly discouraged

自 2.6 版起已弃用:此功能已过时。使用subprocess 模块。

但是,从 Python 3 的某个时候开始,它已被重新实现为简单地使用 subprocess,并重定向到 subprocess.Popen() 文档以获取详细信息。

了解并经常使用check=True

您还会注意到subprocess.call()os.system() 有许多相同的限制。在常规使用中,一般应该检查进程是否成功完成,subprocess.check_call()subprocess.check_output() 会执行此操作(后者也返回已完成子进程的标准输出)。同样,您通常应该将check=Truesubprocess.run() 一起使用,除非您特别需要允许子进程返回错误状态。

实际上,使用check=Truesubprocess.check_*,如果子进程返回非零退出状态,Python 将抛出CalledProcessError exception

subprocess.run() 的一个常见错误是省略 check=True,如果子进程失败,则当下游代码失败时会感到惊讶。

另一方面,check_call()check_output() 的一个常见问题是,当出现异常时,盲目使用这些功能的用户会感到惊讶,例如当grep 没有找到匹配项时。 (无论如何,你应该用原生 Python 代码替换 grep,如下所述。)

所有事情都算在内,您需要了解 shell 命令如何返回退出代码,以及在什么情况下它们会返回非零(错误)退出代码,并有意识地决定应该如何处理它。

理解并可能使用text=True aka universal_newlines=True

从 Python 3 开始,Python 内部的字符串是 Unicode 字符串。但不能保证子进程会生成 Unicode 输出或字符串。

(如果差异不是立即明显,建议阅读 Ned Batchelder 的 Pragmatic Unicode,如果不是完全强制性的,请阅读。如果您愿意,链接后面有一个 36 分钟的视频演示,但您自己阅读该页面可能需要花费时间明显减少。)

在内心深处,Python 必须获取一个bytes 缓冲区并以某种方式对其进行解释。如果它包含一团二进制数据,不应该解码成 Unicode 字符串,因为这是容易出错和引发错误的行为 - 正是让许多 Python 2 脚本百思不得其解的那种讨厌的行为, 在没有办法正确区分编码文本和二进制数据之前。

使用text=True,您告诉 Python 实际上,您希望返回系统默认编码的文本数据,并且应该尽 Python 的能力将其解码为 Python (Unicode) 字符串(通常是 UTF- 8 在任何适度更新的系统上,可能除了 Windows?)

如果这不是您要求返回的内容,Python 只会在stdoutstderr 字符串中为您提供bytes 字符串。也许稍后您确实知道它们毕竟是文本字符串,并且您知道它们的编码。然后,您可以对其进行解码。

normal = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True,
    text=True)
print(normal.stdout)

convoluted = subprocess.run([external, arg],
    stdout=subprocess.PIPE, stderr=subprocess.PIPE,
    check=True)
# You have to know (or guess) the encoding
print(convoluted.stdout.decode('utf-8'))

Python 3.7 为关键字参数引入了更短、更具描述性和更易于理解的别名 text,以前被称为 universal_newlines 有点误导。

了解 shell=Trueshell=False

使用shell=True,您将单个字符串传递给您的shell,然后shell 从那里获取它。

使用shell=False,您可以绕过外壳将参数列表传递给操作系统。

当你没有shell时,你保存一个进程并去掉一个fairly substantial amount of hidden complexity, which may or may not harbor bugs or even security problems.

另一方面,当您没有 shell 时,您就没有重定向、通配符扩展、作业控制和大量其他 shell 功能。

一个常见的错误是使用shell=True,然后仍然向 Python 传递一个标记列表,反之亦然。这恰好在某些情况下有效,但实际上定义不明确并且可能会以有趣的方式中断。

# XXX AVOID THIS BUG
buggy = subprocess.run('dig +short stackoverflow.com')

# XXX AVOID THIS BUG TOO
broken = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    shell=True)

# XXX DEFINITELY AVOID THIS
pathological = subprocess.run(['dig +short stackoverflow.com'],
    shell=True)

correct = subprocess.run(['dig', '+short', 'stackoverflow.com'],
    # Probably don't forget these, too
    check=True, text=True)

# XXX Probably better avoid shell=True
# but this is nominally correct
fixed_but_fugly = subprocess.run('dig +short stackoverflow.com',
    shell=True,
    # Probably don't forget these, too
    check=True, text=True)

除非您确切了解在什么情况下它可能会停止工作,否则“但它对我有用”的常见反驳不是有用的反驳。

重构示例

很多时候,shell 的功能可以用本机 Python 代码替换。简单的 Awk 或 sed 脚本可能应该简单地转换为 Python。

为了部分说明这一点,这里有一个典型但有点傻的例子,它涉及到许多 shell 特性。

cmd = '''while read -r x;
   do ping -c 3 "$x" | grep 'min/avg/max'
   done <hosts.txt'''

# Trivial but horrible
results = subprocess.run(
    cmd, shell=True, universal_newlines=True, check=True)
print(results.stdout)

# Reimplement with shell=False
with open('hosts.txt') as hosts:
    for host in hosts:
        host = host.rstrip('\n')  # drop newline
        ping = subprocess.run(
             ['ping', '-c', '3', host],
             text=True,
             stdout=subprocess.PIPE,
             check=True)
        for line in ping.stdout.split('\n'):
             if 'round-trip min/avg/max' in line:
                 print('{}: {}'.format(host, line))

这里有几点需要注意:

  • 使用shell=False,您不需要shell 需要围绕字符串进行引用。无论如何都要加上引号可能是一个错误。
  • 在子进程中运行尽可能少的代码通常是有意义的。这使您可以在 Python 代码中更好地控制执行。
  • 话虽如此,复杂的 shell 管道很乏味,有时难以在 Python 中重新实现。

重构后的代码还通过非常简洁的语法说明了 shell 真正为您做了多少——无论好坏。 Python 说 显式优于隐式,但 Python 代码 相当冗长,并且可以说看起来比实际情况更复杂。另一方面,它提供了许多点,您可以在其他事情的中间抓住控制权,我们可以轻松地将主机名与 shell 命令输出一起包含在内的增强功能就是一个简单的例子。 (这在 shell 中也绝不是具有挑战性的,但是以另一种转移和可能的另一个过程为代价。)

常见的 Shell 构造

为了完整起见,这里是对其中一些 shell 功能的简要说明,以及一些关于如何将它们替换为原生 Python 工具的说明。

  • 通配符又名通配符扩展可以用glob.glob() 替换,或者经常用简单的Python 字符串比较替换,如for file in os.listdir('.'): if not file.endswith('.png'): continue。 Bash 有各种其他扩展工具,例如 .{png,jpg} 大括号扩展和 {1..100} 以及波浪号扩展(~ 扩展到您的主目录,更一般地 ~account 扩展到另一个用户的主目录)
  • $SHELL$my_exported_var 这样的Shell 变量有时可以简单地替换为Python 变量。导出的 shell 变量可用作例如os.environ['SHELL']export 的意思是使变量对子进程可用——一个对子进程不可用的变量显然对作为 shell 的子进程运行的 Python 不可用,反之亦然。@987654428 subprocess 方法的 @ 关键字参数允许您将子进程的环境定义为字典,因此这是使 Python 变量对子进程可见的一种方法)。使用shell=False,您将需要了解如何删除任何引号;例如,cd "$HOME" 等价于 os.chdir(os.environ['HOME']),目录名称不带引号。 (很多时候cd 无论如何都没有用或没有必要,许多初学者省略了变量周围的双引号并侥幸逃脱until one day ...
  • 重定向允许您从文件中读取作为标准输入,并将标准输出写入文件。 grep 'foo' &lt;inputfile &gt;outputfile 打开outputfile 用于写入,打开inputfile 用于读取,并将其内容作为标准输入传递给grep,然后其标准输出到达outputfile。这通常不难用原生 Python 代码替换。
  • 管道是一种重定向形式。 echo foo | nl 运行两个子进程,其中echo 的标准输出是nl 的标准输入(在操作系统级别,在类Unix 系统中,这是单个文件句柄)。如果你不能用原生 Python 代码替换管道的一端或两端,也许考虑使用 shell,特别是如果管道有两个或三个以上的进程(尽管看看 pipes module in the Python standard library 或一些更现代的和多才多艺的第三方竞争对手)。
  • 作业控制允许您中断作业、在后台运行它们、将它们返回到前台等。停止和继续进程的基本 Unix 信号当然也可以从 Python 获得。但是作业是 shell 中更高级别的抽象,它涉及进程组等,如果你想从 Python 做这样的事情,你必须了解这些。
  • 在您了解 everything 基本上是一个字符串之前,在 shell 中引用可能会造成混淆。所以ls -l / 等价于'ls' '-l' '/',但文字周围的引用是完全可选的。包含 shell 元字符的不带引号的字符串经过参数扩展、空白标记化和通配符扩展;双引号可防止空格标记化和通配符扩展,但允许参数扩展(变量替换、命令替换和反斜杠处理)。这在理论上很简单,但可能会让人感到困惑,尤其是当有多层解释时(例如远程 shell 命令)。

了解sh 和 Bash 之间的区别

subprocess 使用/bin/sh 运行您的shell 命令,除非您另有特别要求(当然在Windows 上除外,它使用COMSPEC 变量的值)。这意味着various Bash-only features like arrays, [[ etc 不可用。

如果您需要使用纯 Bash 语法,您可以 将 shell 的路径作为executable='/bin/bash' 传递(当然,如果您的 Bash 安装在其他地方,则需要调整路径)。

subprocess.run('''
    # This for loop syntax is Bash only
    for((i=1;i<=$#;i++)); do
        # Arrays are Bash-only
        array[i]+=123
    done''',
    shell=True, check=True,
    executable='/bin/bash')

subprocess 与其父级分离,无法更改

一个比较常见的错误是做类似的事情

subprocess.run('cd /tmp', shell=True)
subprocess.run('pwd', shell=True)  # Oops, doesn't print /tmp

如果第一个子进程尝试设置环境变量也会发生同样的情况,当然当您运行另一个子进程等时该环境变量会消失。

子进程完全独立于 Python 运行,当它完成时,Python 不知道它做了什么(除了可以从子进程的退出状态和输出推断出的模糊指示符)。孩子一般不能改变父母的环境;它不能设置变量,改变工作目录,或者说,在没有父级合作的情况下,它不能与父级通信。

在这种特殊情况下的直接解决方法是在单个子进程中运行这两个命令;

subprocess.run('cd /tmp; pwd', shell=True)

虽然这个特殊的用例显然不是很有用;相反,在运行子进程之前使用cwd 关键字参数,或者干脆使用os.chdir()。同样,对于设置变量,您可以通过

来操作当前进程(以及它的子进程)的环境
os.environ['foo'] = 'bar'

或将环境设置传递给子进程

subprocess.run('echo "$foo"', shell=True, env={'foo': 'bar'})

(更不用说明显的重构subprocess.run(['echo', 'bar']);但echo 是一个糟糕的例子,首先要在子进程中运行,当然)。

不要从 Python 运行 Python

这是一个有点可疑的建议;在某些情况下,将 Python 解释器作为 Python 脚本的子进程运行是有意义的,甚至是绝对要求。但很多时候,正确的做法是简单地将其他 Python 模块import 放入您的调用脚本并直接调用其函数。

如果其他 Python 脚本在您的控制之下,并且它不是模块,请考虑 turning it into one。 (这个答案已经太长了,这里就不细说了。)

如果您需要并行性,您可以使用 multiprocessing module. 在子进程中运行 Python 函数还有 threading 在单个进程中运行多个任务(它更轻量级并为您提供更多控制权,但在进程中的线程紧密耦合,并绑定到单个GIL。)

【讨论】:

  • 有关如何避免将 Python 作为子进程调用的更详细说明,请参阅this answer on a tangentially similar question.
  • 令我惊讶的是,我不得不为这样一个基本问题发布一个新答案,以便展示如何以惯用的方式从问题中运行命令。你的答案很长,但我没有看到这样的例子。无关:避免货物崇拜。如果 check_call() 在您的情况下有效,请使用它。我不得不修复一个盲目使用run() 的代码。缺少check=True 导致了一个错误,如果使用 check_call 可以避免这个错误——“check”在名称中,你不能丢失它——它是正确的默认值:不要默默地忽略错误。我没有进一步阅读。
  • @jfs 感谢您的反馈,实际上我正计划添加一个关于 Bash 与 sh 的部分,但你打败了我。我试图详细说明细节,以帮助那些陷阱不明显的初学者,所以这确实有点冗长。否则,您的应该就足够了; +1
  • stderr/stdout = subprocess.PIPE 的性能开销是否高于默认设置?
  • @Stringers 我没有测试过,但我不明白为什么应该这样做。如果您将这些管道连接到进行某些处理的东西,那么当然需要计算该处理;但它不会发生在管道本身。默认设置是根本不捕获 stdout 或 stderr,即打印的任何内容都超出 Python 的可见性和控制范围,就像 os.system() 一样。
【解决方案3】:

用子进程调用它

import subprocess
subprocess.Popen("cwm --rdf test.rdf --ntriples > test.nt")

你得到的错误似乎是因为服务器上没有交换模块,你应该在服务器上安装交换然后再次运行脚本

【讨论】:

  • swap 模块显然在那里,因为从 shell 运行命令有效。
  • 不在服务器上,他在服务器上运行时出现导入错误。
  • @mkn:“然后我只是复制了该输出并将复制粘贴到终端并按Enter,它就可以工作了......” - 你是在服务器上还是在你的机器上尝试过这个?
  • 您是否在独立计算机上运行它很好,但在服务器上运行它时它不起作用?或者您是否可以在服务器终端上运行它而不是在服务器本身上运行它
  • 这是错误 如果您不使用shell=True,那么您应该使用列表来传递多个参数,即使用['a', 'b', 'c'] 而不是'a b c'。尽管由于命令中的&gt; file(shell 重定向)而无法进行简单的拆分。 More details
【解决方案4】:

你可以使用subprocess,但我一直觉得这不是一种“Pythonic”的方式。所以我创建了 Sultan(无耻插件),可以轻松运行命令行功能。

https://github.com/aeroxis/sultan

【讨论】:

  • 干得好!比子流程更干净、更直观。
  • 这应该被诚实地采用到标准库中。
  • 有没有办法使用 Sultan 从终端捕获输出?
  • 是的,你可以@alvas ...这是有关如何操作的文档:sultan.readthedocs.io/en/latest/…
  • @DavidDaniel 嘿,大卫,感谢您提供的出色库。我想知道Sultan 是否可以在这里帮助我解决一个用例。我有 2 个 bash 脚本和 1 个 shell 脚本。我想从我的 python 脚本中运行它们 - 一次一个,所以数字不是问题。脚本中确实有sudo 调用,这将要求用户输入他们的密码(这是在osx btw 上,但shell/bash 功能几乎相同)。我想要的是一种在终端打开的情况下启动它们的方法,用户可以与它交互以输入 sudo pwd。那可能吗?任何帮助表示赞赏:)
【解决方案5】:

你可以使用 bash 程序,使用参数 -c 来执行命令:

bashCommand = "cwm --rdf test.rdf --ntriples > test.nt"
output = subprocess.check_output(['bash','-c', bashCommand])

【讨论】:

  • subprocess.check_output(bashCommand, shell=True) 做同样的事情。如果您的命令是静态字符串,请尝试自己将其解析为列表并避免使用shell=True;尽管在这种情况下,无论如何您都需要 shell 进行重定向,否则您需要将其重构为纯 Python -- with open('test.nt', 'w') as dest: output = subprocess.check_output(['cwm' ,'--rdf', 'test.rdf', '--ntriples'], stdout=dest, shell=False)
  • @tripleee 注意:/bin/sh(由子进程使用)不一定是 bash(你不能使用 bashisms)。虽然如果需要可以使用executable='/bin/bashHere's a code example
  • 这是命令应该成功启动的第一个答案(接受的和第二个流行的答案是错误的。一个小问题:check_output() 在这里没用(输出总是空的,因为&gt; file 重定向;use check_call() instead.
【解决方案6】:

根据错误,您在服务器上缺少一个名为 swap 的包。这个/usr/bin/cwm 需要它。如果您使用的是 Ubuntu/Debian,请使用 aptitude 安装 python-swap

【讨论】:

  • 但是当我直接在终端中运行它时它可以工作......所以交换必须在那里,不是吗?
  • 有两种选择。它要么找不到swap,要么一开始就不应该导入它。你能手动import swap吗?有用吗?
  • 嗯,我不能。如果我在终端中输入 python 来启动 python,然后输入 import swap,那么我会收到错误“ImportError: No module named swap”。奇怪的是,当我直接在服务器终端运行 cwm 命令时它仍然有效
  • 尝试将sys.path 打印在有效和无效的位置。然后尝试在打印的文件夹中查找交换文件夹或 swap.py。正如 Sven 所说,这些路径可能存在问题,这将帮助您解决问题。
【解决方案7】:

您也可以使用“os.popen”。 示例:

import os

command = os.popen('ls -al')
print(command.read())
print(command.close())

输出:

total 16
drwxr-xr-x 2 root root 4096 ago 13 21:53 .
drwxr-xr-x 4 root root 4096 ago 13 01:50 ..
-rw-r--r-- 1 root root 1278 ago 13 21:12 bot.py
-rw-r--r-- 1 root root   77 ago 13 21:53 test.py

None

【讨论】:

  • The documentation 包含一个大红色框:"自 2.6 版起已弃用: 此功能已过时。请使用 subprocess 模块。"
  • 公平地说,os.popen 不再有这个警告,现在只是 subprocess.Popen() 的一个薄包装。
【解决方案8】:

要在没有 shell 的情况下运行命令,请将命令作为 list 传递,并使用 [subprocess] 在 Python 中实现重定向:

#!/usr/bin/env python
import subprocess

with open('test.nt', 'wb', 0) as file:
    subprocess.check_call("cwm --rdf test.rdf --ntriples".split(),
                          stdout=file)

注意:最后没有&gt; test.ntstdout=file 实现重定向。


要在 Python 中使用 shell 运行命令,请将命令作为 字符串 传递并启用 shell=True:

#!/usr/bin/env python
import subprocess

subprocess.check_call("cwm --rdf test.rdf --ntriples > test.nt",
                      shell=True)

这里的 shell 负责输出重定向(&gt; test.nt 在命令中)。


要运行使用 bashisms 的 bash 命令,请明确指定 bash 可执行文件,例如 emulate bash process substitution:

#!/usr/bin/env python
import subprocess

subprocess.check_call('program <(command) <(another-command)',
                      shell=True, executable='/bin/bash')

【讨论】:

  • 也许提到 .split() 在引用字符串等时是不够的。有一个单独的例程 shlex.split() 可以处理任意复杂的 shell 语法。
  • @tripleee .split() 在这种情况下有效。 shlex.split() 有时会很有用,但在某些情况下也可能会失败。有很多事情可以提及。您可以从上面提供的子流程标签描述的链接开始。
【解决方案9】:

subprocess.Popen() 优于 os.system(),因为它提供了更多的控制和可见性。但是,如果你觉得subprocess.Popen() 过于冗长或复杂,peasyshell 是我在上面写的一个小包装器,它可以很容易地与 Python 中的 bash 交互。

https://github.com/davidohana/peasyshell

【讨论】:

    【解决方案10】:

    pythonic 的方式是使用subprocess.Popen

    subprocess.Popen 采用一个列表,其中第一个元素是要运行的命令,后跟任何命令行参数。

    举个例子:

    import subprocess
    
    args = ['echo', 'Hello!']
    subprocess.Popen(args) // same as running `echo Hello!` on cmd line
    
    args2 = ['echo', '-v', '"Hello Again"']
    subprocess.Popen(args2) // same as running 'echo -v "Hello Again!"` on cmd line
    

    【讨论】:

    • 不,最后一个示例与运行echo -v '"Hello Again!"' 相同,用单引号将双引号括起来。
    • 另外,要正确使用subprocesss.Popen,您必须管理生成的进程对象(至少,执行wait() 以防止它变成僵尸进程)。
    猜你喜欢
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多