从python代码执行Unix命令

时间:2017-02-25 22:03:40

标签: python unix

diff -u <(echo "aba"| fold -w1) <(echo "abaa" | fold -w1)

我想从Python代码执行上面的命令。以下是我写的代码。

cmd = "diff -u < (echo 'aba'| fold -w1) < (echo 'abaa' | fold -w1)"
os.system(cmd)

运行上面的代码,我收到sh: 1: Syntax error: "(" unexpected错误。据我所知,unix os无法解析大括号内的echo命令。

帮我修复此错误。

3 个答案:

答案 0 :(得分:2)

该命令在bash中正常运行,但os.system()正在/bin/sh执行命令。您可以查看:

>>> os.system('echo $0')
sh
0

使用/bin/sh执行命令时失败:

[mhawke@localhost-localdomain ~]$ /bin/sh
sh-4.3$ diff -u <(echo "aba"| fold -w1) <(echo "abaa" | fold -w1)
sh: syntax error near unexpected token `('
sh-4.3$ 

您可以在bash中明确地运行命令,如下所示:

>>> os.system("""bash -c 'diff -u <(echo "aba"| fold -w1) <(echo "abaa" | fold -w1)'""")
--- /dev/fd/63  2017-02-26 09:18:14.633395225 +1100
+++ /dev/fd/62  2017-02-26 09:18:14.633395225 +1100
@@ -1,3 +1,4 @@
 a
 b
 a
+a
256

由于您可能对命令的输出感兴趣,因此您通常可以使用subprocess.check_output()来执行命令并收集其输出。不幸的是,diff在检测到输入文件中的差异时喜欢返回非零退出代码,因此无法简单地使用check_output。您可以通过diff:{/ p>来管道cat的输出作弊

>>> from subprocess import check_output
>>> output = check_output(['bash', '-c', 'diff -u <(echo "aba"| fold -w1) <(echo "abaa" | fold -w1) | cat'])
>>> print(output)
b'--- /dev/fd/63\t2017-02-26 10:02:56.814044987 +1100\n+++ /dev/fd/62\t2017-02-26 10:02:56.814044987 +1100\n@@ -1,3 +1,4 @@\n a\n b\n a\n+a\n'

>>> print(str(output, encoding='utf8'))
--- /dev/fd/63  2017-02-26 10:02:56.814044987 +1100
+++ /dev/fd/62  2017-02-26 10:02:56.814044987 +1100
@@ -1,3 +1,4 @@
 a
 b
 a
+a

答案 1 :(得分:2)

首先,不鼓励os.system()支持subprocess.call(cmd, shell=True)。这是值得了解的,因为subprocess文档中有很多其他细节,包括shell=True参数的这种描述(强调添加):

  

在POSIX上shell=True shell默认为/bin/sh .... Popen相当于:

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

所以现在我们知道为什么你的命令不起作用 - 它不是在调用Bash。正如mhawke建议您应该直接调用bash,但您应该更喜欢subprocess模块而不是os.system()

>>> subprocess.call(['/bin/bash', '-c', 'diff -u <(echo "aba"| fold -w1) <(echo "abaa" | fold -w1)'])
--- /dev/fd/63  2017-02-25 14:32:49.000000000 -0800
+++ /dev/fd/62  2017-02-25 14:32:49.000000000 -0800
@@ -1,3 +1,4 @@
 a
 b
 a
+a
1

请注意,由于我们显式调用Bash shell,因此我们不需要shell=True,因为我们告诉Bash调用的命令是单个参数,所以我们不需要反复转义他们,例如正如mhawke所做的那样"""

一旦您确认此命令有效,您可能希望不再简单地调用call()subprocess其他更易于编写脚本的函数,例如{{3 },它返回一个你可以检查的CompletedProcess对象。

正如让 - 弗朗索瓦·法布尔建议你可以用subprocess做更多有力的事情,包括将<()替换作为单独的进程启动并将它们用于调用diff ,从而避免需要在Python中调用bash或编写Bash语法。它更冗长,但更具可扩展性和可维护性。

答案 2 :(得分:0)

或者你可以

import subprocess
cmd = """bash -c 'diff -u <(echo "aba"| fold -w1) <(echo "abaa" | fold -w1)'"""

ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
output = ps.communicate()[0]