2014-07-14 26 views
2

我想編譯一個使用Python的C程序,並且想要使用「<」運算符給出輸入,但它不能按預期工作。 如果我編譯C程序並通過給它輸入一個文件來運行它,例如使用Python子進程調用C編譯器命令

./a.out <inp.txt works 

但同樣,如果我嘗試使用Python腳本來做到這一點,它沒有像預期的那樣工作。 例如:

import subprocess 
subprocess.call(["gcc","a.c","-o","x"]) 
subprocess.call(["./x"]) 

import subprocess 
subprocess.call(["gcc","a.c","-o","x"]) 
subprocess.call(["./x","<inp.txt"]) 

兩個腳本詢問雖然終端輸入。但我認爲在第二個腳本中它應該從文件中讀取。爲什麼這兩個程序都是一樣的?

回答

5

爲了補充@Jonathan Leffler's@alastair's有用的答案:

假設控制你傳遞給shell執行字符串,我認爲沒有錯用外殼以方便使用。 [1]

subprocess.call()具有可選的布爾shell參數,這將導致該命令被傳遞到,使I/O重定向,引用環境變量,...:

subprocess.call("./x <inp.txt", shell = True) 

整個命令行是如何作爲單個而不是參數數組傳遞。


[1]在下列情況下 避免使用的shell:

  • 如果你的Python代碼必須在平臺上運行其他比Unix類的,如Windows
  • 如果性能是最重要的。
  • 如果您發現自己的「外包」任務能夠在Python方面得到更好的處理。

如果你擔心缺乏shell環境的可預測性(如@alastair是):

  • subprocess.callshell = True總是創建的非交互式非登錄實例/bin/sh - 請注意,它不是用戶使用的默認外殼。
  • sh不讀取初始化文件用於非交互式非登錄shell(既不是系統範圍也不是用戶特定的)。
    • 注意,即使在平臺上,其中shbash僞裝,bash當爲sh調用將這樣的行爲。
  • subprocess.call創造了shell = True每一個shell實例是自己的世界,其環境既不是以前的shell實例的影響也不會影響到後來者。
  • 然而,殼實例創建繼承環境蟒蛇過程本身的:
    • 如果從交互shell啓動你的Python程序,然後shell的環境中繼承。請注意,這隻有屬於當前工作目錄環境變量,而不是別名,shell函數和shell變量。
    • 一般情況下,這是一個功能,給出了Python(CPython的)本身的設計是通過環境變量控制的(對於2.x,請參見https://docs.python.org/2/using/cmdline.html#environment-variables;爲3.x中,看到https://docs.python.org/3/using/cmdline.html#environment-variables)。
    • 如果需要,你可以提供自己的環境經由env參數外殼;但是,請注意,如果需要,您將必須提供整個環境,如果需要,可能會包括變量,例如USERHOME;如果需要,可能包括變量,如USERHOME。簡單的例子,定義$PATH明確:
    • subprocess.call('echo $PATH', shell = True, \ env = { 'PATH': '/sbin:/bin:/usr/bin' })
+0

有「沒有錯,使用shell爲了方便」?你會這麼想,但如果例如用戶設置IFS?或者,因爲上面給gcc的調用沒有指定完整路徑,PATH?如果可以避免的話,最好不要使用shell來運行。 – alastair

+0

@alastair:'$ IFS'或'$ PATH'只能從你正在執行的shell命令中改變(臨時);看我的更新如何創建shell實例,並讓我知道如果你仍然擔心修改後的環境(我可能會錯過一些東西)。也就是說,如果您還需要支持Windows(除非您故意只使用足夠簡單的命令以在兩種平臺類型上工作),那麼避免shell的一個有說服力的理由是。 – mklement0

+0

根據'subprocess'文檔,除非明確指定環境,否則它是從Python進程繼承的。如果某人可以操縱* that *過程的環境,它仍可能導致不需要的行爲。 – alastair

4

shell執行進程的I/O重定向。根據你所說的,subprocess模塊不會像那樣做I/O重定向。爲了演示,運行:

subprocess.call(["sh","-c", "./x <inp.txt"]) 

運行shell並重定向I/O。用你的代碼,你的程序./x正在被給出一個它忽略的參數<inp.txt

注意:subprocess.call的替代呼叫純粹用於診斷目的,而不是推薦的解決方案。推薦的解決方案包括閱讀(Python 2)subprocess模塊文檔(或文檔Python 3)以瞭解如何使用模塊進行重定向。

import subprocess 
i_file = open("inp.txt") 
subprocess.call("./x", stdin=i_file) 
i_file.close() 

如果你的腳本是要退出的,所以你不必擔心浪費的文件描述符,你可以壓縮到:

import subprocess 
subprocess.call("./x", stdin=open("inp.txt")) 
2

默認情況下,subprocess模塊未通過參數給shell。爲什麼?因爲通過shell運行命令是危險;除非它們被正確地引用和轉義(這很複雜),否則通常可以說服那些做這種事情的程序運行不需要的和意外的shell命令。

無論如何,使用shell將是錯誤的。如果要從特定文件獲取輸入,可以使用subprocess.Popen,將stdin參數設置爲文件inp.txt的文件描述符(您可以通過調用fileno() Python文件對象來獲取文件描述符)。

相關問題