很多時(shí)候python應(yīng)用需要執(zhí)行一些外部命令來(lái)獲取操作系統(tǒng)的支持。但是python執(zhí)行外部命令的庫(kù)有很多并不知道選擇哪個(gè)會(huì)更好,這時(shí)候小編就要來(lái)推薦subprocess模塊了。這是一個(gè)python自帶的模塊。眾所周知python自帶模塊或許不是最好的,但絕對(duì)是比較好用的。接下來(lái)這篇文章我們就來(lái)看看subprocess的使用詳解吧。
一、了解subprocess
- subeprocess模塊是python自帶的模塊,無(wú)需安裝,主要用來(lái)取代一些就的模塊或方法,如os.system、os.spawn*、os.popen、commands.*等。
- 因此執(zhí)行外部命令優(yōu)先使用subprocess模塊
1、subprocess.run()方法
subprocess.run()方法是官方推薦的方法,幾乎所有的工作都可以用它來(lái)完成。
如下是函數(shù)源碼:
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, ced=None, timeout=None, check=False, enccoding=None, error=None)
該函數(shù)返回一個(gè)CompletedProcess類(lèi)(有屬性傳入?yún)?shù)及返回值)的實(shí)例,該函數(shù)的參數(shù)有很多,只需要記住常用的即可
1、args : 代表需要在操作系統(tǒng)中執(zhí)行的命令,可以是字符串形式(要求shell=True),也可以是list列表類(lèi)型
2、* :代表可變參數(shù),一般是列表或者字典類(lèi)型
3、stdin、stdout、stderr :指定了可執(zhí)行程序的標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出、標(biāo)準(zhǔn)錯(cuò)誤文件句柄
4、shell :代表著程序是否需要在shell上執(zhí)行,當(dāng)想使用shell的特性時(shí),設(shè)置shell=True,這樣就可以使用shell指令的管道、文件名稱(chēng)通配符、環(huán)境變量等,不過(guò)python也提供了很多類(lèi)似shell的模塊,如glob、fnmatch、os.walk()、os.path.expandvars()、os.path.expanduser()和shutil。
5、check :如果check設(shè)置為T(mén)rue,就檢查命令的返回值,當(dāng)返回值為0時(shí),將拋出AclledProcessError的異常
6、timeout :設(shè)置超時(shí)時(shí)間,如果超時(shí)則kill掉子進(jìn)程
1.使用字符串方式執(zhí)行shell命令
[root@localhost python]# vim 1.py #!/bin/env python3 import subprocess b=subprocess.run("ls -l /ltp | head -2", shell=True) # 執(zhí)行run方法,并將返回值賦值給b # total 184980 # -rw-r--r--. 1 root root 10865 May 8 16:21 123.txt print(b) # 執(zhí)行該run函數(shù)后返回的CompletedProcess類(lèi) # CompletedProcess(args='ls -l /ltp | head -2', returncode=0) print(b.args) # 打印出CompletedProcess類(lèi)的agrs屬性值,就是執(zhí)行的shell命令 # ls -l /ltp | head -2 print(b.returncode) # 打印命令執(zhí)行的狀態(tài)碼 # 0
結(jié)果展示
[root@localhost python]# ./1.py
total 184980
-rw-r--r--. 1 root root 10865 May 8 16:21 123.txtCompletedProcess(args='ls -l /ltp | head -2', returncode=0)2
ls -l /ltp | head -2
0
2.使用列表方式執(zhí)行
個(gè)人感覺(jué)方法二不好用,尤其是想要使用管道符號(hào)時(shí),很難用
#!/bin/env python3 import subprocess b = subprocess.run(["ls", "-l", "/ltp"]) print(b) print(b.args) print(b.returncode)
執(zhí)行結(jié)果
[root@localhost python]# ./2.py
total 10865
-rw-r--r--. 1 root root 10865 May 8 16:21 123.txt
CompletedProcess(args=['ls', '-l', '/ltp'], returncode=0)
['ls', '-l', '/ltp']
0
3.捕獲腳本輸出
- 如果需要采集命令執(zhí)行的結(jié)果,可以傳入?yún)?shù)stdout=subprocess.PIPE
[root@localhost python]# cat 3.py #!/bin/env python3 import subprocess # 傳入stdout=subprocess.PIPE參數(shù)即可 b=subprocess.run("ls -l /ltp | head -2", shell=True, stdout=subprocess.PIPE) print(b.stdout)
結(jié)果顯示
[root@localhost python]# ./1.py
b'total 184980 -rw-r--r--. 1 root root 10865 May 8 16:21 123.txt '
4.檢測(cè)異常
示例1:模擬renturncode值不為0
傳入?yún)?shù)check=True,當(dāng)返回值不為0時(shí),就會(huì)拋出異常
[root@localhost python]# cat 1.py #!/bin/env python3 import subprocess b=subprocess.run("ls -l /123 | head -2 && exit 1", shell=True, stdout=subprocess.PIPE, check=True) print(b.returncode)
執(zhí)行結(jié)果:返回了CalledProcessError 類(lèi)型報(bào)錯(cuò)
[root@localhost python]# ./1.py ls: cannot access /123: No such file or directory Traceback (most recent call last): File "./1.py", line 3, in <module> b=subprocess.run("ls -l /123 | head -2 && exit 1", shell=True, stdout=subprocess.PIPE, check=True) File "/usr/local/python3/lib/python3.7/subprocess.py", line 487, in run output=stdout, stderr=stderr) subprocess.CalledProcessError: Command 'ls -l /123 | head -2 && exit 1' returned non-zero exit status 1. # 返回了 CalledProcessError 類(lèi)型報(bào)錯(cuò)
示例2:模擬執(zhí)行超時(shí)
返回 TimeoutExpired 異常
[root@localhost python]# vim 1.py #!/bin/env python3 import subprocess b=subprocess.run("while 2>1;do sleep 1;done",timeout=3, shell=True, stdout=subprocess.PIPE, check=True) print(b.returncode)
顯示結(jié)果
[root@localhost python]# ./1.py
Traceback (most recent call last):
File "/usr/local/python3/lib/python3.7/subprocess.py", line 474, in run
stdout, stderr = process.communicate(input, timeout=timeout)
File "/usr/local/python3/lib/python3.7/subprocess.py", line 939, in communicate
stdout, stderr = self._communicate(input, endtime, timeout)
File "/usr/local/python3/lib/python3.7/subprocess.py", line 1682, in _communicate
self._check_timeout(endtime, orig_timeout)
File "/usr/local/python3/lib/python3.7/subprocess.py", line 982, in _check_timeout
raise TimeoutExpired(self.args, orig_timeout)
subprocess.TimeoutExpired: Command 'while 2>1;do sleep 1;done' timed out after 3 secondsDuring handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "./1.py", line 3, in <module>
b=subprocess.run("while 2>1;do sleep 1;done",timeout=3, shell=True, stdout=subprocess.PIPE, check=True)
File "/usr/local/python3/lib/python3.7/subprocess.py", line 479, in run
stderr=stderr)
subprocess.TimeoutExpired: Command 'while 2>1;do sleep 1;done' timed out after 3 seconds
2、Popen類(lèi)
1.初步認(rèn)識(shí)Popen類(lèi)
首先來(lái)看一下Popen類(lèi)的構(gòu)造函數(shù)
class Popen( args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0 ):
參數(shù) 字符串或列表bufsize0 : 無(wú)緩沖
參數(shù) | 字符串或列表 |
---|---|
bufsize | 0 : 無(wú)緩沖
1 : 行緩沖 其他正數(shù)值 :緩沖區(qū)大小 負(fù)數(shù)值 :采用默認(rèn)的系統(tǒng)緩沖(一般是全緩沖) |
executable | 一般不用,args 字符串或列表 的第一項(xiàng)表示程序名 |
stdin
stdout stderr |
None : 沒(méi)有任何重定向 繼承父進(jìn)程
PIPE : 創(chuàng)建管道 文件對(duì)象 文件描述符(整數(shù)) stderr也可以設(shè)置為stdout |
preexec_fn | 鉤子函數(shù),在fork和exec之間執(zhí)行 |
close_fds | unix 下執(zhí)行新進(jìn)程前是否關(guān)閉0/1/2之外的文件
windows 下不繼承還是繼承父進(jìn)程的文件描述 |
shell | 若為T(mén)rue的話 :
在unix 下相當(dāng)于在args前面添加了 “/bin/bash” “-c" 在windows下,相當(dāng)于添加了"cmd.exe /c” |
cwd | 設(shè)置工作目錄 |
env | 設(shè)置環(huán)境變量 |
unviersal_newlines | 各種換行符統(tǒng)一處理成" " |
startupinfo | windows下傳遞給CreateProcess的結(jié)構(gòu)體 |
creationflags | windows下,傳遞CREATE_NEW_CONSOLE創(chuàng)建自己的控制臺(tái)窗口 |
2.Popen的使用方法
1、subprocess.Popen([“cat”, “abc.txt”])
2、subprocess.Popen(“cat abc.txt”, shell=True)
上面的第二種其實(shí)就相當(dāng)于:subprocess.Popen(["/bin/bash", “-c”, “cat abc.txt”])
示例:
[root@localhost python]# cat 3.py #!/bin/env python3 import subprocess obj = subprocess.Popen("ls -l /ltp", shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) error_info = obj.stderr.read() out_info = obj.stdout.read() result = out_info + error_info print(result) [root@localhost python]# ./3.py total 184980 -rw-r--r--. 1 root root 10865 May 8 16:21 123.txt -rw-r--r--. 1 root root 802 Apr 21 09:42 ab.sh drwxr-xr-x. 3 root root 101 Apr 1 18:34 auth -rw-r--r--. 1 root root 5242880 Mar 18 13:20 bigfile -rwxrwxrwx. 1 root root 1392 Feb 5 09:24 dingding.sh
Popen類(lèi)的對(duì)象方法
名稱(chēng) | 功能 |
---|---|
poll() | 檢查是否結(jié)束,設(shè)置返回值 |
wait() | 等待結(jié)束,設(shè)置返回值 |
communicate() | 參數(shù)是標(biāo)準(zhǔn)輸入,返回標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)出錯(cuò) |
send_signal() | 發(fā)動(dòng)信號(hào)(主要指linux下有用) |
terminate() | 終止進(jìn)程,unix對(duì)應(yīng)的SIGTERM信號(hào),windows下調(diào)用api函數(shù)TerminateProcess() |
kill() | 殺死進(jìn)程(unix對(duì)應(yīng)SIGKILL信號(hào)),windows下同上 |
stdin
stdout stderr |
參數(shù)中指定PIPE時(shí)有用 |
pid | 進(jìn)程id |
returncode | 進(jìn)程返回值 |
補(bǔ)充:其他方法
1、subeprocess.call(*args,**kwargs): call()方法調(diào)用Popen()執(zhí)行程序,并且等待它執(zhí)行完成
2、subpeocess.check_call(*args, **kwargs): 調(diào)用上面的call(),如果返回值非零,返回異常
3、subprocess.check_output(*args, **kwargs) : 調(diào)用Popen()執(zhí)行程序,并返回標(biāo)準(zhǔn)輸出
二、補(bǔ)充os模塊執(zhí)行外部命令
1、os.system()方法
示例:
[root@localhost python]# cat 4.py #!/bin/env python3 import os # 變量ret接收命令執(zhí)行后的返回值 ret = os.system('ls -l /ltp |head -2') print(" 執(zhí)行成功" if ret == 0 else " 執(zhí)行失敗")
執(zhí)行結(jié)果
[root@localhost python]# ./4.py
total 184980
-rw-r--r--. 1 root root 10865 May 8 16:21 123.txt
執(zhí)行成功
2、os.popen()用法
與subprocess.Popen()類(lèi)似,就不寫(xiě)了
補(bǔ)充:subprocess.run()和subprocess.Popen()的執(zhí)行結(jié)果是寫(xiě)入到緩存的,可以執(zhí)行結(jié)束后打印結(jié)果,不會(huì)實(shí)時(shí)在終端輸出;而os.system()是實(shí)時(shí)輸出到終端界面的;
以上就是Python執(zhí)行外部命令的詳細(xì)內(nèi)容,更多Python學(xué)習(xí)資料請(qǐng)關(guān)注W3Cschool其它相關(guān)文章!