簡體   English   中英

Python subprocess 模塊,我如何為管道命令系列中的第一個提供輸入?

[英]Python subprocess module, how do I give input to the first of series of piped commands?

我正在嘗試使用 Python 的 subprocess 模塊。 我需要的是將輸入發送到第一個進程,其輸出成為第二個進程的輸入。 這種情況與此處文檔中給出的示例基本相同:http: //docs.python.org/library/subprocess.html#replacing-shell-pipeline除了我需要提供輸入第一個命令。 這是復制的示例:

p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
output = p2.communicate()[0]

如果我們將第一行更改為:

p1 = Popen(["cat"], stdout=PIPE, stdin=PIPE)

如何向進程提供輸入字符串? 如果我通過將最后一行更改為:

output = p2.communicate(input=inputstring)[0]

這行不通。

我確實有一個工作版本,它只是將第一個命令的輸出存儲在一個字符串中,然后將其傳遞給第二個命令。 這並不可怕,因為基本上沒有可以利用的並發性(在我的實際用例中,第一個命令將很快退出並在最后產生所有輸出)。 這是完整的工作版本:

import subprocess

simple = """Writing some text
with some lines in which the
word line occurs but others
where it does
not
"""

def run ():
  catcommand = [ "cat" ]
  catprocess = subprocess.Popen(catcommand,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
  (catout, caterr) = catprocess.communicate(input=simple)
  grepcommand = [ "grep", "line" ]
  grepprocess = subprocess.Popen(grepcommand,
                                stdin=subprocess.PIPE,
                                stdout=subprocess.PIPE,
                                stderr=subprocess.PIPE)
  (grepout, greperr) = grepprocess.communicate(input=catout)
  print "--- output ----"
  print grepout 
  print "--- error ----"
  print greperr 

if __name__ == "__main__":
  run()

我希望我已經足夠清楚了,感謝您的幫助。

如果你這樣做

from subprocess import Popen, PIPE
p1 = Popen(["cat"], stdout=PIPE, stdin=PIPE)

您應該執行p1.communicate("Your Input to the p1") ,這將流經 PIPE。 標准輸入是進程的輸入,您應該只與它通信。

給出的程序絕對沒問題,似乎沒有問題。

我假設catgrep只是示例命令,否則您可以使用沒有子進程的純 Python 解決方案,例如:

for line in simple.splitlines():
    if "line" in line:
       print(line)

或者,如果您想使用grep

from subprocess import Popen, PIPE

output = Popen(['grep', 'line'], stdin=PIPE, stdout=PIPE).communicate(simple)[0]
print output,

您可以將第一個命令的輸出傳遞給第二個命令,而無需先將其存儲在字符串中:

from subprocess import Popen, PIPE
from threading import Thread

# start commands in parallel
first = Popen(first_command, stdin=PIPE, stdout=PIPE)
second = Popen(second_command, stdin=first.stdout, stdout=PIPE)
first.stdout.close() # notify `first` if `second` exits 
first.stdout = None # avoid I/O on it in `.communicate()`

# feed input to the first command
Thread(target=first.communicate, args=[simple]).start() # avoid blocking

# get output from the second command at the same time
output = second.communicate()[0]
print output,

如果您不想將所有輸入/輸出存儲在內存中; 您可能需要線程(在塊中讀取/寫入而不會阻塞)或選擇循環(適用於 POSIX)。

如果有多個命令,則按照@Troels Folke的建議直接使用 shell 或使用諸如plumbum之類的庫來隱藏手動模擬 shell 的所有血腥細節可能更具可讀性。

嗯,為什么不混合一點(ba)sh? :-)

from subprocess import Popen, PIPE
cproc = Popen('cat | grep line', stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True)
out, err = cproc.communicate("this line has the word line in it")

但請注意:

  • 這僅適用於使用 Bourne Shell 兼容 shell 的系統(如大多數 *nix'es)

  • Usign shell=True 並將用戶輸入放在命令字符串中是一個壞主意,除非您先轉義用戶輸入。 閱讀 subprocess docs -> "Frequently Used Arguments" 了解詳細信息。

  • 這是丑陋的,不可移植的,非pythonic等等......

編輯:如果您只想使用cat ,則無需使用grep 只需將輸入直接提供給 grep,或者更好的是,使用 python 正則表達式。

我遇到了類似的問題,我想要幾個管道Popen 這對我有用:

from subprocess import Popen, PIPE

p1 = Popen(["cat"], stdin=PIPE, stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdin.write(inputstring)
p1.stdin.close()
output = p2.communicate()[0]

但是,帶有線程的@jfs解決方案似乎更健壯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM