Python編程之子進程管理(subprocess)詳解
引言
在寫程式時,我們無法避免需要運行外部程式,相較於功能比較簡單的os.system(),更加傾向於使用subprocess模組來執行外部程式。
模組介紹
subprocess.run()
使用subprocess.run()執行命令的時候,父進程會一直等待直到子進程結束後才會繼續運行父進程
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False) """ 參數介紹 1. args: cmd命令 2. stdin: 傳遞參數進來 3. input: 傳遞參數進來,使用input的時候不能使用stdin 4. stdout: 外部程式的輸出,可以指定通過管道(subprocess.PIPE) 5. stderr: 外部程式的報錯輸出, 可以指定通過管道(subprocess.PIPE)或者和stdout使用同一句柄(stderr=subprocess.STDOUT) 6. shell: 是否通過shell執行命令 7. timeout: 如果超時則終止子進程,該參數被傳遞給Popen.communicate() 8. check: 檢查returncode是否為0,如果不為0則引發subprocess.CalledProcessError錯誤, 可以通過try....except...捕獲 """
實例


import subprocess as sp # 三種方式構造命令 sp.run('ls -l', shell=True) sp.run(['ls', '-l'], shell=True) sp.run(' '.join(['ls', '-l']), shell=True) # 判斷是否正確執行命令 sp.run('ls -l', shell=True, check=True) # 獲取命令的輸出 p = sp.run('ls -l', shell=True, check=True, stdout=sp.PIPE, stderr=sp.PIPE) print(p.stdout.read()) # 使用stdin接受數據傳入 p1 = sp.run('ls -l', shell=True, check=True, stdout=sp.PIPE, stderr=sp.PIPE) print(p1.stdout.read()) p2 = sp.run('grep lovefish', shell=True, check=True, stdin=p1.stdout, stdout=sp.PIPE, stderr=sp.PIPE) print(p2.stdout.read())
例子
subprocess.Popen()
subprocess.Popen(args, bufsize=-1, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None,
env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=()) """ 參數介紹 1. args:cmd命令,字元串或者列表 2. bufsize:0:無緩衝; 1:行緩衝,只可以在universal_newlines=True時被使用;其他正值則為緩衝區的大小;負數則為使用系統默認緩衝 3. executable:一般不使用,用來表示shell程式 4. stdin:傳遞數據進來 5. stdout:命令的輸出,可以指定通過管道輸出(subprocess.PIPE) 6. stderr:命令的報錯輸出,可以通過管道(subprocess.PIPE)或者和stdout使用同一句柄輸出(subprocess.STDOUT) 7. preexec_fns: 在exec之前執行 8. close_fds:如果為真,在unix下,則關閉除0,1,2之外的文件。在windows下無法設置close_fds為真和重定向stderr和stdout 9. shell:是否通過shell執行命令 10. cwd:命令執行的工作目錄 11. env:設置環境變數 12. universal_newlines:讓返回數據以文本字元串輸出 函數介紹 1. Popen.poll():檢查子進程是否結束 2. Popen.wait():等待直到子進程結束 3. Popen.communicate():內部數據交互,將數據發送給stdin,返回stdout和stderr 4. Popen.send_signal():發送訊號給子進程 5. Popen.terminate():終止子進程,unix下對應SIGTERM,windows下對應TerminateProcess() 6. Popen.kill():殺死子進程,unix下對應SIGKILL,windows下和terminate()一致 對象介紹 1. Popen.args:命令 2. Popen.stdout:命令的輸出 3. Popen.stderr:命令的報錯輸出 4. Popen.stdin:命令接受的數據 5. Popen.pid:子進程的ID 6. Popen.returncode:返回值 """
實例
import subprocess as sp # 父進程不等待子進程 p = sp.Popen('ls -l', shell=True, stdout=sp.PIPE, stderr=sp.PIPE) # 父進程等待子進程結束之後再繼續運行 p = sp.Popen('ls -l', shell=True, stdout=sp.PIPE, stderr=sp.PIPE) p.wait() # 使用內容管理器 with Popen(["ls -l"], stdout=PIPE) as proc: print(proc.stdout.read())
注意
在使用管道(PIPE)輸出stdout或者stderr時,請注意輸出的數據量不能超過PIPE的上限,否則就會出現PIPE被阻塞,導致程式被阻塞無法繼續運行,可以通過使用Popen.communicate()把stdout和stderr的輸出存到記憶體中來緩解由於PIPE過小導致subprocess.Popen()無法繼續運行程式的問題