day5-subprocess模塊


一、概述

實際應用中,有些時候我們不得不跟操作系統進行指令級別的交互,如Linux中的shell。Python中早期通過os模塊和commands模塊來實現操作系統級別的交互,但從2.4版本開始,官方建議使用subprocess模塊。因此對於os和commands模塊只會簡單講解,重點會放在subprocess模塊和Popen類上。

對於指令的執行,我們一般關注以下兩點:

  1. 命令執行的狀態碼--表示命令執行是否成功
  2. 命令執行的輸出結果--命令執行成功后的輸出

二、os與commands模塊

Python中提供了以下幾個函數來幫助我們完成命令行指令的執行:

image

說明:

  1. os.popen(command)函數得到的是一個文件對象,因此除了read()方法外還支持write()等方法,具體要根據command來定;
  2. commands模塊只存在於Python 2.7中,且不支持windows平台,因此commands模塊很少被使用。另外,commands模塊實際上也是通過對os.popen()的封裝來完成的。

以上內容轉載自http://www.cnblogs.com/yyds/p/7288916.html,下面是簡單的程序示例:

  • os.system()
      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   #命令執行狀態
    上述程序表明,os.system一次性返回命令執行結果和執行狀態返回碼,如果用變量存儲,則需要單獨獲取狀態碼。
  • os.popen()
    創建一個文件對象,需要通過read()方法獲取,並且只會返回命令執行結果,沒有狀態碼
      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
  • commands.getstatusoutput()
      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')
    需要注意的是commands模塊僅支持linux平台,且在python 3.5版本后不再支持

三、subprocess模塊的常用函數

subprocess模塊是關鍵建議使用的模塊,顧名思義是建立一個子進程,用來運行與系統交互的指令。Subporcess模塊常用的函數有以下幾類:
image

說明:

  1. 在Python 3.5之后的版本中,官方文檔中提倡通過subprocess.run()函數替代其他函數來使用subproccess模塊的功能;
  2. 在Python 3.5之前的版本中,我們可以通過subprocess.call(),subprocess.getoutput()等上面列出的其他函數來使用subprocess模塊的功能;
  3. subprocess.run()、subprocess.call()、subprocess.check_call()和subprocess.check_output()都是通過對subprocess.Popen的封裝來實現的高級函數,因此如果我們需要更復雜功能時,可以通過subprocess.Popen來完成。
  4. subprocess.getoutput()和subprocess.getstatusoutput()函數是來自Python 2.x的commands模塊的兩個遺留函數。它們隱式的調用系統shell,並且不保證其他函數所具有的安全性和異常處理的一致性。另外,它們從Python 3.3.4開始才支持Windows平台。


上述內容轉載自http://www.cnblogs.com/yyds/p/7288916.html

下面詳解講解函數的具體用法。

3.1 subprocess.run()

語法: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,程序會直接報錯沒有該文件或目錄。

3.2 subprocess.call()

語法: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   #命令執行狀態返回碼

3.3 subprocess.check_call()

語法: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.
注意:細心的同學可能會發現程序執行后返回的不只是狀態碼,還有傳遞的指令執行的結果,注意命令執行執行的結果是subprocess創建的子進程執行命令后返回的輸出,上述幾個函數都是這樣。何以見得?
  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

3.4 subprocess.check_output()

語法: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參數,實際測試也只是輸出了狀態碼,並沒有給出具體的錯誤原因信息,待后續驗證。

3.5 subprocess.getoutput()

語法: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'

3.6 subprocess.getstatusoutput()

語法: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 >>>

四、subprocess.Popen()

該類用於在一個新的進程中執行一個子程序。前面我們提到過,上面介紹的這些函數都是基於subprocess.Popen類實現的,通過使用這些被封裝后的高級函數可以很方便的完成一些常見的需求。由於subprocess模塊底層的進程創建和管理是由Popen類來處理的,因此,當我們無法通過上面那些高級函數來實現一些不太常見的功能時就可以通過subprocess.Popen類提供的靈活的api來完成。

  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()函數,用於設置子進程的一些屬性,如主窗口的外觀,進程優先級等

4.1 Popen類的常用方法

