subprocess模塊

TOC

1、什麼是subprocess模塊

subprocess:
sub: 子
process: 進程python

能夠經過python代碼給操做系統發送命令,並將執行結果返回。shell

2、subprocess語法

import subprocess
while True:
    # 1.讓用戶輸入終端命令
    cmd_str = input('請輸入終端命令:').strip()
    # Popen(cmd命令, shell=True,
    # stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    # 調用Popen就會將用戶的終端命令發送給本地操做系統的終端
    # 獲得一個對象,對象中包含着正確或錯誤的結果。
    obj = subprocess.Popen(
        cmd_str, shell=True,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )

    success = obj.stdout.read().decode('gbk')
    if success:
        print(success, '正確的結果')

    error = obj.stderr.read().decode('gbk')
    if error:
        print(error, '錯誤的結果')

3、官方介紹

subprocess模塊能夠生成新的進程,鏈接到它們的input/output/error管道,同時獲取它們的返回碼。函數

4、基本操做方法

1. subprocess的run、call、check_call、check_output函數

  • subprocess.run(args[, stdout, stderr, shell ...]):執行args命令,返回值爲CompletedProcess類;
    若未指定stdout,則命令執行後的結果輸出到屏幕上,函數返回值CompletedProcess中包含有args和returncode;
    若指定有stdout,則命令執行後的結果輸出到stdout中,函數返回值CompletedProcess中包含有args、returncode和stdout;
    若執行成功,則returncode爲0;若執行失敗,則returncode爲1;
    若想獲取args命令執行後的輸出結果,命令爲:output = subprocess.run(args, stdout=subprocess.PIPE).stdout
  • subprocess.call(args[, stdout, ...]):執行args命令,返回值爲命令執行狀態碼;
    若未指定stdout,則命令執行後的結果輸出到屏幕;
    若指定stdout,則命令執行後的結果輸出到stdout;
    若執行成功,則函數返回值爲0;若執行失敗,則函數返回值爲1;
    (相似os.system)
  • subprocess.check_call(args[, stdout, ...]):執行args命令,返回值爲命令執行狀態碼;
    若未指定stdout,則命令執行後的結果輸出到屏幕;
    若指定stdout,則命令執行後的結果輸出到stdout;
    若執行成功,則函數返回值爲0;若執行失敗,拋出異常;
    (相似subprocess.run(args, check=True))
  • subprocess.check_output(args[, stderr, ...]):執行args命令,返回值爲命令執行的輸出結果;
    若執行成功,則函數返回值爲命令輸出結果;若執行失敗,則拋出異常;
    (相似subprocess.run(args, check=True, stdout=subprocess.PIPE).stdout)

(1) args:啓動進程的參數,默認爲字符串序列(列表或元組),也可爲字符串(設爲字符串時通常需將shell參數賦值爲True);
(2) shell:shell爲True,表示args命令經過shell執行,則可訪問shell的特性;
(3) check:check爲True時,表示執行命令的進程以非0狀態碼退出時會拋出;subprocess.CalledProcessError異常;check爲False時,狀態碼爲非0退出時不會拋出異常;
(4) stdout、stdin、stderr:分別表示程序標準標輸出、輸入、錯誤信息;
run函數返回值爲CompletedProcess類,若需獲取執行結果,可經過獲取返回值的stdout和stderr來捕獲;
check_output函數若需捕獲錯誤信息,可經過stderr=subprocess.STDOUT來獲取;操作系統

# subprocess.run使用
def subprocess_run():
    print("**** subprocess.run ****")
    print("----------")
    result1 = subprocess.run(["adb", "devices"])
    print("result1:", result1)
    print("----------")
    result2 = subprocess.run("adb devices", shell=True, check=True)
    print("result2:", result2)
    print("----------")
    result3 = subprocess.run(["adb", "devices"], stdout=subprocess.PIPE)
    print("result3:", result3)
    print(type(result3))
subprocess_run()
"""結果
**** subprocess.run ****
----------
List of devices attached
338b123f0504 device

result1: CompletedProcess(args=['adb', 'devices'], returncode=0)
----------
List of devices attached
338b123f0504 device

result2: CompletedProcess(args='adb devices', returncode=0)
----------
result3: CompletedProcess(args=['adb', 'devices'], returncode=0, stdout=b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n')
<class 'subprocess.CompletedProcess'>
"""

# subprocess.call使用
def subprocess_call():
    print("**** subprocess.call ****")
    print("----------")
    result1 = subprocess.call(["adb", "devices"])
    print("result1:", result1)
    print("----------")
    result2 = subprocess.call(["adb", "devices"], stdout=subprocess.PIPE)
    print("result2:", result2)
subprocess_call()
"""結果
**** subprocess.call ****
----------
List of devices attached
338b123f0504 device

result1: 0
----------
result2: 0
"""

# subprocess.check_call
def subprocess_check_call():
    print("**** subprocess.check_call ****")
    print("----------")
    result1 = subprocess.check_call(["adb", "devices"])
    print("result1:", result1)
    print("----------")
    result2 = subprocess.check_call(["adb", "devices"], stdout=subprocess.PIPE)
    print("result2:", result2)
