簡體   English   中英

Bash管道到python

[英]Bash pipe to python

我需要通過管道實時吸收bash命令的輸出。 例如

for i in $(seq 1 4); do echo $i; sleep 1; done | ./script.py

script.py有這個

for line in sys.stdin.readlines():
        print line

我希望序列在可用時打印,但python腳本在繼續之前等待bash腳本結束。

我看了這個相關的答案,但這並沒有解決我的問題。 我如何在python中實現這一目標?

第一個問題是readlines將所有行讀入列表。 在所有行都存在之前不能這樣做,直到stdin達到EOF才會這樣做。

但是你實際上並不需要一個行列表 ,只需要一些可迭代的行。 sys.stdin這樣的文件已經一個可迭代的文件。 它是一個懶惰的,一旦它們可用就一次生成一行,而不是等待一次生成它們。

所以:

for line in sys.stdin:
    print line

當你發現自己伸手readlines ,問問自己是否真的需要它。 答案永遠是否定的。 (好吧,除非你想用一個參數調用它,或者在一些有缺陷的不完全文件的對象上調用它。)參見Readlines Considered Silly for more。


但同時,還有第二個問題。 不是Python正在緩沖它的stdin ,或者其他進程正在緩沖它的stdout ,而是文件對象迭代器本身正在進行內部緩沖,這可能(取決於你的平台 - 但在大多數POSIX平台上,它通常會)防止你到EOF之前到達第一行,或者至少直到讀過很多行。

這是一個已知的問題與Python 2.x中,它已被固定在3.x中,*但這並不能幫助你,除非你願意升級。

該解決方案在命令行和環境文檔中以及大多數系統的聯機幫助頁中提到,但隱藏在-u標志文檔的中間:

請注意,xreadlines(),readlines()和file-object迭代器(“for sys.stdin中的行”)中存在內部緩沖,不受此選項的影響。 要解決此問題,您需要在“while 1:”循環中使用“sys.stdin.readline()”。

換一種說法:

while True:
    line = sys.stdin.readline()
    if not line:
        break
    print line

要么:

for line in iter(sys.stdin.readline, ''):
    print line

對於另一個問題,在這個答案中 ,Alex Martelli指出你總是可以忽略sys.stdin並重新fdopen文件描述符。 這意味着你得到一個POSIX fd而不是C stdio句柄的包裝器。 但這對於這個問題既不必要也不充分,因為問題不在於C stdio緩沖,而是file.__iter__緩沖與它交互的方式。


* Python 3.x不再使用C stdio庫的緩沖了; 它在io模塊中的類型中完成所有操作,這意味着迭代器只能共享文件對象本身使用的相同緩沖區。 雖然io在2.x上也可用,但它不是你為stdio文件句柄open -or的默認設置,這就是為什么它在這里沒有幫助。

使用Python 2.7.9(可能是3.x之前的所有Python),這可以達到您的期望:

#!/usr/bin/python

import sys

while True:
   line=sys.stdin.readline()
   if not line:
      break
   print line   

你也可以這樣做:

#!/usr/bin/python

import sys

for line in iter(sys.stdin.readline, ''):
   print line 

在Python 3.4.3上,您可以執行abarnert建議的操作:

#!/usr/local/bin/python3

import sys

for line in sys.stdin:
    print(line)

您也可以使用Python 3使用的io類重新打開sys.stdin:

#!/usr/bin/python

import sys, io

for line in io.open(sys.stdin.fileno()):
    print(line)

第一,第二和最后一個方法都適用於OS X上的Python 2.7.6和2.7.9以及Python 3.4.3; 第三種方法,僅適用於Python 3。

當前最受歡迎的答案實際上並沒有回答這個問題,因為它不會在輸出時打印輸出。 類似下面的代碼應該做你想要的:

import sys

def readline():
    while True:
        res = sys.stdin.readline()
        if not res:
            break
        yield res

for line in readline():
    print line

在這里,我們不是等待readlines構建列表,而是讀取一行然后產生值。 我們只是繼續消耗輸入和屈服,直到流的末尾由sys.stdin.readline()的空返回發出信號。

暫無
暫無

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

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