Python Module_subprocess_子進程(程式調用)__Python

來源:互聯網
上載者:User
目錄

目錄 前言 軟體環境 認識subprocess Popen Constructor建構函式 Class Popen的參數 args 調用程式 調用Shell指令 stdinstdoutstderr 即時擷取子程式輸出 一次擷取子程式的全部輸出 將標準錯誤和標準輸出一起輸出 shell bufsize close_fds 其他參數含義 Popen成員函數 Popenpoll PopenwaittimeoutNone PopencommunicateinputNonetimeoutNone Popensend_signalsignal Popenterminate Popenkill Popen成員屬性 Popenpid Popenreturncode Popenstdin 輸入互動 Popenstdout 連續的輸入輸出互動 Popenstderr subprocess函數 subprocesscall subprocesscheck_call subprocesscheck_output 最後

前言

subpocess用於在父進程中建立子進程,如果你希望在Python程式中調用外部程式,如:Powershell、shell、cmd、bat。subprocess將會是一個非常好的選擇。 軟體環境 系統
Win 10 軟體
Python 3.4.4 IPython 4.0.0 認識subprocess

還是那句話,最高效的方法不過看官方文檔,傳送門:這裡
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.systemos.spawn*os.popen*popen2.* commands.*

subprocess的誕生是為了替代、整合以前幾種舊的建立子進程的方法,能夠實現以管道的形式串連子進程的stdinstdoutstderr,並且子進程會返回一個returncode給父進程。與C語言中的fock實作類別似的功能。
Execute a child program in a new process. On POSIX, the class uses os.execvp() like behavior to execute the child program. On Windows, the class uses the Windows CreateProcess() function
在POSIX類型系統中會使用os.execvp()來執行子程式,而在windows環境中會使用CreateProcess()函數來執行,這篇博文主要記錄在windows環境下的使用。 Popen Constructor(建構函式)

subprocess擁有數個通過不同的方式來建立子進程的函數,但是subprocess只有一個Popen類,同樣是用於建立子進程。使用Class Popen建立的對象擁有Popen的成員屬性和方法。

class 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=())

在Python 3.2之後的版本Popen對象添加了下面這種寫法:
on exit, standard file descriptors are closed, and the process is waited for.

with Popen(["ifconfig"], stdout=PIPE) as proc:    log.write(proc.stdout.read())

下面介紹Popen類的參數含義。 Class Popen的參數 args

args :should be a sequence of program arguments or else a single string.
args參數可以是String類型或者sequence類型,作為子程式的聲明。在Windows中調用的子進程API是CreateProcess([String]),所以可以接受諸如notepad.exe test.txt這樣的字串來執行。但是在Linux的環境下需要接受List類型對象來分隔程式名和參數。如果是序列類型,序列的第一個參數一般也作為子程式的路徑,之後的元素作為傳入子程式的參數。官方建議args參數使用List類型對象調用程式

調用一個Powershell指令碼程式:

args = [r"C:\WINDOWS\system32\WindowsPowerShell\v1.0\powershell.exe","-ExecutionPolicy","Unrestricted",r"E:\Users\oe-fanguiju\Desktop\SendMail.ps1",str(bodyStr)]ps = subprocess.Popen(args,stdout=subprocess.PIPE)

注意:在String前加入r是為了避免出現SyntaxError: (unicode error) 調用Shell指令

序列化傳入參數 shlex.split()
我們還可以使用shlex.split()函數來將我們所需要執行的指令序列化後再賦值給args參數。

>>> import shlex, subprocess>>> command_line = input()/bin/vikings -input eggs.txt -output "spam spam.txt" -cmd "echo '$MONEY'">>> args = shlex.split(command_line)>>> print(args)['/bin/vikings', '-input', 'eggs.txt', '-output', 'spam spam.txt', '-cmd', "echo '$MONEY'"]>>> p = subprocess.Popen(args) # Success!
stdin\stdout\stderr

