Python - 調用終端執行命令

這裏主要總結下,在 Python 代碼腳本里,涉及到調用 Shell 腳本、終端命令行、其它 Python 腳本的場景.

1. 方法1 - os.system()

os.system() - 只返回狀態碼,執行結果會輸出到stdout,即輸出到終端. 僅在 Linux 中有效.

用法:

import os

# 不傳遞參數
os.system(cmd) # cmd 即爲Linux 終端命令行指令
               # 返回命令執行的狀態值
               # 輸出數字爲 0,表示正確執行;
               # 輸出數字非 0,表示錯誤執行
            
# 傳遞一個參數
os.system("shell command argus %s" % argus1)

# 傳遞兩個及以上參數
os.system("shell command argus %s %s" % (argus1, argus2)

如:

import os

# 不傳遞參數
os.system("ls")    # 顯示文件夾文件,不包含隱藏文件
os.system("ls -a") # 顯示文件夾所有文件,包含隱藏文件
os.system("pwd")   # 獲取當前目錄
os.system("top")   # 顯示進程情況,退出需要輸入 'q'.

# 傳遞一個參數
os.system("python test.py -i %s" %inputparam)

# 傳遞兩個及以上參數
os.system("python test.py -i %s -b %s" % (inputparam1, inputparam2))

注:os.system(cmd) 不能執行交互式命令,如 ssh root@ip 需要輸入密碼的終端命令.

Python 字符格式化:

%s    字符串 (採用str()的顯示)
%r    字符串 (採用repr()的顯示)
%c    單個字符
%b    二進制整數
%d    十進制整數
%i    十進制整數
%o    八進制整數
%x    十六進制整數
%e    指數(基底寫爲e)
%E    指數(基底寫爲E)
%f    浮點數
%F    浮點數,與上相同
%g    指數(e)或浮點數 (根據顯示長度)
%G    指數(E)或浮點數 (根據顯示長度)
%%    字符"%"

參考:os.system如何傳參

2. 方法二 - os.popen()

os.popen() - 用於從一個命令打開一個管道,返回結果是一個連接管道的文件對象,該文件對象的操作方法同 open(),可以從該文件對象中讀取返回結果. 如果執行成功,不會返回狀態碼,如果執行失敗,則會將錯誤信息輸出到stdout,並返回一個空字符串. 在Unix,Windows中有效.

用法:

import os

os.popen(cmd, mode, bufsize)
# cmd - 使用的命令。
# mode - 模式權限可以是 'r'(默認) 或 'w'.
# bufsize - 指明文件需要的緩衝大小:
#            0-無緩衝;1-行緩衝;
#            其它正值表示使用參數大小的緩衝(大概值,以字節爲單位)
#            負的bufsize意味着使用系統的默認值.
#           一般來說,對於tty設備,它是行緩衝;
#            對於其它文件,它是全緩衝. 如果沒有改參數,使用系統的默認值.
# 返回一個文件描述符號爲 fd 的打開的文件對象.

如:

import os

files = os.popen("ls").readlines() # 文件夾內所有文件的列表.

注: os.popen()在大多數場景都是挺好用,但需要注意:

[1] - 在需要讀取命令執行結果時,避免在命令無法退出或進入交互模式的場景應用 os.popen();

[2] - os.popen()無法滿足需求時,可以考慮subprocess.Popen().

參考:關於os.popen你可能不知道的

3. 方法三 - subprocess 模塊

docs - subprocess

subprocess 模塊是 Python 2.4 版本開始引入的模塊,主要用來取代 一些舊的模塊方法,如os.systemos.spawnos.popencommands.*等.

subprocess 通過子進程來執行外部指令,並通過 input/output/error 管道,獲取子進程的執行的返回信息.

3.1. subprocess.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=(), 
                       *, 
                       encoding=None, 
                       errors=None)

參考: python中的subprocess.Popen()使用

參考: Python多進程(1)——subprocess與Popen()

參數說明:

 

[1] - args 參數: 要執行的命令或可執行文件的路徑. 一個由字符串組成的序列(通常是列表),列表的第一個元素是可執行程序的路徑,剩下的是傳給這個程序的參數,如果沒有要傳給這個程序的參數,args 參數可以僅僅是一個字符串。

[2] - bufsize:控制 stdinstdoutstderr 等參數指定的文件的緩衝,和打開文件的 open() 函數中的參數 bufsize 含義相同.

[3] - executable:如果這個參數不是 None,將替代參數 args 作爲可執行程序;

[4] - stdin:指定子進程的標準輸入;

[5] - stdout:指定子進程的標準輸出;

[6] - stderr:指定子進程的標準錯誤輸出;

對於 stdin, stdout 和 stderr 而言,如果它們是 None(默認情況),那麼子進程使用和父進程相同的標準流文件. 父進程如果想要和子進程通過 communicate() 方法通信,對應的參數必須是 subprocess.PIPE;stdin, stdout 和 stderr 也可以是已經打開的 file 對象,前提是以合理的方式打開,比如 stdin 對應的文件必須要可讀等.

[7] - preexec_fn:默認是None,否則必須是一個函數或者可調用對象,在子進程中首先執行這個函數,然後再去執行爲子進程指定的程序或Shell.

[8] - close_fds:布爾型變量,爲 True 時,在子進程執行前強制關閉所有除 stdin,stdout和stderr外的文件;

