1. 程式人生 > >12、subprocess模組

12、subprocess模組

我們經常需要通過Python去執行一條系統命令或指令碼,系統的shell命令是獨立於你的python程序之外的,每執行一條命令,就是發起一個新程序,通過python呼叫系統命令或指令碼的模組在python2有os.system,
>>> os.system('uname -a')
Darwin Alexs-MacBook-Pro.local 15.6.0 Darwin Kernel Version 15.6.0: Sun Jun  4 21:43:07 PDT 2017; root:xnu-3248.70.3~1/RELEASE_X86_64 x86_64
0

 

這條命令的實現原理是什麼呢?(視訊中講,解釋程序間通訊的問題...) 除了os.system可以呼叫系統命令,,commands,popen2等也可以,比較亂,於是官方推出了subprocess,目地是提供統一的模組來實現對系統命令或指令碼的呼叫 The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions:
  • os.system
  • os.spawn*
The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly. The run() function was added in Python 3.5; if you need to retain compatibility with older versions, see the Older high-level API section. 三種執行命令的方法
  • subprocess.run(*popenargs, input=None, timeout=None, check=False, **kwargs) #官方推薦
  • subprocess.call(*popenargs, timeout=None, **kwargs) #跟上面實現的內容差不多,另一種寫法
  • subprocess.Popen() #上面各種方法的底層封裝

run()方法

Run command with arguments and return a CompletedProcess instance.The returned instance will have attributes args, returncode, stdout and stderr. By default, stdout and stderr are not captured, and those attributes will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them. If check is True and the exit code was non-zero, it raises a CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute, and output & stderr attributes if those streams were captured. If timeout is given, and the process takes too long, a TimeoutExpired exception will be raised. The other arguments are the same as for the Popen constructor. 標準寫法
subprocess.run(['df','-h'],stderr=subprocess.PIPE,stdout=subprocess.PIPE,check=True)

 

涉及到管道|的命令需要這樣寫
subprocess.run('df -h|grep disk1',shell=True) #shell=True的意思是這條命令直接交給系統去執行,不需要python負責解析

  

call()方法

#執行命令,返回命令執行狀態 , 0 or 非0
>>> retcode = subprocess.call(["ls", "-l"])
 
#執行命令,如果命令結果為0,就正常返回,否則拋異常
>>> subprocess.check_call(["ls", "-l"])
0
 
#接收字串格式命令,返回元組形式,第1個元素是執行狀態,第2個是命令結果
>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')
 
#接收字串格式命令,並返回結果
>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'
 
#執行命令,並返回結果,注意是返回結果,不是列印,下例結果返回給res
>>> res=subprocess.check_output(['ls','-l'])
>>> res
b'total 0\ndrwxr-xr-x 12 alex staff 408 Nov 2 11:05 OldBoyCRM\n'

  

Popen()方法

常用引數:
  • args:shell命令,可以是字串或者序列型別(如:list,元組)
  • stdin, stdout, stderr:分別表示程式的標準輸入、輸出、錯誤控制代碼
  • preexec_fn:只在Unix平臺下有效,用於指定一個可執行物件(callable object),它將在子程序執行之前被呼叫
  • shell:同上
  • cwd:用於設定子程序的當前目錄
  • env:用於指定子程序的環境變數。如果env = None,子程序的環境變數將從父程序中繼承。
下面這2條語句執行會有什麼區別?
a=subprocess.run('sleep 10',shell=True,stdout=subprocess.PIPE)
a=subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)

  

區別是Popen會在發起命令後立刻返回,而不等命令執行結果。這樣的好處是什麼呢? 如果你呼叫的命令或指令碼 需要執行10分鐘,你的主程式不需卡在這裡等10分鐘,可以繼續往下走,幹別的事情,每過一會,通過一個什麼方法來檢測一下命令是否執行完成就好了。 Popen呼叫後會返回一個物件,可以通過這個物件拿到命令執行結果或狀態等,該物件有以下方法 poll() Check if child process has terminated. Returns returncode wait() Wait for child process to terminate. Returns returncode attribute. terminate()終止所啟動的程序Terminate the process with SIGTERM kill() 殺死所啟動的程序 Kill the process with SIGKILL communicate()與啟動的程序互動,傳送資料到stdin,並從stdout接收輸出,然後等待任務結束
>>> a = subprocess.Popen('python3 guess_age.py',stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE,shell=True)
 
>>> a.communicate(b'22')
 
(b'your guess:try bigger\n', b'')

  

send_signal(signal.xxx)傳送系統訊號 pid 拿到所啟動程序的程序號