天天看點

subprocess子程序建立過程詳解引子shell内建指令和外部指令subprocess在Linux下執行指令subprocess在Windows下執行指令參考

文章目錄

  • 引子
  • shell内建指令和外部指令
  • subprocess在Linux下執行指令
  • subprocess在Windows下執行指令
  • 參考

引子

有一個需求:代碼運作環境為python 3.7,用python擷取系統所有别名資訊。

首先想到的,就是使用subprocess子產品建立子程序,執行alias指令并擷取傳回值。于是出現了這樣一段代碼:

subprocess子程式建立過程詳解引子shell内建指令和外部指令subprocess在Linux下執行指令subprocess在Windows下執行指令參考

毫不猶豫敲下Enter鍵執行,結果呈現的是:

subprocess子程式建立過程詳解引子shell内建指令和外部指令subprocess在Linux下執行指令subprocess在Windows下執行指令參考

這是什麼情況?為什麼會報FileNotFoundError?問題出在哪兒?

shell内建指令和外部指令

先介紹一個概念,linux的内建指令和外部指令。

内建指令實際上是shell程式的一部分,其中包含的是一些比較簡單的linux系統指令,這些指令寫在bash源碼裡面,由shell程式識别并在shell程式内部完成運作,通常在linux系統加載運作時shell就被加載并駐留在系統記憶體中。

外部指令是linux系統中的實用程式部分,通常外部指令的實體并不包含在shell中,而是存放在檔案中。是以,在系統加載時并不随系統一起被加載到記憶體中,隻有在需要時才将其調用記憶體,由shell通過環境變量PATH,管理其執行的路徑查找、加載存放,并控制其執行。

在上述例子中,調用shutil子產品确認alias指令的存放位置,傳回結果為空。

subprocess子程式建立過程詳解引子shell内建指令和外部指令subprocess在Linux下執行指令subprocess在Windows下執行指令參考

在shell中使用type指令檢視,确認alias為内建指令。

subprocess子程式建立過程詳解引子shell内建指令和外部指令subprocess在Linux下執行指令subprocess在Windows下執行指令參考

subprocess在Linux下執行指令

檢視官方文檔,subprocess提供的所有進階方法(run、call……等等)都基于popen方法實作。文檔中也有提到,對于Linux系統,subprocess.popen基于POSIX,使用_posixsubprocess.fork_exec建立子程序,這個子程序會繼承父程序中環境變量PATH的值,并據此搜尋、加載并運作對應的可執行檔案。

結論:subprocess在linux下執行指令的本質,是執行一個可執行檔案。

alias是内建指令,不存在可執行檔案,是以在使用subprocess.run執行時抛出FileNotFoundError異常。

那有沒有什麼辦法解決呢?有!在subprocess.run等方法中,提供了shell參數。該參數預設值為False,當需要運作shell内建指令時,設定shell=True即可。其實作原理是,根據系統不同(這裡主要指Android和linux),在執行指令前面,添加對應shell執行字元串,生成新的執行指令清單,建立子程序執行。這也可以解釋為什麼,在官方文檔中指出,當shell=True時,傳入的指令可以為一個字元串,而非清單。

subprocess子程式建立過程詳解引子shell内建指令和外部指令subprocess在Linux下執行指令subprocess在Windows下執行指令參考

subprocess在Windows下執行指令

剛才說的是subprocess在Linux下執行指令的過程,我們知道subprocess包是一個跨平台實作的包,那在Windows系統中又如何呢?

在Windows中,我們發現其建立子程序是通過調用WinApi中CreateProcess()實作的。調用時未指定lpApplicationName參數,通過環境變量PATH找到并執行lpCommandLine參數對應的可執行檔案。

結論:subprocess在Windows下執行外指令的本質,也是運作可執行檔案。

是以,我們無法使用subprocess直接執行DOS指令。同樣,我們可以指定shell=True執行DOS指令。其實作原理是:利用COMSPEC啟動一個cmd,并将控制窗體顯示的wShowWindow參數值設定為SW_HIDE(即視窗隐藏),再将cmd的啟動指令和執行指令拼接,生成新的執行指令清單,建立子程序執行。

subprocess子程式建立過程詳解引子shell内建指令和外部指令subprocess在Linux下執行指令subprocess在Windows下執行指令參考

參考

[1] https://docs.python.org/3.7/library/subprocess.html#popen-objects

[2] https://blog.csdn.net/caimouse/article/details/1690008

[3] https://blog.csdn.net/baidu_29198395/article/details/82926348