Open類的常用方法大概可分為兩類,一類是與子進程進行交互的方法,如stdin,stdout,stderr,communicate,kill,terminate,send_signal,另外一類是獲取子進程的狀態信息,如pid,poll,下面逐一展開它們的用法:

  1. stdin
    stdin實現向子進程的輸入。
      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 
    注意上述示例程序中的universal_newlines=True參數,不使用該參數輸入時會提示輸入的對象必須是二進制類型的,使用后才能直接輸入文本流。
    communicate在下文單獨講述。
  2. stdout
    stdout捕獲子進程的輸出
      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 ...
    注意:在windows平台下運行類似程序時,由於很多命令都是cmd.exe支持的,因此需要加上shell=True參數,否則會提示找不到文件。
  3. stderr
    stderr用於捕獲子進程的錯誤輸出,前提是程序本身沒有語法錯誤,能正常進入到子程序執行環節
      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 或批處理文件。
  4. commucate()與死鎖問題
    誠然,上面講述的講述的stdin,stdout,stderr也能完成與子進程的一些必要交互(輸入,捕獲輸出好,捕獲錯誤),他們都通過PIPE管道來進行處理,大致流程如下:
    image
    由於PIPE本質上是問文本流提供一個緩沖區,其容量是有限的,因此比較安全的做法是及時清理管道的內容,以避免可能的死鎖問題。

    死鎖問題:
    如果你使用了管道,而又不去處理管道的輸出,那么小心點,如果子進程輸出數據過多,死鎖就會發生了,比如下面的用法:
    p=subprocess.Popen("longprint", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p.wait()
    longprint是一個假想的有大量輸出的進程,那么在我的xp, Python2.5的環境下,當輸出達到4096時,死鎖就發生了。當然,如果我們用p.stdout.readline或者p.communicate去清理輸出,那么無論輸出多少,死鎖都是不會發生的。或者我們不使用管道,比如不做重定向,或者重定向到文件,也都是可以避免死鎖的。
    官方文檔里推薦使用 Popen.communicate()。這個方法會把輸出放在內存,而不是管道里,所以這時候上限就和內存大小有關了,一般不會有問題。而且如果要獲得程序返回值,可以在調用 Popen.communicate() 之后取 Popen.returncode 的值。

    p.communicate()會立即阻塞父進程,直到子進程執行完畢,在不超過內存情況下還能避免wait()阻塞父進程可能帶來的死鎖問題,因此一般情況下推薦使用(子進程輸出不超過內存大小)。
    它本身附帶input和timeout參數,它的輸出是一個包含標准輸出和錯誤輸出的元組(stdout,stderr),我們一般使用out,err=p.communicate()來分別處理stdout和stderr。
      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

    如果子進程輸出過多,還是要考慮通過文件來接收輸出,方法是把stdout指向一個open好的具備寫權限的文件對象(還記得stdin,stdout,stderr就是相應的句柄嗎)即可:
      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
    這方面的示例還比較粗淺,實際場景的用法,還有待后續實踐深入。
  5. poll()
    定時檢查子進程是否已結束,結束則返回0,反之返回None
      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 #子進程已結束
  6. wait()
    阻塞父進程,等待子進程結束,並返回子進程執行狀態碼
      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
    從上述程序可看出,返回的子進程狀態碼,非0代表執行失敗。
  7. pid()
    返回父進程的pid,即發起Popen的進程,注意並非發起的子進程
      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
    這里需要注意的是,子進程的命令執行完畢,父進程不會自己結束,感興趣的同學可以持續觀察ps -ef的輸出
  8. kill()
    殺死子進程,注意發起Popen的父進程不受影響。對比測試:
    正常執行子進程的命令:
      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
    調用kill()方法后:
      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
  9. terminate()
    終止子進程 p ,等於向子進程發送 SIGTERM 信號。
      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
  10. send_signal()
    向子進程發送信號,Linux下有用。以后用到再說把。
  11. returncode
    返回子進程的執行狀態碼,相當於Linux下的$?,便於判斷子進程命令是否執行成功。0表示子進程命令執行ok,非0表示執行有誤。
      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的需求,到時再深入學習了。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM