在寫程式時,我們無法避免需要執行外部程式,相較於功能比較簡單的os.system(),更加傾向於使用subprocess模組來執行外部程式。
使用subprocess.run()執行命令的時候,父程序會一直等待直到子程序結束後才會繼續執行父程序
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False,
encoding=None, errors=None, text=None, env=None, universal_newlines=None, **other_popen_kwargs) """ 引數介紹 1. args: cmd命令 2. stdin: 傳遞引數進來 3. input: 傳遞引數進來,使用input的時候不能使用stdin 4. stdout: 外部程式的輸出,可以指定通過管道(subprocess.PIPE) 5. stderr: 外部程式的報錯輸出, 可以指定通過管道(subprocess.PIPE)或者和stdout使用同一控制程式碼(stderr=subprocess.STDOUT) 6. capture_output: 同時獲取stdout和stderr 7. shell: 是否通過shell執行命令 8. cwd: 命令執行的工作目錄 9. timeout: 如果超時則終止子程序,該引數被傳遞給Popen.communicate() 10. check: 檢查returncode是否為0,如果不為0則引發subprocess.CalledProcessError錯誤, 可以通過try....except...捕獲 11. encoding: 編碼型別 12. errors: 13. text: 可用來代替universal_newlines 14. env: 設定環境變數 15. universal_newlines: 返回資料以文字字串輸出,否則為二進位制輸出 """
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(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=None, startupinfo=None,
creationflags=0, restore_signals=True, start_new_session=False, pass_fds=(), *,
group=None, extra_groups=None, user=None, umask=- 1, encoding=None, errors=None, text=None, pipesize=- 1) """ 引數介紹 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:讓返回資料以文字字串輸出 13. pipesize:設定sp.PIPE的大小 函數介紹 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()無法繼續執行程式的問題
本文來自部落格園,作者:LoveFishO,轉載請註明原文連結:https://www.cnblogs.com/lovefisho/p/16787619.html