subprocess_check_call()
"""結果
**** subprocess.check_call ****
----------
List of devices attached
338b123f0504 device

result1: 0
----------
result2: 0
"""

# subprocess.check_output
def subprocess_check_output():
    print("**** subprocess.check_output ****")
    print("----------")
    result1 = subprocess.check_output(["adb", "devices"])
    print("result1:", result1)
    print("----------")
    result2 = subprocess.run(["adb", "devices"], stdout=subprocess.PIPE).stdout
    print("result2:", result2)
subprocess_check_output()
"""結果
**** subprocess.check_output ****
----------
result1: b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n'
----------
result2: b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n'
"""

2. subprocess的getoutput、getstatusoutput函數

  • subprocess.getoutput(cmd):執行cmd命令,返回值爲命令執行的輸出結果(字符串類型);
    注:執行失敗,不會拋出異常(相似os.popen(cmd).read());
  • subprocess.getstatusoutput(cmd):執行cmd命令,返回值爲元組類型(命令執行狀態, 命令執行的輸出結果);
    元組中命令執行狀態爲0,表示執行成功;命令執行狀態爲1,表示執行失敗;

cmd:參數,字符串類型;code

# subprocess.getoutput或getstatusoutput使用
def subprocess_get_output():
    print("**** subprocess.getoutput ****")
    result1 = subprocess.getoutput("adb devices")
    print("result1:", result1)
    print(type(result1))

    print("**** subprocess.getstatusoutput ****")
    result2 = subprocess.getstatusoutput("adb devices")
    print("result2:", result2)
    print(type(result2))
subprocess_get_output()
"""結果
**** subprocess.getoutput ****
result1: List of devices attached
338b123f0504 device

<class 'str'>
**** subprocess.getstatusoutput ****
result2: (0, 'List of devices attached \n338b123f0504\tdevice\n')
<class 'tuple'>
"""

5、 subprocess.Popen類

1. 介紹

subprocess.Popen類用於在一個新進程中執行一個子程序,上述subprocess函數均是基於subprocess.Popen類;對象

2.操做

  • subprocess.Popen(args[, bufsize, stdin, stdout, stderr, ...]):Popen類的構造函數,返回結果爲subprocess.Popen對象;
  • args:須要執行的系統命令,可爲字符串序列(列表或元組,shell爲默認值False便可,建議爲序列),也可爲字符串(使用字符串時,需將shell賦值爲True);
  • shell:默認爲False,若args爲序列時,shell=False;若args爲字符串時,shell=True,表示經過shell執行命令;
  • stdout、stdin、stderr:分別表示子程序標準輸出、標準輸入、標準錯誤,可爲subprocess.PIPE、一個有效的文件描述符、文件對象或None。
    若爲subprocess.PIPE:表明打開通向標準流的管道,建立一個新的管道;
    若爲None:表示沒有任何重定向,子進程會繼承父進程;
    stderr也可爲subprocess.STDOUT:表示將子程序的標準錯誤輸出重定向到了標準輸出
  • bufsize:指定緩衝策略,0表示不緩衝,1表示行緩衝,其它整數表示緩衝區大小,負數表示使用系統默認值0;
  • cwd:默認值爲None;若非None,則表示將會在執行這個子進程以前改變當前工做目錄;
  • env:用於指定子進程的環境變量。若env爲None,那麼子進程的環境變量將從父進程中繼承;若env非None,則表示子程序的環境變量由env值來設置,它的值必須是一個映射對象。
  • universal_newlines: 不一樣系統的換行符不一樣。若True,則該文件對象的stdin,stdout和stderr將會以文本流方式打開;不然以二進制流方式打開。

(1)subprocess.Popen對象經常使用方法(如PopenObject爲subprocess.Popen對象)

  • PopenObject.poll() :用於檢查命令是否已經執行結束,若結束返回狀態碼;若未結束返回None;
  • PopenObject.wait([timeout, endtime]):等待子進程結束,並返回狀態碼;若超過timeout(s)進程仍未結束,則拋出異常;
  • PopenObject.send_signal(signal):發送信號signal給子進程;
  • PopenObject.terminate():中止子進程;
  • PopenObject.kill():殺死子進程;
  • PopenObject.communicate([input, timeout]):與進程進行交互(如發送數據到stdin、讀取stdout和stderr數據),它會阻塞父進程,直到子進程完成;
    input:表示將發送到子進程的字符串數據,默認爲None;
    timeout:超時判斷,若超過timeout秒後仍未結束則拋出TimeoutExpired異常;
    communicate返回值:一個元組(stdout_data, stderr_data)