stdin\stdout\stderr指定了子程式的標準輸入、輸出、錯誤的檔案控制代碼(file handles)。他們可以是PIPE管道、DEVNULL(DEVNULL indicates that the special file os.devnull will be used.)、檔案描述符(existing file descriptor 一個正整數)或已存在的檔案對象(file object)。當他的值是None時,不會發生重新導向,子進程的檔案控制代碼將會繼承父進程。而且stderr=subprocess.STDOUT能夠將標準錯誤的檔案控制代碼設成標準輸出(子程式的標準錯誤匯合到標準輸出)。將stdout/stderr指定為subprocess.PIPE,這樣在Popen被調用的時候會在父進程和子進程之間建立管道,子進程的標準輸出和錯誤輸出都重新導向到管道,可以被父進程擷取。 即時擷取子程式輸出

p = subprocess.Popen("/etc/service/tops-cmos/module/hadoop/test.sh", shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)returncode = p.poll()    while returncode is None:   #檢查子程式是否結束        line = p.stdout.readline()    #若沒有,則擷取子程式的輸出        returncode = p.poll()        line = line.strip()        print lineprint returncode

這樣就可以即時的擷取子進程的輸出。 一次擷取子程式的全部輸出

當你希望在子程式執行完後一次性擷取所有子進程輸出時,子進程對象可以調用communicate(),他會一直阻塞,等待子進程結束後擷取子進程返回的輸出。

ps = subprocess.Popen(args,stdout=subprocess.PIPE)psAllReturn = ps.communicate()#Or: psReturn = ps.stdout.read()return psReturn

只有當子程式執行結束的後才會返回執行結果。
注意:communicate()會在通訊一次之後即關閉了管道。如果希望進程之間頻繁的通訊,並不建議這種方法。
可以嘗試下面的方法:

p= subprocess.Popen(["wc"], stdin=subprocess.PIPE,stdout=subprocess.PIPE,shell=True)  p.stdin.write('your command')   #傳遞資料給子進程p.stdin.flush()                 #清空子進程管道緩衝#......do something   try:      #......do something      p.stdout.readline()         #擷取子進程輸出    #......do something  except:      print('IOError')  #......do something more  p.stdin.write('your other command')  p.stdin.flush()  #......do something more 
將標準錯誤和標準輸出一起輸出
ps = subprocess.Popen(args,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)

這樣無論是標準輸出還是標準錯誤輸出都會經過stdout管道返回給父進程。 shell

The shell argument (which defaults to False) specifies whether to use the shell as the program to execute. If shell is True, it is recommended to pass args as a string rather than as a sequence.
shell指定是否使用shell程式來執行子進程,當shell = True時,子進程將會由shell來執行,並且建議args參數使用String對象。
If args is a string, the string specifies the command to execute through the shell.

In [19]: p = subprocess.Popen("ipconfig /all",stdout = subprocess.PIPE,shell=True)  #args = "ipconfig /all"In [20]: pRet = p.stdout.read()  #父進程獲得執行結果#On Windows with shell=True, the COMSPEC environment variable specifies the default shell.#Win下相當於```args = ["cmd.exe","ipconfig","/all"]

On POSIX with shell=True, the shell defaults to /bin/sh.
Linux下相當於args = ["/bin/sh"," -c",args[0], args[1], ...] bufsize

bufsize will be supplied as the corresponding argument to the open() function when creating the stdin/stdout/stderr pipe file objects.
0 means unbuffered (read and write are one system call and can return short)
1 means line buffered (only usable if universal_newlines=True i.e., in a text mode)
any other positive value means use a buffer of approximately that size
negative bufsize (the default) means the system default of io.DEFAULT_BUFFER_SIZE will be used.
當你將stdin/stdout/stderr重新導向到PIPE或檔案對象時,bufsize能夠傳遞指定緩衝的方式給open()函數,並以此來建立檔案對象:
0 表示無緩衝;
1 表示行緩衝;
otherNumber 表示緩衝區大小,
-1 是bufsize參數的預設值表示使用系統緩衝(全緩衝)
注意:當子進程返回的資料達到緩衝的Size時,子程式會等待付進程讀取快取資料。 close_fds

