實際應用中,有些時候咱們不得不跟操做系統進行指令級別的交互,如Linux中的shell。Python中早期經過os模塊和commands模塊來實現操做系統級別的交互,但從2.4版本開始,官方建議使用subprocess模塊。所以對於os和commands模塊只會簡單講解,重點會放在subprocess模塊和Popen類上。html
對於指令的執行,咱們通常關注如下兩點:python
Python中提供瞭如下幾個函數來幫助咱們完成命令行指令的執行:linux
說明:redis
- os.popen(command)函數獲得的是一個文件對象,所以除了read()方法外還支持write()等方法,具體要根據command來定;
- commands模塊只存在於Python 2.7中,且不支持windows平臺,所以commands模塊不多被使用。另外,commands模塊實際上也是經過對os.popen()的封裝來完成的。
以上內容轉載自http://www.cnblogs.com/yyds/p/7288916.html,下面是簡單的程序示例:shell
1 >>> import os 2 >>> os.system('pwd') 3 /root #命令執行結果 4 0 #命令執行狀態 5 >>> os.system('pwd1') 6 sh: pwd1: command not found 7 32512 8 >>> res=os.system('wget') 9 wget: missing URL 10 Usage: wget [OPTION]... [URL]... 11 12 Try ‘wget --help’ for more options. 13 >>> res=os.system('redis') 14 sh: redis: command not found #命令執行結果 15 >>> res 16 32512 #命令執行狀態
1 >>> import os 2 >>> os.popen('uptime') 3 <open file 'uptime', mode 'r' at 0x7ff37451cc00> 4 >>> print(os.popen('uptime').read()) 5 07:21:57 up 33 days, 2:00, 1 user, load average: 0.00, 0.00, 0.00
1 >>> import commands 2 >>> commands.getstatusoutput('who') 3 (0, 'root pts/0 2018-03-05 07:15 (172.17.35.6)') 4 >>> commands.getstatusoutput('uptime') 5 (0, ' 07:24:34 up 33 days, 2:02, 1 user, load average: 0.00, 0.00, 0.00')
subprocess模塊是關鍵建議使用的模塊,顧名思義是創建一個子進程,用來運行與系統交互的指令。Subporcess模塊經常使用的函數有如下幾類:windows
說明:api
上述內容轉載自http://www.cnblogs.com/yyds/p/7288916.html數組
下面詳解講解函數的具體用法。緩存
語法:subprocess.run(args, *, stdin=None, stdout=None, stderr=None, shell=False)
使用說明:這是python 3.5版本才新增出現的函數,用於執行指定的命令,等待命令執行完成後返回一個包含執行結果的CompletedProcess類的實例。
這裏重點講述下shell=False這個參數:
默認狀況下這個參數爲False,不調用shell自己支持的一些特性(如管道、文件名通配符、環境變量擴展功能)必須以列表形式傳遞須要執行的命令,第一個元素做爲命令,後續的元素做爲命令參數;而shell=True參數會讓subprocess.call接受字符串類型的變量做爲命令,並調用shell去執行這個字符串(可使用shell的特性了,如管道、文件名通配符、環境變量擴展功能),若是命令使用了shell的分隔符,那麼還能夠一次性執行多條命令,使用起來很方便。
問題來了,既然shell=True使用更方便,爲何默認值是Flase呢?這是由於萬一對傳入的命令檢查不夠仔細,執行了危險的命令好比 rm -rf / 這種那後果會很是嚴重,而使用shell=False就能夠避免這種風險,所以是一種安全機制。
仍是上程序把(程序在linux下運行效果更直觀):安全
1 >>> import subprocess 2 >>> subprocess.run(['ls', '-l']) #列表形式傳遞命令 3 total 28 4 -rw-------. 1 root root 1096 Sep 24 2015 anaconda-ks.cfg 5 -rw-r--r-- 1 root root 238 Jan 11 13:12 history_command 6 -rw-r--r--. 1 root root 8835 Sep 24 2015 install.log 7 -rw-r--r--. 1 root root 3384 Sep 24 2015 install.log.syslog 8 drwxr-xr-x 3 root root 4096 Mar 6 04:55 software 9 CompletedProcess(args=['ls', '-l'], returncode=0)#返回了狀態碼 10 >>> subprocess.run('ls -l', shell=True) 11 total 28 12 -rw-------. 1 root root 1096 Sep 24 2015 anaconda-ks.cfg 13 -rw-r--r-- 1 root root 238 Jan 11 13:12 history_command 14 -rw-r--r--. 1 root root 8835 Sep 24 2015 install.log 15 -rw-r--r--. 1 root root 3384 Sep 24 2015 install.log.syslog 16 drwxr-xr-x 3 root root 4096 Mar 6 04:55 software 17 CompletedProcess(args='ls -l', returncode=0) #單字符串形式傳遞命令 18 >>> subprocess.run('ls|wc -l', shell=True) 19 5 20 CompletedProcess(args='ls|wc -l', returncode=0) 21 >>> subprocess.run('ls|wc -l') 22 Traceback (most recent call last): 23 File "<stdin>", line 1, in <module> 24 File "/usr/local/python_3.6.2/lib/python3.6/subprocess.py", line 403, in run 25 with Popen(*popenargs, **kwargs) as process: 26 File "/usr/local/python_3.6.2/lib/python3.6/subprocess.py", line 707, in __init__ 27 restore_signals, start_new_session) 28 File "/usr/local/python_3.6.2/lib/python3.6/subprocess.py", line 1333, in _execute_child 29 raise child_exception_type(errno_num, err_msg) 30 FileNotFoundError: [Errno 2] No such file or directory: 'ls|wc -l'
注意:
若是必須使用shell的特性而沒有設置shell的參數爲Ture,程序會直接報錯沒有該文件或目錄。
語法:subprocess.run(args, *, stdin=None, stdout=None, stderr=None, shell=False)
使用說明:執行指定的命令,返回執行狀態返回碼,其功能相似於os.system(cmd)。在使用這個函數時,不要使用 stdout=PIPE 或 stderr=PIPE 參數,否則會致使子進程輸出的死鎖。若是要使用管道,能夠在 communicate()方法中使用Popen(網上看到的論述,須要後續實踐)
1 >>> import subprocess 2 >>> subprocess.call('ls|wc -l', shell=True) #管道符,必須調用shell才能支持 3 37 #命令執行結果 4 0 #命令執行狀態返回碼
語法:subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False)
使用說明:運行由args指定的命令,直到命令執行完成。若是返回碼爲零,則返回。不然,拋出 CalledProcessError異常。CalledProcessError對象包含有返回碼的屬性值。
1 >>> import subprocess 2 >>> subprocess.check_call('ls -l', shell=True) 3 total 28 4 -rw-------. 1 root root 1096 Sep 24 2015 anaconda-ks.cfg 5 -rw-r--r-- 1 root root 238 Jan 11 13:12 history_command 6 -rw-r--r--. 1 root root 8835 Sep 24 2015 install.log 7 -rw-r--r--. 1 root root 3384 Sep 24 2015 install.log.syslog 8 drwxr-xr-x 3 root root 4096 Mar 6 04:55 software 9 0返回碼 10 >>> subprocess.check_call('ls1', shell=True) #執行出錯 11 /bin/sh: ls1: command not found 12 Traceback (most recent call last): 13 File "<stdin>", line 1, in <module> 14 File "/usr/local/python_3.6.2/lib/python3.6/subprocess.py", line 291, in check_call 15 raise CalledProcessError(retcode, cmd) 16 subprocess.CalledProcessError: Command 'ls1' returned non-zero exit status 127.
1 >>> import subprocess 2 >>> res=subprocess.check_call('ls', shell=True) 3 anaconda-ks.cfg history_command install.log install.log.syslog software 4 >>> res 5 0
語法:subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)
使用說明:
Python 2.7中新增的的函數。執行指定的命令,若是執行狀態碼爲0則返回命令執行結果,不然拋出CalledProcessError異常。
universal_newlines參數說明: 該參數影響的是輸入與輸出的數據格式,好比它的值默認爲False,此時stdout和stderr的輸出是字節序列;當該參數的值設置爲True時,stdout和stderr的輸出是字符串。
1 >>> import subprocess 2 >>> subprocess.check_output('ls', shell=True) #默認返回的結果是字節序列 3 b'anaconda-ks.cfg\nhistory_command\ninstall.log\ninstall.log.syslog\nsoftware\n' 4 >>> subprocess.check_output('ls', shell=True, universal_newlines=True) #輸出字符串形式 5 'anaconda-ks.cfg\nhistory_command\ninstall.log\ninstall.log.syslog\nsoftware\n' 6 >>> subprocess.check_output('ls1', shell=True, universal_newlines=True) #執行失敗 7 /bin/sh: ls1: command not found 8 Traceback (most recent call last): 9 File "<stdin>", line 1, in <module> 10 File "/usr/local/python_3.6.2/lib/python3.6/subprocess.py", line 336, in check_output 11 **kwargs).stdout 12 File "/usr/local/python_3.6.2/lib/python3.6/subprocess.py", line 418, in run 13 output=stdout, stderr=stderr) 14 subprocess.CalledProcessError: Command 'ls1' returned non-zero exit status 127.
注意:
1. 不要在這個函數中使用 stdout=PIPE 或 stderr=PIPE, 不然會形成子進程死鎖。若是須要使用管道,能夠在 communicate()方法中使用Popen.
2. 若是要捕捉結果中的標準錯誤,可以使用 stderr=subprocess.STDOUT參數,實際測試也只是輸出了狀態碼,並無給出具體的錯誤緣由信息,待後續驗證。
語法:subprocess.getoutput(cmd)
使用說明:接收字符串格式的命令,執行命令並返回執行結果,其功能相似於os.popen(cmd).read()和commands.getoutput(cmd)。
1 >>> import subprocess 2 >>> subprocess.getoutput('ls', shell=True) 3 Traceback (most recent call last): 4 File "<stdin>", line 1, in <module> 5 TypeError: getoutput() got an unexpected keyword argument 'shell' #再也不接受其餘參數 6 >>> 7 >>> subprocess.getoutput('ls') #純字符串形式輸出結果 8 'anaconda-ks.cfg\nhistory_command\ninstall.log\ninstall.log.syslog\nsoftware' 9 >>> subprocess.getoutput('ls1') 10 '/bin/sh: ls1: command not found'
語法:subprocess.getstatusoutput(cmd)
使用說明:執行cmd命令,返回一個元組(命令執行狀態, 命令執行結果輸出),其功能相似於commands.getstatusoutput()。
1 >>> import subprocess 2 >>> subprocess.getstatusoutput('ls') 3 (0, 'anaconda-ks.cfg\nhistory_command\ninstall.log\ninstall.log.syslog\nsoftware') 4 >>> subprocess.getstatusoutput('ls1') 5 (127, '/bin/sh: ls1: command not found') 6 >>>
1 class subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, 2 preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, 3 startup_info=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=())
參數說明:
•args: 要執行的shell命令,能夠是字符串,也能夠是命令各個參數組成的序列。當該參數的值是一個字符串時,該命令的解釋過程是與平臺相關的,所以一般建議將args參數做爲一個序列傳遞。
•bufsize: 指定緩存策略,0表示不緩衝,1表示行緩衝,其餘大於1的數字表示緩衝區大小,負數表示使用系統默認緩衝策略。
•stdin, stdout, stderr: 分別表示程序標準輸入、輸出、錯誤句柄。 它們的值能夠是PIPE, 一個存在的文件描述符(正整數),一個存在的文件對象或 None.
•preexec_fn: 用於指定一個將在子進程運行以前被調用的可執行對象,只在Unix平臺下有效。
•close_fds: 若是該參數的值爲True,則除了0,1和2以外的全部文件描述符都將會在子進程執行以前被關閉。
•shell: 該參數用於標識是否使用shell做爲要執行的程序,若是shell值爲True,則建議將args參數做爲一個字符串傳遞而不要做爲一個序列傳遞。
•cwd: 若是該參數值不是None,則該函數將會在執行這個子進程以前改變當前工做目錄。
•env: 用於指定子進程的環境變量,若是env=None,那麼子進程的環境變量將從父進程中繼承。若是env!=None,它的值必須是一個映射對象。
•universal_newlines: 若是該參數值爲True,則該文件對象的stdin,stdout和stderr將會做爲文本流被打開,不然他們將會被做爲二進制流被打開。
•startupinfo和creationflags: 這兩個參數只在Windows下有效,它們將被傳遞給底層的CreateProcess()函數,用於設置子進程的一些屬性,如主窗口的外觀,進程優先級等
Open類的經常使用方法大概可分爲兩類,一類是與子進程進行交互的方法,如stdin,stdout,stderr,communicate,kill,terminate,send_signal,另一類是獲取子進程的狀態信息,如pid,poll,下面逐一展開它們的用法:
1 >>> import subprocess 2 >>> p1=subprocess.Popen(['python'], stdin=subprocess.PIPE, stdout=subprocess.PIP 3 E, stderr=subprocess.PIPE) 4 >>> 5 >>> 6 >>> p1.stdin.write("print('Hello World!')") 7 Traceback (most recent call last): 8 File "<stdin>", line 1, in <module> 9 TypeError: a bytes-like object is required, not 'str' 10 >>> p1=subprocess.Popen(['python'], stdin=subprocess.PIPE, stdout=subprocess.PIP 11 E, stderr=subprocess.PIPE, universal_newlines=True) 12 >>> 13 >>> p1.stdin.write("print('Hello World!')") 14 21 15 >>> out,err=p1.communicate() 16 >>> p1.stdin.close() 17 >>> print(out) 18 Hello World! 19
1 import subprocess 2 3 p1 = subprocess.Popen(['dir'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 4 print(p1.stdout.read()) 5 6 輸出: 7 驅動器 D 中的卷是 本地磁盤 8 卷的序列號是 6651-23F0 9 10 D:\python\S13\Day5\test 的目錄 11 12 2018/03/10 08:07 <DIR> . 13 2018/03/10 08:07 <DIR> .. 14 2017/12/26 07:43 8 1.txt 15 2017/12/26 06:32 374 2.py 16 ...
1 import subprocess 2 3 p1 = subprocess.Popen(['dir 1'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 4 print(p1.stderr.read()) 5 6 輸出: 7 '"dir 1"' 不是內部或外部命令,也不是可運行的程序 8 或批處理文件。
Popen.communicate()
。這個方法會把輸出放在內存,而不是管道里,因此這時候上限就和內存大小有關了,通常不會有問題。並且若是要得到程序返回值,能夠在調用 Popen.communicate()
以後取 Popen.returncode
的值。1 import subprocess 2 3 p1 = subprocess.Popen(['python'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 4 p1.communicate(input="print('Hello world!')") 5 out,err=p1.communicate() 6 print(p1.communicate()) 7 print(out) 8 9 輸出: 10 ('Hello world!\n', '') 11 Hello world! 12
1 >>> import subprocess 2 >>> p1 = subprocess.Popen(['ls','007'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) 3 >>> out,err=p1.communicate() 4 >>> print(err) 5 ls: cannot access 007: No such file or directory
1 >>> import subprocess 2 >>> file = open('file.log', encoding='utf-8', mode='a') 3 >>> p1 = subprocess.Popen('ping -c 10 baidu.com', stdin=subprocess.PIPE, stdout=file, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 4 >>> print(p1.communicate()) 5 (None, '') 6 >>> quit() 7 [root@test211 ~]# ls -ltr 8 total 32 9 -rw-r--r--. 1 root root 3384 Sep 24 2015 install.log.syslog 10 -rw-r--r--. 1 root root 8835 Sep 24 2015 install.log 11 -rw-------. 1 root root 1096 Sep 24 2015 anaconda-ks.cfg 12 -rw-r--r-- 1 root root 238 Jan 11 13:12 history_command 13 drwxr-xr-x 3 root root 4096 Mar 6 04:55 software 14 -rw-r--r-- 1 root root 818 Mar 11 07:10 file.log 15 [root@test211 ~]# cat file.log 16 PING baidu.com (111.13.101.208) 56(84) bytes of data. 17 64 bytes from 111.13.101.208: icmp_seq=1 ttl=52 time=43.7 ms 18 64 bytes from 111.13.101.208: icmp_seq=2 ttl=52 time=42.4 ms 19 64 bytes from 111.13.101.208: icmp_seq=3 ttl=52 time=43.1 ms 20 64 bytes from 111.13.101.208: icmp_seq=4 ttl=52 time=43.6 ms 21 64 bytes from 111.13.101.208: icmp_seq=5 ttl=52 time=43.5 ms 22 64 bytes from 111.13.101.208: icmp_seq=6 ttl=52 time=43.7 ms 23 64 bytes from 111.13.101.208: icmp_seq=7 ttl=52 time=43.4 ms 24 64 bytes from 111.13.101.208: icmp_seq=8 ttl=52 time=42.4 ms 25 64 bytes from 111.13.101.208: icmp_seq=9 ttl=52 time=43.6 ms 26 64 bytes from 111.13.101.208: icmp_seq=10 ttl=52 time=43.6 ms 27 28 --- baidu.com ping statistics --- 29 10 packets transmitted, 10 received, 0% packet loss, time 9058ms 30 rtt min/avg/max/mdev = 42.437/43.349/43.760/0.479 ms
1 >>> import subprocess 2 >>> p1 = subprocess.Popen(["ping -c 10 baidu.com"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 3 >>> print(p1.poll()) 4 None #子進程未結束 5 >>> print(p1.poll()) 6 0 #子進程已結束
1 >>> import subprocess 2 >>> p1 = subprocess.Popen(["ping -c 10 baidu.com"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 3 >>> p1.wait() 4 0 5 >>> import subprocess 6 >>> p2 = subprocess.Popen(["sleep 15;ls 007"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 7 >>> p2.wait() 8 2 9 >>> p3 = subprocess.Popen(["sleep 15;pwd1"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 10 >>> p3.wait() 11 127
1 >>> import subprocess 2 >>> p1 = subprocess.Popen(["ping -c 5 baidu.com"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 3 >>> print(p1.pid) 4 4219 5 6 查看pid的進程 7 [root@test211 ~]# ps -ef|grep 4219 8 root 4219 4218 0 21:37 pts/0 00:00:00 [ping] <defunct> 9 root 4223 4150 0 21:38 pts/1 00:00:00 grep --color 4219
1 import subprocess 2 p1 = subprocess.Popen('ping -n 5 baidu.com', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 3 out,error=p1.communicate() 4 print(p1.pid) 5 print(out) 6 7 輸出: 8 9060 9 10 正在 Ping baidu.com [111.13.101.208] 具備 32 字節的數據: 11 來自 111.13.101.208 的回覆: 字節=32 時間=33ms TTL=55 12 來自 111.13.101.208 的回覆: 字節=32 時間=33ms TTL=55 13 來自 111.13.101.208 的回覆: 字節=32 時間=34ms TTL=55 14 來自 111.13.101.208 的回覆: 字節=32 時間=69ms TTL=55 15 來自 111.13.101.208 的回覆: 字節=32 時間=33ms TTL=55 16 17 111.13.101.208 的 Ping 統計信息: 18 數據包: 已發送 = 5,已接收 = 5,丟失 = 0 (0% 丟失), 19 往返行程的估計時間(以毫秒爲單位): 20 最短 = 33ms,最長 = 69ms,平均 = 40ms
1 import subprocess 2 p1 = subprocess.Popen('ping -n 5 baidu.com', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 3 p1.kill() 4 out,error=p1.communicate() 5 print(p1.pid) 6 print(out) 7 8 輸出:(只能獲取到pid,子進程沒有任何輸出了) 9 9144
1 import subprocess 2 p1 = subprocess.Popen('ping -n 5 baidu.com', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 3 p1.terminate() #終止子進程 4 out,error=p1.communicate() 5 print(p1.pid) 6 print(out) 7 8 輸出:(沒有子進程的任何輸出了) 9 7448
1 >>> import subprocess 2 >>> p1 = subprocess.Popen('ping -c 5 baidu.com', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 3 >>> print(p1.returncode) 4 None 5 >>> out,error=p1.communicate() 6 >>> print(p1.returncode) 7 0 8 >>> p2 = subprocess.Popen('ping1 -c 5 baidu.com', stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, shell=True) 9 >>> out,error=p2.communicate() 10 >>> print(p2.returncode) 11 127 12 >>>
實際應用中,可能還存在處理異步subprocess的需求,到時再深刻學習了。