【Python】模組之subprocess
一 簡介
在使用Python 開發MySQL自動化相關的運維工具的時候,遇到一些有意思的問題,本文介紹Python的 subprocess 模組以及如何和MySQL互動具體操作,如啟動 ,關閉 ,備份資料庫。
二 基礎知識
Python2.4引入來管理子程式,可以像Linux 系統中執行shell命令那樣fork一個子程式執行外部的命令,並且可以連線子程式的output/input/error管道,獲取命令執行的輸出,錯誤資訊,和執行成功與否的結果。
Subprocess 提供了三個函式以不同的方式建立子程式。他們分別是
subprocess.call()
父程式等待子程式完成,並且返回子程式執行的結果 0/1
其實現方式
例子
subprocess.check_call()
父程式等待子程式完成,正常情況下返回0,當檢查退出資訊,如果returncode不為0,則觸發異常
subprocess.CalledProcessError,該物件包含有returncode屬性,應用程式中可用try...except...來檢查命令是否執行成功。
其實現方式
例子
subprocess.check_output()
和 subprocess.check_call() 類似,但是其返回的結果是執行命令的輸出,而非返回0/1
其實現方式
例子
透過上面三個例子,我們可以看出前面兩個函式不容易控制輸出內容,在使用subprocess包中的函式建立子程式執行命令的時候,需要考慮
1) 在建立子程式之後,父程式是否暫停,並等待子程式執行。
2) 如何處理函式返回的資訊(命令執行的結果或者錯誤資訊)
3) 當子程式執行的失敗也即returncode不為0時,父程式如何處理後續流程?
三 subprocess的核心類 Popen()
認真的讀者朋友可以看出上面三個函式都是基於Popen實現的,為啥呢?因為 subprocess 僅僅提供了一個類,call(),check_call(),check_outpu()都是基於Popen封裝而成。當我們需要更加自主的應用subprocess來實現應用程式的功能時,
我們要自己動手直接使用Popen()生成的物件完成任務。接下來我們研究Popen()的常見用法 ,詳細的用法請參考
Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)
這裡我們只要掌握常用的引數即可
args 字串或者列表,比如 "ls -a" / ["ls","-a"]
stdin/stdout/stderr 為None時表示沒有任何重定向,繼承父程式,還可以設定為PIPE 建立管道/檔案物件/檔案描述符(整數)/stderr 還可以設定為 STDOUT 後面會給出常見的用法
shell 是否使用shell來執行程式。當shell=True, 它將args看作是一個字串,而不是一個序列。在Unix系統,且 shell=True時,shell預設使用 /bin/sh.
如果 args是一個字串,則它宣告瞭透過shell執行的命令。這意味著,字串必須要使用正確的格式。
如果 args是一個序列,則第一個元素就是命令字串,而其它的元素都作為引數使用。可以這樣說,Popen等價於:
Popen(['/bin/sh', '-c', args[0], args[1], ...])
與上面第二部分介紹的三個函式不同,subprocess.Popen() fork子程式之後主程式不會等待子程式結束,而是直接執行後續的命令。當我們需要等待子程式結束必須使用wait()或者communicate()函式。舉個例子,
從執行結果上看,子程式 ping命令並未執行完畢,subprocess.Popen()後面的命令就開始執行了。
Popen常見的函式
Popen.poll() 用於檢查子程式是否已經結束,設定並返回returncode屬性。
Popen.wait() 等待子程式結束,設定並返回returncode屬性。
Popen.communicate(input=None) 與子程式進行互動。向stdin傳送資料,或從stdout和stderr中讀取資料。可選引數input指定傳送到子程式的引數。 Communicate()返回一個元組:(stdoutdata, stderrdata)。注意:如果希望透過程式的stdin向其傳送資料,在建立Popen物件的時候,引數stdin必須被設定為PIPE。同樣,如果希望從stdout和stderr獲取資料,必須將stdout和stderr設定為PIPE。需要注意的是 communicate()是Popen物件的一個方法,該方法會阻塞父程式,直到子程式完成。
Popen.send_signal(signal) 向子程式傳送訊號。
Popen.terminate() 終止子程式。
Popen.kill() 殺死子程式。
Popen.pid 獲取子程式的程式ID。
Popen.returncode 獲取程式的返回值,成功時,返回0/失敗時,返回 1。如果程式還沒有結束,返回None。
這裡需要多做說明的是
對於 wait() 官方提示
即當stdout/stdin設定為PIPE時,使用wait()可能會導致死鎖。因而建議使用communicate
而對於communicate,文件又給出:
communicate會把資料讀入記憶體快取下來,所以當資料很大或者是無限的資料時不要使用。
那麼坑爹的問題來了:當你要使用Python的subprocess.Popen實現命令列之間的管道傳輸,同時資料來源又非常大(比如讀取上GB的文字或者無盡的網路流)時,官方文件不建議用wait,同時communicate還可能把記憶體撐爆,我們該怎麼操作?
四 Subprocess 和MySQL 的互動
紙上來得終覺淺,絕知此事要躬行。自動化運維需求中會有重啟/關閉/備份/恢復 MySQL的需求。怎麼使用Python的subprocess來解決呢?啟動MySQL的命令如下
實際上使用child=subprocess.Popen(startMySQL,shell=True,stdout=stdout=subprocess.PIPE),子程式mysql_safe是無任何返回輸出的,使用,child.communicate()或者讀取stdout 則會持續等待。
需要使用 child.wait()或者child.poll()檢查子程式是否執行完成。
五 參考資料
[1]
[2] Python中的subprocess與Pipe
[3] python類庫31[程式subprocess]
在使用Python 開發MySQL自動化相關的運維工具的時候,遇到一些有意思的問題,本文介紹Python的 subprocess 模組以及如何和MySQL互動具體操作,如啟動 ,關閉 ,備份資料庫。
二 基礎知識
Python2.4引入來管理子程式,可以像Linux 系統中執行shell命令那樣fork一個子程式執行外部的命令,並且可以連線子程式的output/input/error管道,獲取命令執行的輸出,錯誤資訊,和執行成功與否的結果。
Subprocess 提供了三個函式以不同的方式建立子程式。他們分別是
subprocess.call()
父程式等待子程式完成,並且返回子程式執行的結果 0/1
其實現方式
-
def call(*popenargs, **kwargs):
- return Popen(*popenargs, **kwargs).wait()
-
>>> out=subprocess.call(["ls", "-l"])
-
total 88
-
drwxr-xr-x 5 yangyi staff 170 1 25 22:37 HelloWorld
-
drwxr-xr-x 11 yangyi staff 374 12 18 2015 app
-
-rw-r--r-- 1 yangyi staff 3895 4 19 11:29 check_int.py
-
..... 省略一部分
-
>>> print out
-
0
-
>>> out=subprocess.call(["ls", "-I"])
-
ls: illegal option -- I
-
usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]
-
>>> print out
- 1
父程式等待子程式完成,正常情況下返回0,當檢查退出資訊,如果returncode不為0,則觸發異常
subprocess.CalledProcessError,該物件包含有returncode屬性,應用程式中可用try...except...來檢查命令是否執行成功。
其實現方式
-
def check_call(*popenargs, **kwargs):
-
retcode = call(*popenargs, **kwargs)
-
if retcode:
-
cmd = kwargs.get("args")
-
raise CalledProcessError(retcode, cmd)
- return 0
-
>>> out=subprocess.check_call(["ls"])
-
HelloWorld check_int.py enumerate.py hello.py
-
>>> print out
-
0
-
>>> out=subprocess.check_call(["ls",'-I']) #執行命令失敗的時候回丟擲CalledProcessError異常,並且返回結果1
-
ls: illegal option -- I
-
usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]
-
Traceback (most recent call last):
-
File "", line 1, in <module>
-
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 540, in check_call
-
raise CalledProcessError(retcode, cmd)
- subprocess.CalledProcessError: Command '['ls', '-I']' returned non-zero exit status 1
和 subprocess.check_call() 類似,但是其返回的結果是執行命令的輸出,而非返回0/1
其實現方式
-
def check_output(*popenargs, **kwargs):
-
process = Popen(*popenargs, stdout=PIPE, **kwargs)
-
output, unused_err = process.communicate()
-
retcode = process.poll()
-
if retcode:
-
cmd = kwargs.get("args")
-
raise CalledProcessError(retcode, cmd, output=output)
- return output
-
>>> out=subprocess.check_output(["ls"]) #成功執行命令
-
>>> print out
-
HelloWorld
-
check_int.py
-
enumerate.py
-
flasky
-
hello.py
-
>>> out=subprocess.check_output(["ls","-I"])#執行命令出現異常直接列印出異常資訊。
-
ls: illegal option -- I
-
usage: ls [-ABCFGHLOPRSTUWabcdefghiklmnopqrstuwx1] [file ...]
-
Traceback (most recent call last):
-
File "", line 1, in <module>
-
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 573, in check_output
-
raise CalledProcessError(retcode, cmd, output=output)
-
subprocess.CalledProcessError: Command '['ls', '-I']' returned non-zero exit status 1
- >>>
1) 在建立子程式之後,父程式是否暫停,並等待子程式執行。
2) 如何處理函式返回的資訊(命令執行的結果或者錯誤資訊)
3) 當子程式執行的失敗也即returncode不為0時,父程式如何處理後續流程?
三 subprocess的核心類 Popen()
認真的讀者朋友可以看出上面三個函式都是基於Popen實現的,為啥呢?因為 subprocess 僅僅提供了一個類,call(),check_call(),check_outpu()都是基於Popen封裝而成。當我們需要更加自主的應用subprocess來實現應用程式的功能時,
我們要自己動手直接使用Popen()生成的物件完成任務。接下來我們研究Popen()的常見用法 ,詳細的用法請參考
Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0)
這裡我們只要掌握常用的引數即可
args 字串或者列表,比如 "ls -a" / ["ls","-a"]
stdin/stdout/stderr 為None時表示沒有任何重定向,繼承父程式,還可以設定為PIPE 建立管道/檔案物件/檔案描述符(整數)/stderr 還可以設定為 STDOUT 後面會給出常見的用法
shell 是否使用shell來執行程式。當shell=True, 它將args看作是一個字串,而不是一個序列。在Unix系統,且 shell=True時,shell預設使用 /bin/sh.
如果 args是一個字串,則它宣告瞭透過shell執行的命令。這意味著,字串必須要使用正確的格式。
如果 args是一個序列,則第一個元素就是命令字串,而其它的元素都作為引數使用。可以這樣說,Popen等價於:
Popen(['/bin/sh', '-c', args[0], args[1], ...])
與上面第二部分介紹的三個函式不同,subprocess.Popen() fork子程式之後主程式不會等待子程式結束,而是直接執行後續的命令。當我們需要等待子程式結束必須使用wait()或者communicate()函式。舉個例子,
-
import subprocess
-
sbp=subprocess.Popen(["ping","-c","5",""])
- print "ping is not done"
從執行結果上看,子程式 ping命令並未執行完畢,subprocess.Popen()後面的命令就開始執行了。
Popen常見的函式
Popen.poll() 用於檢查子程式是否已經結束,設定並返回returncode屬性。
Popen.wait() 等待子程式結束,設定並返回returncode屬性。
Popen.communicate(input=None) 與子程式進行互動。向stdin傳送資料,或從stdout和stderr中讀取資料。可選引數input指定傳送到子程式的引數。 Communicate()返回一個元組:(stdoutdata, stderrdata)。注意:如果希望透過程式的stdin向其傳送資料,在建立Popen物件的時候,引數stdin必須被設定為PIPE。同樣,如果希望從stdout和stderr獲取資料,必須將stdout和stderr設定為PIPE。需要注意的是 communicate()是Popen物件的一個方法,該方法會阻塞父程式,直到子程式完成。
Popen.send_signal(signal) 向子程式傳送訊號。
Popen.terminate() 終止子程式。
Popen.kill() 殺死子程式。
Popen.pid 獲取子程式的程式ID。
Popen.returncode 獲取程式的返回值,成功時,返回0/失敗時,返回 1。如果程式還沒有結束,返回None。
這裡需要多做說明的是
對於 wait() 官方提示
- Warning This will deadlock when using stdout=PIPE and/or stderr=PIPE and the child process generates enough output to a pipe such that it blocks waiting for the OS pipe buffer to accept more data. Use communicate() to avoid that.
而對於communicate,文件又給出:
-
Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optionalinput argument should be a string to be sent to the child process, orNone, if no data should be sent to the child.communicate() returns a tuple (stdoutdata, stderrdata).
-
Note that if you want to send data to the process’s stdin, you need to create the Popen object with stdin=PIPE. Similarly, to get anything other thanNone in the result tuple, you need to give stdout=PIPE and/orstderr=PIPE too.
-
Note
- The data read is buffered in memory, so do not use this method if the data size is large or unlimited.
那麼坑爹的問題來了:當你要使用Python的subprocess.Popen實現命令列之間的管道傳輸,同時資料來源又非常大(比如讀取上GB的文字或者無盡的網路流)時,官方文件不建議用wait,同時communicate還可能把記憶體撐爆,我們該怎麼操作?
四 Subprocess 和MySQL 的互動
紙上來得終覺淺,絕知此事要躬行。自動化運維需求中會有重啟/關閉/備份/恢復 MySQL的需求。怎麼使用Python的subprocess來解決呢?啟動MySQL的命令如下
- startMySQL="/usr/bin/mysqld_safe --defaults-file=/srv/my{0}/my.cnf --read_only=1 & ".format(port)
需要使用 child.wait()或者child.poll()檢查子程式是否執行完成。
-
import subprocess,time
-
def startMySQL(port):
-
startMySQL="/usr/bin/mysqld_safe --defaults-file=/srv/my{0}/my.cnf --read_only=1 & ".format(port)
-
child=subprocess.Popen(startMySQL, shell=True,stdout=subprocess.PIPE)
-
child.poll()
-
time.sleep(3) #有些MySQL例項啟動可能需要一定的時間
-
if child.returncode:
-
print "instance {0} startup failed ...".format(port)
-
else:
-
print "instance {0} startup successed ...".format(port)
-
return
-
root@rac3:~/python# >python 1.py
- instance 3308 startup successed ...
[1]
[2] Python中的subprocess與Pipe
[3] python類庫31[程式subprocess]
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22664653/viewspace-2121025/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- python Subprocess 模組Python
- python之subprocessPython
- Python模組學習:subprocess 建立子程式Python
- python如何呼叫subprocess模組實現外部命令?Python
- python subprocessPython
- 序列化模組,subprocess模組,re模組,常用正則
- python常用模組補充hashlib configparser logging,subprocess模組Python
- Python中subprocess學習Python
- python模組之collections模組Python
- python之模組Python
- Python模組之urllib模組Python
- python–模組之基本Python
- python之shutil模組Python
- python之time模組Python
- 【Python】模組之fileinputPython
- 【Python】模組之queuePython
- python–模組之random隨機數模組Pythonrandom隨機
- python–模組之os操作檔案模組Python
- Python模組之jsonPythonJSON
- python模組之hashlibPython
- Python基礎之模組Python
- Python學習之模組Python
- Python常用模組之sysPython
- 【python】python 模組學習之--FabricPython
- 【python】python 模組學習之--pexpectPython
- python模組之os.pathPython
- python模組之configparserPython
- Python之time模組詳解Python
- Python之OS模組詳解Python
- Python學習之常用模組Python
- python學習之argparse模組Python
- python中使用subprocess批量執行linux下命令PythonLinux
- python中使用subprocess批次執行linux下命令PythonLinux
- Python 快速教程(標準庫06):子程式 (subprocess包)Python
- python之匯入模組的方法Python
- Python學習之 datetime模組Python
- python之排序操作及heapq模組Python排序
- Python學習之模組與包Python