### 1.os.system() os.system() 是對 C 語言中 system() 系統函數的封裝,允許執行一條命令,並返回退出碼(exit code),命令輸出的內容會直接列印到屏幕上,無法直接獲取。 示例: ```python # test.py import os os.syste ...
1.os.system()
os.system() 是對 C 語言中 system() 系統函數的封裝,允許執行一條命令,並返回退出碼(exit code),命令輸出的內容會直接列印到屏幕上,無法直接獲取。
示例:
# test.py
import os
os.system("ls -l | grep test") # 允許管道符
# 測試執行
$ ll <======== 列出當前目錄中的內容
drwxr-xr-x 2 foo foo 4096 Feb 13 09:09 __pycache__
-rw-r--r-- 1 foo foo 359 Feb 19 09:21 test.py
$ python test.py
-rw-r--r-- 1 foo foo 359 Feb 19 09:21 test.py <======== 只有名字包含 test 的文件被列出
2.subprocess.run()
Python 3.5 開始推薦使用這個方法執行命令,其原型如下:
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
)
其中:
-
args: 可以是一個字元串(當 shell=True 時),也可以是一個列表(當 shell=False 時)
-
stdin, stdout, stderr: 用於指定標準IO文件句柄,可以是:
subprocess.PIPE: 用作 stdout, stderr 參數的值時,可以從返回值對象中的 stdout 和 stderr 屬性中讀取輸出內容 subprocess.STDOUT: 用作 stderr 參數的值時,相當於把標準錯誤重定向到標準輸入中) subprocess.DEVNULL: 用作 stdout, stderr 參數的值時,相當於把輸出內容重定向到 /dev/null 用戶已經打開的文件對象或描述符(整型數字)
-
capture_output: 當設置為 True 時,相當於 stdout 和 stderr 參數都設置為 True 了,可以通過返回值對象訪問標準輸出和標準錯誤內容
-
shell: 當設置為 True 時,args 參數會當做一條命令字元串(支持管道、重定向操作);當它為 False 時,args 需是一個列表(並且不支持管道、重定向操作)
-
cwd: 指定執行命令的目錄,預設為當前目錄
-
timeout: 指定命令執行超時時間(按妙計),若執行超時了,會 kill 掉命令並拋出 TimeoutExpired 異常
-
check: 當設置為 True 時,會自動檢測執行退出碼,若不為0,則拋出 CalledProcessError 異常
-
text: 當設置為 True 時,stdin、stdout、stderr 會以“文本”模式打開(返回值對象中的 stdout、stderr 存儲文本內容),否則返回值對象中 stdout、stderr 存儲的是位元組序列
-
env: 用於設置程式執行時繼承的環境變數等,預設與當前進程相同
該方法返回一個 CompletedProcess 對象,其中包含以下屬性:
- returncode: 執行命令的退出碼
- stdout: 捕獲的標準輸出內容(當 stdout 參數為 PIPE 時)。其格式預設為位元組序列,除非 text 參數為 True (此時為文本格式)。
- stderr: 捕獲的標準錯誤內容(當 stderr 參數為 PIPE 時)。其格式預設為位元組序列,除非 text 參數為 True (此時為文本格式)。
- args: 同參數 args 。
示例:
import subprocess
subprocess.run(["ls", "-l"]) # 預設時,args 參數需是一個列表
subprocess.run("ls -l", shell=True) # 當 shell 為 True 時,args 是一個字元串
ret = subprocess.run("ls -l", shell=True, capture_output=True, text=True) # 以文本模式捕獲輸出內容
print("Return code:", ret.returncode) # Return code: 0
print("STDOUT:", ret.stdout) # STDOUT: ...當前目錄內容...
print("STDERR:", ret.stderr) # STDERR: <空>
ret = subprocess.run("abcdefg", shell=True, text=True, # 註意:這裡必須 shell=True 才能捕獲到 /bin/sh 的輸出錯誤
# 當 shell=False 時,是要去捕獲 "abcdefg" 命令自身輸出的內容,但是它不存在,python 會報錯
stdout=subprocess.PIPE, stderr=subprocess.STDOUT # 標準錯誤重定向到標準輸出
)
print("STDOUT:", ret.stdout) # STDOUT: /bin/sh: abcdefg: command not found
另一個用於測試 shell 參數區別的示例如下:
import sys, re, subprocess
if len(sys.argv) == 1: # parent process
cmd = ["python", sys.argv[0], "--run-child"]
ret = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
print(ret) # CompletedProcess(args=['python', 'test.py', '--run-child'], returncode=0, stdout='stdout output\n', stderr='stderr output')
assert re.match("stdout output", ret.stdout)
assert re.match("stderr output", ret.stderr) # 如果 cmd 中的命令不存在,這裡是捕獲不到的,subprocess.run()自己就會報錯
ret = subprocess.run(" ".join(cmd), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
print(ret) # CompletedProcess(args='python test.py --run-child', returncode=0, stdout='stdout output\n', stderr='stderr output')
assert re.match("stdout output", ret.stdout)
assert re.match("stderr output", ret.stderr) # 如果 cmd 中的命令不存在,這裡也是可以捕獲到的,內容可能是 xxx command not found
print("Passed!")
else: # child process
print("stdout output")
sys.stderr.write("stderr output")
3.subprocess.call()
Python 3.5 以前(包括 2.x 版本)沒有 subprocess.run() 方法,可以使用 subprocess.call() 來執行命令,該方法原型如下:
subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None)
註意:這個方法的返回值是命令的退出碼,而不是一個對象,所以無法像 subprocess.run() 一樣捕獲命令輸出內容(不要設置 stdout=PIPE 或 stderr=PIPE,否則可能造成命令卡死)。
該方法的其它參數與 subprocess.run() 類似。
4.subprocess.check_output()
Python 3.5 以前的版本,要想捕獲命令輸出內容,可以使用 subprocess.check_output() 方法,它的原型如下:
subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, cwd=None, encoding=None, errors=None, universal_newlines=None, timeout=None, text=None)
註意:參數中沒有 stdout ,因為這個函數的返回值預設就是標準輸出內容,也可以將設置 stderr=subprocess.STDOUT 將標準錯誤重定向到標準輸出,但是好像沒有辦法單獨捕獲標準錯誤內容呢!
示例:
import sys, re, subprocess
#Python小白學習交流群:711312441
if len(sys.argv) == 1: # parent process
cmd = ["python", sys.argv[0], "--run-child"]
ret = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
print("[" + ret + "]") # 輸出內容中包含標準輸出和標準錯誤,輸出順序在 windows 下和 linux 下可能會有差異
assert re.search("stdout output", ret)
assert re.search("stderr output", ret)
print("Passed!")
else: # child process
print("stdout output")
sys.stderr.write("stderr output")