subprocess模塊

  須要經過Python去執行一條系統命令或腳本,系統的shell命令是獨立於你的python進程以外的,每執行一條命令,就是發起一個新進程,經過python調用系統命令或腳本的模塊在python2有os.system。python

  執行返回命令執行狀態,利用echo $?  查看到返回值‘0’
shell

>>> import os
>>> os.system('uname -a')
Darwin MacBook-Pro.local 17.2.0 Darwin Kernel Version 17.2.0: Fri Sep 29 18:27:05 PDT 2017; root:xnu-4570.20.62~3/RELEASE_X86_64 x86_64
0

  python2中除了os.system能夠調用系統命令,commands,popen2等也能夠,比較亂。因而官方在Python3推出了subprocess,目地是提供統一的模塊來實現對系統命令或腳本的調用。spa

1、subprocess.run()方法

  subprocess.run(*popenargs, input=None, timeout=None, check=False, **kwargs)操作系統

  首先注意run方法執行結果,有stdout、args、returncode這三個屬性。
code

>>> import subprocess
>>> a = subprocess.run(['du', '-sh'])
 24K    .
>>> a.stdout   # 拿到標準輸出結果
>>> a.args      # 拿到標準輸出命令
['du', '-sh']
>>> a.returncode    # 拿到標準輸出返回值
0

  標準寫法:subprocess.run(['df', '-h'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True)對象

>>> a = subprocess.run(['ls', '-lrt'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> a.stdout    # 標準輸出
b'total 48\n-rw-r--r--  1 hqs  staff     51  4 12 16:10 __init__.py\n-rw-r--r--  1 hqs  staff  16790  4 17 22:38 ftp_client.py\n'
>>> a.stderr    # 標準錯誤
b''

>>> a = subprocess.run(['df', '-sdfh'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
>>> a.stderr
b'df: illegal option -- s\nusage: df [-b | -H | -h | -k | -m | -g | -P] [-ailn] [-T type] [-t] [filesystem ...]\n'
>>> a.stdout
b''

  運用管道借用操做系統內存,實現Python和shell內存交互。拿到shell命令執行結果。blog

  帶管道符的狀況,不要用列表(解析不了);繼承

  shell=True不作解析直接把整個命令交給shell處理;進程

  check=True有錯誤將直接提示報錯。不加的話不提示報錯,須要用stderr查看錯誤。內存

>>> a = subprocess.run('df -h | grep disk1',stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
>>> a.stdout
b'/dev/disk1s1   233Gi   62Gi  168Gi    28%  871372 9223372036853904435    0%   /
/dev/disk1s4   233Gi  3.0Gi  168Gi     2%       3 9223372036854775804    0%   /private/var/vm\n'

>>> a = subprocess.run(['df','-ususidih'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True)
提示出現CalledProcessError報錯

2、subprocee.CALL方法

  subprocess.call(*popenargs, timeout=None, **kwargs)

  應用列表執行命令主要有call()方法和check_call()方法。

  應用列表執行命令,並返回結果:check_output()方法。

  應用字符串執行命令主要有getstatusoutput()方法和getoutput()方法。

# 執行命令,返回命令執行狀態, 0或非0
>>> retcode = subprocess.call(["ls", "-l"])
total 0
drwx------+  9 huangqiushi  staff   288  3  2 13:32 Desktop
drwx------+  4 huangqiushi  staff   128  3  1 08:17 Documents
...
drwxr-xr-x   7 huangqiushi  staff   224  3  2 20:26 PycharmProjects
>>> retcode
0

# 執行命令,若是命令結果爲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 = subprocess.check_output(['du','-sh'])
>>> res
b' 27G\t.\n'

3、subprocess.Popen()方法

  Popen方法是最基礎的方法,是run()方法和call()方法的底層封裝。

經常使用參數:
    args:shell命令,能夠是字符串或者序列類型(如:list,元組)
    stdin, stdout, stderr:分別表示程序的標準輸入、輸出、錯誤句柄
    preexec_fn:只在Unix平臺下有效,用於指定一個可執行對象(callable object),它將在子進程運行以前被調用
    shell:shell=True的意思是這條命令直接交給系統去執行,不須要python負責解析
    cwd:用於設置子進程的當前目錄
    env:用於指定子進程的環境變量。若是env = None,子進程的環境變量將從父進程中繼承。

  Popen發起一個新進程不影響主程序,run是當前進程執行,Popen是後臺執行。

一、Popen調用後的返回對象

  Popen調用後會返回一個對象,能夠經過這個對象拿到命令執行結果或狀態等,該對象有如下方法:

def sayhi():
    print('run...hahah')
a = subprocess.Popen('echo $PWD;sleep 2',shell=True,cwd="/tmp",stdout=subprocess.PIPE,preexec_fn=sayhi)
a.poll()  # 檢查子程序是否終止,返回返回值
a.wait()  # 等待子程序終止,返回返回值
a.terminate()  # 終止所啓動的進程
a.kill()    # 殺死所啓動的進程
a.communicate()    # 與啓動的進程交互,發送數據到stdin,從stdout接收輸出,而後等待任務結束
a.send_signal(signal.xxx)   # 發送系統信號
a.pid # 拿到所啓動進程的進程號

二、管道操做

>>> def sayhi():
...         print('run...hahah')
>>> a = subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE,preexec_fn=sayhi)
>>> a.stdout  
<_io.BufferedReader name=3>
>>> a.stdout.read() 
b'run...hahah\n'
# cwd設置當前目錄
>>> a = subprocess.Popen('echo $PWD;sleep 2',shell=True,cwd="/tmp",stdout=subprocess.PIPE,preexec_fn=sayhi)
>>> a.stdout.read()
b'run...hahah\n/private/tmp\n' 

三、pid()方法使用

  注意terminate()kill()方法的區別:終止和殺死

>>> a = subprocess.Popen('sleep 100',shell=True,stdout=subprocess.PIPE) 
>>> a.pid
14939
>>> a.terminate()  # 停掉不強制,進程沒有停掉

>>> a = subprocess.Popen('for i in $(seq 1 100);do sleep 1;echo $i >> /tmp/sleep.log;done',shell=True,stdout=subprocess.PIPE)
>>> a.pid
15056
>>> a.kill()   # 強制殺死進程

四、communicate()方法

  與啓動的進程交互,發送數據到stdin,並從stdout接收輸出,而後等待任務結束須要用bytes進行交互、且只能交互一次。

>>> a = subprocess.Popen('python3 guessAge.py',stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE,shell=True)
>>> a.communicate(b'1234')  # 須要和bytes進行交互
(b'guess age: try smaller,you have 3 chance\n
guess age: ', b'Traceback (most recent call last):\n
  File "guessAge.py", line 19, in <module>\n
      guess_age = int(input("guess age: "))\n
      EOFError: EOF when reading a line\n')

五、send_signal()方法發送系統信號

import signal
a = subprocess.Popen('sleep 100',stdout=subprocess.PIPE,shell=True)
a.send_signal(signal.SIGKILL)
相關文章
相關標籤/搜索