If close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. (POSIX only). The default varies by platform: Always true on POSIX. On Windows it is true when stdin/stdout/stderr are None, false otherwise. On Windows, if close_fds is true then no handles will be inherited by the child process. Note that on Windows, you cannot set close_fds to true and also redirect the standard handles by setting stdin, stdout or stderr.
在Unix中,如果close_fds = True,除了0、1、2之外的檔案描述符都會被關閉。如果在Windows中stdin/stdout/stderr = None,即繼承父進程時,close_fds = True ,相反為False。在Windows下也不會繼承其他檔案描述符。
注意:在Windows中不能夠在close_fds = True的前提下對stdin, stdout or stderr做重新導向(redirect ),鎖定子進程的stdin/stdout/stderr。

In [24]: p = subprocess.Popen("ipconfig",shell=True,close_fds=True,stdout=subprocess.PIPE)ValueError: close_fds is not supported on Windows platforms if you redirect stdin/stdout/stderr
其他參數含義

given, startupinfo:If given, startupinfo will be a STARTUPINFO object, which is passed to the underlying CreateProcess function. creationflags, if given, can be CREATE_NEW_CONSOLE or CREATE_NEW_PROCESS_GROUP. (Windows only)
在Windows中,調用CreateProcess()函數建立子進程時,startupinfo參數會傳遞STARTUPINFO對象,來設定子進程的外觀等等屬性。

executable:指定要執行的程式名,很少使用,一般用args參數來指定需要執行的子程式。可以指定執行子進程的shell(e.g. bash、csh、zsh)。Unix下,預設是/bin/sh。Windows下,就是環境變數%COMSPEC%的值。windows下,只有當你要執行的命令確實是shell內建命令(比如dir ,copy)時,你才需要指定shell=True
,而當你要執行一個基於命令列的批處理指令碼的時候,不需要指定此項。

C:\Users\Username>echo %COMSPEC%C:\WINDOWS\system32\cmd.exe

preexec_fn:If preexec_fn is set to a callable object, this object will be called in the child process just before the child is executed. (POSIX only)
鉤子函數,只在Unix平台下有效,用於指定一個可執行對象(callable object),它將在子進程運行之前被調用。容易造成死結,慎用。

cmd:指定了子進程的工作目錄
注意:並不會把該目錄做為可執行檔的搜尋目錄,所以不要把子程式檔案所在目錄設定為cwd 。

env:是一個字典類型,用於執行子進程的執行環節變數,而不使用預設繼承父進程的環境變數

universal_newlines:為True時,子進程的stdout和stderr被視為文字物件,不管是Unix的行結束符’/n’,還是Mac格式的行結束符’/r’,還是Windows格式的行結束符’/r/n’都將被視為 ‘/n’處理 。

pass_fds:is an optional sequence of file descriptors to keep open between the parent and child. Providing any pass_fds forces close_fds to be True. (POSIX only)

restore_signals:If restore_signals is true (the default) all signals that Python has set to SIG_IGN are restored to SIG_DFL in the child process before the exec. Currently this includes the SIGPIPE, SIGXFZ and SIGXFSZ signals. (POSIX only)

start_new_session:If start_new_session is true the setsid() system call will be made in the child process prior to the execution of the subprocess. (POSIX only) Popen成員函數 Popen.poll()

Check if child process has terminated. Set and return returncode attribute.
用於檢查子進程是否已經結束。設定並返回returncode屬性 Popen.wait(timeout=None)

Wait for child process to terminate. Set and return returncode attribute.
等待子進程結束。設定並返回returncode屬性。使用Popen類建立的子進程時,父進程預設不會等待子進程結束,需要Call wait()函數來實現等待子進程結束後父進程繼續執行。
timeout:If the process does not terminate after timeout seconds, raise a TimeoutExpired exception. It is safe to catch this exception and retry the wait.
注意: 如果子進程輸出了大量資料到stdout或者stderr的管道,並達到了系統PIPE的緩衝大小時,子進程會等待父進程讀取管道內的資料,若此時父進程正在wait()的話,將不會讀取管道內的資料,從而造成死結,建議使用Pepon.communicate()來避免這種情況。 Popen.communicate(input=None,timeout=None)

