python調用Shell腳本,有兩種方法:os.system(cmd)或os.popen(cmd),前者返回值是腳本的退出狀態碼,后者的返回值是腳本執行過程中的輸出內容。所以說一般我們認為popen更加強大
os.system(cmd):
該方法在調用完shell腳本后,返回一個16位的二進制 數,低位為殺死所調用腳本的信號號碼,高位為腳本的退出狀態碼,即腳本中“exit 1”的代碼執行后,os.system函數返回值的高位數則是1,如果低位數是0的情況下,則函數的返回值是0×100,換算為10進制得到256。
os.popen(cmd):
這種調用方式是通過管道的方式來實現,函數返回一個file-like的對象,里面的內容是腳本輸出的內容(可簡單理解為echo輸出的內容)。
實例如下:
1 import numpy2 import os3 t=os.popen('ls')4 PRint t.read()5 t=os.system('ls')6 print t
效果:
server.py
setup.py
t
test
test.c
test.nja
test.o
0
-----------------------------------------------------我是分割線---------------------------------------------------------------------------------------------------------
受@趙銳指教,subprocess的Popen更實用。于是趕緊學習了一下
官方指南:https://docs.python.org/2/library/subprocess.html
官方也建議用這個替代(當然unix用戶還有個更新的subprocess32)
這個模塊粗略的看一下主要是啟用另一個線程,并可獲取輸入,輸出以及錯誤信息等,并提供了subprocess.Popen以及他的幾個封裝函數
先介紹下封裝的函數
一、subprocess.call
subprocess.call (*popenargs , **kwargs )
執行命令,并等待命令結束,再返回子進程的返回值。參數同Popen。我暫時的理解就是這個是加上了同步的popen。
二、subprocess.check_call
subprocess.check_call (*popenargs , **kwargs )
執行上面的call命令,并檢查返回值,如果子進程返回非0,則會拋出CalledProcessError異常,這個異常會有個returncode 屬性,記錄子進程的返回值。
三、check_output()
執行程序,并返回其標準輸出.
而Popen則用起來更廣泛,用起來和call一樣,只是如果要同步要自己加上wait
借鑒一下屬性
1.Popen.poll():用于檢查子進程是否已經結束。設置并返回returncode屬性。2.Popen.wait():等待子進程結束。設置并返回returncode屬性。3.Popen.communicate(input=None):與子進程進行交互。向stdin發送數據,或從stdout和stderr中讀取數據。可選參數input指定發送到子進程的參數。Communicate()返回一個元組:(stdoutdata, stderrdata)。注意:如果希望通過進程的stdin向其發送數據,在創建Popen對象的時候,參數stdin必須被設置為PipE。同樣,如果希望從stdout和stderr獲取數據,必須將stdout和stderr設置為PIPE。4.Popen.send_signal(signal):向子進程發送信號。5.Popen.terminate():停止(stop)子進程。在windows平臺下,該方法將調用Windows API TerminateProcess()來結束子進程。6.Popen.kill():殺死子進程。7.Popen.stdin:如果在創建Popen對象是,參數stdin被設置為PIPE,Popen.stdin將返回一個文件對象用于策子進程發送指令。否則返回None。8.Popen.stdout:如果在創建Popen對象是,參數stdout被設置為PIPE,Popen.stdout將返回一個文件對象用于策子進程發送指令。否則返回None。9.Popen.stderr:如果在創建Popen對象是,參數stdout被設置為PIPE,Popen.stdout將返回一個文件對象用于策子進程發送指令。否則返回None。10.Popen.pid:獲取子進程的進程ID。11.Popen.returncode:獲取進程的返回值。如果進程還沒有結束,返回None。12.subprocess.call(*popenargs, **kwargs):運行命令。該函數將一直等待到子進程運行結束,并返回進程的returncode。文章一開始的例子就演示了call函數。如果子進程不需要進行交互,就可以使用該函數來創建。13.subprocess.check_call(*popenargs, **kwargs):與subprocess.call(*popenargs, **kwargs)功能一樣,只是如果子進程返回的returncode不為0的話,將觸發CalledProcessError異常。在異常對象中,包括進程的returncode信息。
關于subprocess的安全性:
不像其他的popen函數,不會直接調用/bin/sh來解釋命令,也就是說,命令中的每一個字符都會被安全地傳遞到子進程里。
這里著重介紹一下怎么用這個替換原本的幾個庫
一、替換shell命令
output=`mycmd myarg`# 替換為output = check_output(["mycmd", "myarg"]
二、替換shell管道
output=`dmesg | grep hda`# 替換為p1 = Popen(["dmesg"], stdout=PIPE)p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)p1.stdout.close() # Allow p1 to receive a SIGPIPE if p2 exits.output = p2.communicate()[0]
三、替換os.system()
status = os.system("mycmd" + " myarg")# 替換為status = subprocess.call("mycmd" + " myarg", shell=True)
注意:
其實,更真實的替換是:
try:
retcode = call(“mycmd” + ” myarg”, shell=True)
if retcode < 0:
print >>sys.stderr, “Child was terminated by signal”, -retcode
else:
print >>sys.stderr, “Child returned”, retcode
except OSError, e:
print >>sys.stderr, “Execution failed:”, e
代替os.spawn系列
P_NOWAIT的例子
pid = os.spawnlp(os.P_NOWAIT, “/bin/mycmd”, “mycmd”, “myarg”)
等效于
pid = Popen(["/bin/mycmd", "myarg"]).pid
P_WAIT的例子
retcode = os.spawnlp(os.P_WAIT, “/bin/mycmd”, “mycmd”, “myarg”)
等效于
retcode = call(["/bin/mycmd", "myarg"])
Vector的例子
os.spawnvp(os.P_NOWAIT, path, args)
等效于
Popen([path] + args[1:])
關于環境變量的例子
os.spawnlpe(os.P_NOWAIT, “/bin/mycmd”, “mycmd”, “myarg”, env)
等效于
Popen(["/bin/mycmd", "myarg"], env={“PATH”: “/usr/bin”})
代替os.popen(), os.popen2(), os.popen3():
pipe = os.popen(“cmd”, ‘r’, bufsize)
等效于
pipe = Popen(“cmd”, shell=True, bufsize=bufsize, stdout=PIPE).stdout
pipe = os.popen(“cmd”, ‘w’, bufsize)
等效于
pipe = Popen(“cmd”, shell=True, bufsize=bufsize, stdin=PIPE).stdin
(child_stdin, child_stdout) = os.popen2(“cmd”, mode, bufsize)
等效于
p = Popen(“cmd”, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdin, child_stdout) = (p.stdin, p.stdout)
(child_stdin, child_stdout, child_stderr) = os.popen3(“cmd”, mode, bufsize)
等效于
p = Popen(“cmd”, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
(child_stdin, child_stdout, child_stderr) = (p.stdin, p.stdout, p.stderr)
(child_stdin, child_stdout_and_stderr) = os.popen4(“cmd”, mode, bufsize)
等效于
p = Popen(“cmd”, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True)
(child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout)
*nix下,os.popen2, os.popen3, os.popen4 也可以接受一個列表做為執行的命令,這時參數會被直接傳給程序,而不經過shell的解釋轉換。如下:
(child_stdin, child_stdout) = os.popen2(["/bin/ls", "-l"], mode, bufsize)
等效于
p = Popen(["/bin/ls", "-l"], bufsize=bufsize, stdin=PIPE, stdout=PIPE)
(child_stdin, child_stdout) = (p.stdin, p.stdout)
返回值處理:
pipe = os.popen(“cmd”, ‘w’)
…
rc = pipe.close()
if rc != None and rc % 256:
print “There were some errors”
等效于
process = Popen(“cmd”, ‘w’, shell=True, stdin=PIPE)
…
process.stdin.close()
if process.wait() != 0:
print “There were some errors”
代替popen2模塊里的函數:
(child_stdout, child_stdin) = popen2.popen2(“somestring”, bufsize, mode)
等效于
p = Popen(["somestring"], shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)
*nix下,popen2 也可以接受一個列表做為執行的命令,這時參數會被直接傳給程序,而不經過shell的解釋轉換。如下:
(child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode)
等效于
p = Popen(["mycmd", "myarg"], bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)
popen2.Popen3 and popen2.Popen4 基本上也能用 subprocess.Popen 代替,除了以下幾點要注意:
stdin=PIPE
和 stdout=PIPE
必須要指定close_fds=True
部分內容轉載于http://hi.baidu.com/u_chen/item/fbb839f2fdc6c713a629889e
新聞熱點
疑難解答