(2)subprocess.Popen對象的文本或字節流控制

  • PopenObject.stdin:
    若PopenObject中stdin爲PIPE,則返回一個可寫流對象;若encoding或errors參數被指定或universal_newlines參數爲True,則此流是一個文件流,不然爲字節流。
    若PopenObject中stdin不是PIPE,則屬性爲None。
    stdin輸入流非None,可執行寫操做即PopenObject.stdin.write(s)
  • PopenObject.stdout:
    若PopenObject中stdout爲PIPE,則返回一個可讀流對象;若encoding或errors參數被指定或universal_newlines參數爲True,則此流是一個文件流,不然爲字節流。
    若PopenObject中stdout不是PIPE,則屬性爲None。
    stdout輸出流非None,可執行讀操做即PopenObject.stdout.read()或.readlines()
  • PopenObject.stderr:
    若PopenObject中stderr爲PIPE,則返回一個可讀流對象;若encoding或errors參數被指定或universal_newlines參數爲True,則此流是一個文件流,不然爲字節流。
    若PopenObject中stderr不是PIPE,則屬性爲None。
    stderr錯誤流非None,可執行讀操做即PopenObject.stderr.read()或.readlines()
def subprocess_Popen1():
    print("***經過communicate函數分別輸出PopenObject對象的輸出流和錯誤流***")
    args = [["adb", "devices"], ["adb", "devices11"]]
    for arg in args:
        popen_object = subprocess.Popen(arg, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        object_stdout, object_stderr = popen_object.communicate()
        output = {"popen_object": popen_object,
                  "object_stdout": object_stdout,
                  "object_stderr": object_stderr}
        print(output)
    """
    {'popen_object': <subprocess.Popen object at 0x0000000002212400>, 'object_stdout': b'List of devices attached \r\n106D111805005938\tdevice\r\n\r\n', 'object_stderr': b''}
    {'popen_object': <subprocess.Popen object at 0x0000000002577C18>, 'object_stdout': b'', 'object_stderr': b'Android Debug Bridge version 1.0.31\r\n\r\n -a .....}
    """

    print("***經過stdout和stderr方法輸出PopenObject對象輸出流和錯誤流***")
    p0 = subprocess.Popen(["adb", "devices"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    object_stdout = p0.stdout.read()
    p0.stdout.close()
    object_stderr = p0.stderr.read()
    p0.stderr.close()
    print(object_stdout) # 結果:b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n'
    print(object_stderr) # 結果:b''

    print("***Popen對象stdin寫入功能:使用stdout和stderr輸出")
    args = ["python", "python1"]
    for arg in args:
        p4 = subprocess.Popen([arg], shell=True, stdout=subprocess.PIPE,
                              stdin=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
        p4.stdin.write("print('hello')")
        p4.stdin.close()
        out = p4.stdout.read()
        p4.stdout.close()
        err = p4.stderr.read()
        p4.stderr.close()
        print("out:%s err:%s" % (out, err))
    """
    ***Popen對象stdin寫入功能
    out:hello
    err:
    out: err:'python1' 不是內部或外部命令,也不是可運行的程序或批處理文件。
    """

    print("***Popen對象stdin寫入功能:使用communicate輸出")
    p4 = subprocess.Popen(["python"], stdout=subprocess.PIPE,
                          stdin=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
    p4.stdin.write("print('hello')")
    output = p4.communicate()
    print(output) # 結果:('hello\n', '')

    print("***不含encoding參數***")
    p1 = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE)
    out1 = p1.stdout.readlines()
    print(out1) # 結果: [b'List of devices attached \r\n', b'106D111805005938\tdevice\r\n', b'\r\n']

    print("***含encoding參數***")
    p2 = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE, encoding="utf-8")
    out2 = p2.stdout.readlines()
    print(out2) # 結果: ['List of devices attached \n', '106D111805005938\tdevice\n', '\n']

    print("***Popen對象檢查命令是否結束,等待進程結束")
    print(p2.poll()) # 結果: None
    print(p2.wait()) # 結果: 0
    print(p2.poll()) # 結果: 0

    print("***Popen對象communicate函數,它會阻塞父進程直至子進程完成")
    p3 = subprocess.Popen("adb devices", shell=True, stdout=subprocess.PIPE)
    out = p3.communicate()[0]
    print(out) # 結果:b'List of devices attached \r\n338b123f0504\tdevice\r\n\r\n'
    print(p3.poll()) # 結果:0
subprocess_Popen1()



def subprocess_Popen2():
    """
    1. 經過管道功能,實現adb shell ps | findstr top功能
    2. 直接爲args賦值爲一個字符串,實現adb shell ps | findstr top功能
    :return:
    """
    print("***經過管道方式***")
    p1 = subprocess.Popen(["adb", "shell", "ps"], stdout=subprocess.PIPE)
    p2 = subprocess.Popen(["findstr", "top"], stdin=p1.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, err = p2.communicate()
    print(out, err) # 結果:b'shell 8508 8504 2600 1044 c004e5f8 b6f40938 S top\r\r\n' b''
    print("***經過傳一個字符串方式***")
    p3 = subprocess.Popen("adb shell ps | findstr top", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    out, err = p3.communicate()
    print(out, err) # 結果:b'shell 8508 8504 2600 1044 c004e5f8 b6f40938 S top\r\r\n' b''
subprocess_Popen2()


相關文章
相關標籤/搜索