與子進程進行互動。向stdin發送資料,選擇性參數input指定發送到子進程的資料。
Communicate()時從stdout和stderr中讀取資料,直到文本末尾的EOF(進程之間採用文本通訊),等待子進程結束。返回一個元組:(stdout_data, stderr_data),The data will be bytes or, if universal_newlines was True, strings.如果universal_newlines = True則返回一個String。
注意:如果希望通過stdin向子進程發送資料,需要通過stdin=PIPE建立管道對象。同樣,如果希望從stdout和stderr擷取資料,必須將stdout和stderr設定為PIPE。

p=subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)(stdout_data, stderr_data) = p.communicate()

Note:If the process does not terminate after timeout seconds, a TimeoutExpired exception will be raised. Catching this exception and retrying communication will not lose any output.
如果timeout還沒有結束進程的話,需要捕捉觸發的TimeoutExpired異常,並且使用Popen.communicate()來保留子程式的輸出。

proc = subprocess.Popen(...)try:    outs, errs = proc.communicate(timeout=15)except TimeoutExpired:    proc.kill()    outs, errs = proc.communicate()
Popen.send_signal(signal)

向子進程發送訊號。 Popen.terminate()

停止子進程。在windows平台下,該方法將調用Windows API TerminateProcess()來結束子進程。 Popen.kill()

殺死子進程,在Windows上調用了TerminateProcess() API。在Unix上相當於發送了訊號SIGTERM和SIGKILL。 Popen成員屬性 Popen.pid

擷取子進程的進程ID。 Popen.returncode

擷取進程的傳回值。如果進程還沒有結束,返回None。 Popen.stdin

If the stdin argument was PIPE, this attribute is a writeable stream object as returned by open() 輸入互動

#test.pyimport sys  line = sys.stdin.readline()  print 'test',line  #run.py  from subprocess import *  p = Popen('./test.py',stdin=PIPE,stdout=PIPE)  p.stdin.write('say hi/n')  print p.stdout.readline()  
Popen.stdout

If the stdout argument was PIPE, this attribute is a readable stream object as returned by open(). 連續的輸入輸出互動

# test.pyimport sys  while True:      line = sys.stdin.readline()      if not line:break      sys.stdout.write(line)      sys.stdout.flush()  # run.pyimport sys  from subprocess import *  proc = Popen('./test.py',stdin=PIPE,stdout=PIPE,shell=True)  for line in sys.stdin:      proc.stdin.write(line)  #子進程的輸入    proc.stdin.flush()          output = proc.stdout.readline()    #子進程的輸出      sys.stdout.write(output)           #父進程的列印

注意: run.py的flush和test.py中的flush,要記得清空緩衝區,否則程式得不到正確的輸入和輸出 Popen.stderr

If the stderr argument was PIPE, this attribute is a readable stream object as returned by open(). subprocess函數

subprocess函數本質上是對subprocess.Popen的封裝,能夠簡便的建立子進程。當需要建立更加複雜的子進程時,建議使用Popen類,該類會產生子進程對象,且擁有多樣化的成員方法和屬性。 subprocess.call()

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

父進程等待子進程完成
返回退出資訊(returncode,相當於Linux exit code)

In [20]: subprocess.call("ipconfig")..Out[20]: 0
subprocess.check_call()
 subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

父進程等待子進程完成
返回0
檢查退出資訊,如果returncode不為0,則舉出錯誤subprocess.CalledProcessError,該對象包含有returncode屬性,可用try…except…來檢查

In [25]: subprocess.check_call("config",shell=True)CalledProcessError: Command 'config' returned non-zero exit status 1

call()和check_call()的區別:兩者的區別在於遇到錯誤的時候處理不一樣,call()返回returncode ,check_call()再返回returncode後還會拋出異常。check_call實際上會調用call函數,然後加入了異常處理的情況。兩者在本質上都會調用Popen().wait()來等待進程結束並返回returncode subprocess.check_output()

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)

父進程等待子進程完成
返回子進程向標準輸出的輸出結果
檢查退出資訊,如果returncode不為0,則舉出錯誤subprocess.CalledProcessError,該對象包含有returncode屬性和output屬性,output屬性為標準輸出的輸出結果,可用try…except…來檢查。 最後

在使用subprocess模組的時候很容易卡死的情況出現,一些避免卡死的思路,我們之後再聊。 : -)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.