運行python的時候,我們都是在創建並運行一個進程。像Linux進程那樣,一個進程可以fork一個子進程,並讓這個子進程exec另外一個程序。在Python中,我們通過標准庫中的subprocess包來fork一個子進程,並運行一個外部的程序。
subprocess包中定義有數個創建子進程的函數,這些函數分別以不同的方式創建子進程,所以我們可以根據需要來從中選取一個使用。另外subprocess還提供了一些管理標准流(standard stream)和管道(pipe)的工具,從而在進程間使用文本通信。
call(*popenargs, **kwargs): 執行命令,返回狀態碼
>>> import subprocess >>> ret = subprocess.call(["ls", "-l"]) total 216 -rw-r--r-- 1 root root 297 May 5 21:23 class.py -rw-r--r-- 1 root root 330 May 4 10:33 fenye.py -rw-r--r-- 1 root root 173 May 4 07:24 obj.py >>> ret = subprocess.call("ls -l") #默認shell=False Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib64/python2.7/subprocess.py", line 524, in call return Popen(*popenargs, **kwargs).wait() File "/usr/lib64/python2.7/subprocess.py", line 711, in __init__ errread, errwrite) File "/usr/lib64/python2.7/subprocess.py", line 1308, in _execute_child raise child_exception OSError: [Errno 2] No such file or directory >>> ret = subprocess.call("ls -l", shell=True) #shell=True不會報錯 total 216 -rw-r--r-- 1 root root 297 May 5 21:23 class.py -rw-r--r-- 1 root root 330 May 4 10:33 fenye.py -rw-r--r-- 1 root root 173 May 4 07:24 obj.py >>> print(ret) 0
check_call(*popenargs, **kwargs): 執行命令,如果執行狀態碼是 0 ,則返回0,否則拋異常
>>> ret = subprocess.call(["cd", "A"]) /usr/bin/cd: line 2: cd: A: No such file or directory >>> ret = subprocess.check_call(["cd", "A"]) /usr/bin/cd: line 2: cd: A: No such file or directory Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib64/python2.7/subprocess.py", line 542, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command '['cd', 'A']' returned non-zero exit status 1
check_output(*popenargs, **kwargs):執行命令,如果狀態碼是 0 ,則返回執行結果,否則拋異常
>>> ret = subprocess.check_output(["ls", "-l"]) >>> print(ret) total 216 -rw-r--r-- 1 root root 297 May 5 21:23 class.py -rw-r--r-- 1 root root 330 May 4 10:33 fenye.py -rw-r--r-- 1 root root 173 May 4 07:24 obj.py >>> ret = subprocess.check_output(["lsa", "-l"]) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib64/python2.7/subprocess.py", line 568, in check_output process = Popen(stdout=PIPE, *popenargs, **kwargs) File "/usr/lib64/python2.7/subprocess.py", line 711, in __init__ errread, errwrite) File "/usr/lib64/python2.7/subprocess.py", line 1308, in _execute_child raise child_exception OSError: [Errno 2] No such file or directory
subprocess.Popen(...) 用於執行復雜的系統命令
參數:
- args:shell命令,可以是字符串或者序列類型(如:list,元組)
- bufsize:指定緩沖。0 無緩沖,1 行緩沖,其他 緩沖區大小,負值 系統緩沖
- stdin, stdout, stderr:分別表示程序的標准輸入、輸出、錯誤句柄
- preexec_fn:只在Unix平台下有效,用於指定一個可執行對象(callable object),它將在子進程運行之前被調用
- close_sfs:在windows平台下,如果close_fds被設置為True,則新創建的子進程將不會繼承父進程的輸入、輸出、錯誤管道。
所以不能將close_fds設置為True同時重定向子進程的標准輸入、輸出與錯誤(stdin, stdout, stderr)。 - shell:同上
- cwd:用於設置子進程的當前目錄
- env:用於指定子進程的環境變量。如果env = None,子進程的環境變量將從父進程中繼承。
- universal_newlines:不同系統的換行符不同,True -> 同意使用 \n
- startupinfo與createionflags只在windows下有效將被傳遞給底層的CreateProcess()函數,用於設置子進程的一些屬性,如:主窗口的外觀,進程的優先級等等
>>> obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) >>> obj.stdin.write("print('hello')\n") >>> obj.stdin.write("print('hello word')") >>> obj.stdin.close() >>> cmd_out = obj.stdout.read() >>> obj.stdout.close() >>> cmd_error = obj.stderr.read() >>> obj.stderr.close() >>> print(cmd_out) hello hello word >>> print(cmd_error)
或者
>>> obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) >>> obj.stdin.write("print('hello word')") >>> out_error_list = obj.communicate() >>> print(out_error_list) ('hello word\n', '')
管道(shell中的|)
[root@Python ~]# ls -l | wc -l 18 >>> p1=subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE) >>> p2=subprocess.Popen(["wc","-l"], stdin=p1.stdout,stdout=subprocess.PIPE) >>> out=p2.communicate() >>> print(out) (b'18\n', None)
上面實例其執行過程:
child1.stdout-->subprocess.PIPE
child2.stdin<--subprocess.PIPE
child2.stdout-->subprocess.PIPE
需要注意的是:communicate()是Popen對象的一個方法,該方法會阻塞父進程,直到子進程完成