2017-02-25 184 views
1
diff -u <(echo "aba"| fold -w1) <(echo "abaa" | fold -w1) 

我想從Python代碼執行上述命令。以下是我寫的代碼。從python代碼執行Unix命令

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

運行上面的代碼,我得到了sh: 1: Syntax error: "(" unexpected錯誤。據我所知,unix os無法解析大括號內的echo命令。

幫我解決這個錯誤。

回答

2

命令在bash中正常運行,但os.system()正在執行/bin/sh中的命令。

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

/bin/sh執行的命令失敗:

[[email protected] ~]$ /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的輸出通過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\[email protected]@ -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

最好的辦法是使用與管道鏈接在一起3'Popen'對象。 –

+0

@ Jean-FrançoisFabre:這是真的,但這取決於你的觀點。 OP詢問'os.system()'。 – mhawke

+0

我不是在批評你的答案,而是問題:) +1是我的。我應該評論這個問題,而不是答案。我不能責怪你不想用python編寫3個管道! –

2

首先,os.system()是有利於subprocess.call(cmd, shell=True)氣餒。這是值得了解的,因爲有很多的附加細節的subprocess文檔中,包括shell=True參數的描述(強調):

在POSIX與shell=True,該殼默認爲/bin/sh .... POPEN不等價的:

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

所以,現在我們知道爲什麼你的命令不起作用 - 這不是調用猛砸。作爲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功能之一是更多的腳本友好的,如run(),它返回一個CompletedProcess對象,你可以檢查移開。

正如讓 - 弗朗索瓦·法布爾建議你可以做很多更強大的東西與subprocess,以及包括啓動<()替換爲單獨的進程,並將它們通過管道進入呼叫diff,從而避免了需要調用bash或寫的Bash語法在Python中。它更冗長,但更具可擴展性和可維護性。

+1

和便攜式,你只需要在窗口上安裝'diff'&'fold'。 –

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] 
+0

如果你沒有全部使用3個子進程對象並刪除'shell = True'部分,那麼使用'subprocess'而不是'os.system()'有什麼意義? –

+0

@ Jean-FrançoisFabre「最好的方法是使用與管道連接在一起的3個Popen對象。」你是這個意思嗎? – Juggernaut