[9] - shell:布爾型變量,明確要求使用shell運行程序,與參數 executable 一同指定子進程運行在什麼 Shell 中 —— 如果executable=None 而 shell=True,則使用 /bin/sh 來執行 args 指定的程序;也就是說,Python首先起一個shell,再用這個shell來解釋指定運行的命令.

[10] - cwd:代表路徑的字符串,指定子進程運行的工作目錄,要求這個目錄必須存在;

[11] - env:字典,鍵和值都是爲子進程定義環境變量的字符串;

[12] - universal_newline:布爾型變量,爲 True 時,stdout 和 stderr 以通用換行(universal newline)模式打開,

[13] - startupinfo:見下一個參數;

[14] - creationfalgs:最後這兩個參數是Windows中才有的參數,傳遞給Win32的CreateProcess API調用.

例1:

import subprocess

p = subprocess.Popen('ls -l', shell=True)

p.returncode
p.wait() # 0
p.pid # 子進程的 PID
p.returncode # 子進程的返回狀態.
             #  None —— 子進程尚未結束;
             #  ==0 —— 子進程正常退出;
             #  > 0—— 子進程異常退出,returncode對應於出錯碼;
             #  < 0—— 子進程被信號殺掉了.
p.stdin
p.stdout
p.stderr

例2:

From: Python subprocess.Popen 實時輸出 stdout(正確管道寫法)

import sbuprocess

proc = subprocess.Popen(cmd, 
                        shell=True, 
                        stdout=subprocess.PIPE, 
                        stderr=subprocess.STDOUT)
try:
    while True:
        buff = proc.stdout.readline()
        print(buff)
        if buff == '' and proc.poll() != None:
            break
        else:
            .....
except Exception:
    data["status"] = -1
finally:
    return data

From: python的subprocess模塊

subprocess.Popen() - 在一些複雜場景中,需要將一個進程的執行輸出作爲另一個進程的輸入. 在另一些場景中,需要先進入到某個輸入環境,然後再執行一系列的指令等. 這個時候就需要使用到suprocess.Popen()方法,該方法有以下參數:

[1] - args:shell命令,可以是字符串,或者序列類型,如list,tuple.

[2] - bufsize:緩衝區大小,可不用關心

[3] - stdin, stdout, stderr:分別表示程序的標準輸入,標準輸出及標準錯誤

[4] - shell: 與 subprocess.call() 中相同.

[5] - cwd:用於設置子進程的當前目錄

[6] - env:用於指定子進程的環境變量. 如果env=None,則默認從父進程繼承環境變量.

[7] - universal_newlines:不同系統的的換行符不同,當該參數設定爲true時,則表示使用n作爲換行符.

例如1:

status = subprocess.Popen('mkdir subprocesstest',shell=True,cwd='/root')

例如2:

import subprocess

obj = subprocess.Popen(["python"], 
                       stdin=subprocess.PIPE, 
                       stdout=subprocess.PIPE, 
                       stderr=subprocess.PIPE)
obj.stdin.write('print 1 \n')
obj.stdin.write('print 2 \n')
obj.stdin.write('print 3 \n')
obj.stdin.write('print 4 \n')
obj.stdin.close()

cmd_out = obj.stdout.read()
obj.stdout.close()
cmd_error = obj.stderr.read()
obj.stderr.close()

print cmd_out
print cmd_error

# 或
import subprocess

obj = subprocess.Popen(["python"], 
                       stdin=subprocess.PIPE, 
                       stdout=subprocess.PIPE, 
                       stderr=subprocess.PIPE)
obj.stdin.write('print 1 \n')
obj.stdin.write('print 2 \n')
obj.stdin.write('print 3 \n')
obj.stdin.write('print 4 \n')

out_error_list = obj.communicate()
print out_error_list

例如3:

import subprocess

# 將一個子進程的輸出,作爲另一個子進程的輸入:
child1 = subprocess.Popen(["cat","/etc/passwd"], 
                          stdout=subprocess.PIPE)
child2 = subprocess.Popen(["grep","0:0"],
                          stdin=child1.stdout, 
                          stdout=subprocess.PIPE)
out = child2.communicate()

例如4:

import subprocess

child = subprocess.Popen('sleep 60',
                         shell=True,
                         stdout=subprocess.PIPE)
child.poll()        # 檢查子進程狀態
child.kill()        # 終止子進程
child.send_signal() # 向子進程發送信號
child.terminate()   # 終止子進程

3.2. subprocess.call()

subprocess.call() - 執行命令,並返回執行狀態. 其中shell參數爲False時,命令需要通過列表的方式傳入;當shell爲True時,可直接傳入命令.

例如:

import subprocess

status1 = subprocess.call(['df','-hT'],shell=False)
status2 = subprocess.call('df -hT',    shell=True)
print(status1) # 0
print(status2) # 0

3.3. subprocess.check_call()

subprocess.check_call() - 用法與subprocess.call()類似,區別是,當返回值不爲0時,直接拋出異常.

例如:

import subprocess

status2 = subprocess.check_call('df -hT',    shell=True)
print(status2) # 0

status1 = subprocess.check_call('dfdadas',    shell=True) #出錯,異常.

3.4. subprocess.check_output()

subprocess.check_output() - 用法與subprocess.call()subprocess.check_call()類似,區別是,××如果當返回值爲0時,直接返回輸出結果,如果返回值不爲0,直接拋出異常**.

subprocess.check_output() 僅在python3.x中才有.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章