簡體   English   中英

從文件或 STDIN 讀取

[英]Read from File, or STDIN

我編寫了一個命令行實用程序,它使用 getopt 來解析命令行上給出的 arguments。 我還想讓文件名成為可選參數,例如在 grep、cut 等其他實用程序中。所以,我希望它具有以下用法

tool -d character -f integer [filename]

我該如何實施以下內容?

  • 如果給出了文件名,則從文件中讀取。
  • 如果沒有給出文件名,則從 STDIN 讀取。

fileinput模塊可以做你想做的 - 假設非選項參數在args那么:

import fileinput
for line in fileinput.input(args):
    print line

如果args為空,則fileinput.input()將從標准輸入讀取; 否則它會依次從每個文件中讀取,類似於 Perl 的while(<>)

用最簡單的話來說:

import sys
# parse command line
if file_name_given:
    inf = open(file_name_given)
else:
    inf = sys.stdin

此時,您將使用inf從文件中讀取。 根據是否給定文件名,這將從給定的文件或標准輸入讀取。

當您需要關閉文件時,您可以這樣做:

if inf is not sys.stdin:
    inf.close()

然而,在大多數情況下,如果你完成了關閉sys.stdin是無害的。

我喜歡使用上下文管理器的一般習慣用法,但是當您退出with語句時,(太)瑣碎的解決方案最終會關閉sys.stdin ,我想避免這種情況。

借用這個答案,這是一個解決方法:

import sys
import contextlib

@contextlib.contextmanager
def _smart_open(filename, mode='Ur'):
    if filename == '-':
        if mode is None or mode == '' or 'r' in mode:
            fh = sys.stdin
        else:
            fh = sys.stdout
    else:
        fh = open(filename, mode)
    try:
        yield fh
    finally:
        if filename != '-':
            fh.close()
    
if __name__ == '__main__':
    args = sys.argv[1:]
    if args == []:
        args = ['-']
    for filearg in args:
        with _smart_open(filearg) as handle:
            do_stuff(handle)

我想你可以os.dup()實現類似的東西,但我編寫的代碼變得更加復雜和神奇,而上面的代碼有點笨拙但非常簡單。

我更喜歡使用“-”作為您應該從標准輸入讀取的指示符,它更明確:

import sys
with open(sys.argv[1], 'r') if sys.argv[1] is not "-" else sys.stdin as f:
    pass # do something here

要使用 python 的with語句,可以使用以下代碼:

import sys
with open(sys.argv[1], 'r') if len(sys.argv) > 1 else sys.stdin as f:
    # read data using f
    # ......

不是直接的答案,而是相關的。

通常,當您編寫 python 腳本時,您可以使用argparse包。 如果是這種情況,您可以使用:

parser = argparse.ArgumentParser()
parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)

'?'。 如果可能,將從命令行使用一個參數,並作為單個項目生成。 如果不存在命令行參數,則將生成默認值。

在這里我們將默認設置為sys.stdin

所以如果有一個文件,它將讀取它,如果沒有,它將從標准輸入中獲取輸入“注意:我們在上面的例子中使用了位置參數”

更多訪問: https : //docs.python.org/2/library/argparse.html#nargs

切換到argparse (它也是標准庫的一部分)並使用默認值為 stdin 的argparse.FileType

import  argparse, sys

p = argparse.ArgumentParser()
p.add_argument('input', nargs='?',
  type=argparse.FileType(), default=sys.stdin)
args = p.parse_args()

print(args.input.readlines())

但是,這不會讓您為 stdin 指定編碼和其他參數; 如果你想這樣做,你需要使參數成為非可選的,並讓FileType-作為參數給出時使用 stdin 做它的事情:

p.add_argument('input', type=FileType(encoding='UTF-8'))

請注意,后一種情況將不支持二進制模式 ( 'b' ) I/O。 如果您需要它,您可以使用上面的默認參數技術,但提取二進制 I/O 對象,例如,對於 stdout, default=sys.stdout.buffer 但是,如果用戶指定-無論如何,這仍然會中斷。 (使用- stdin/stdout 始終包裝在TextIOWrapper 。)

如果您希望它與- ,或者在打開文件時需要提供任何其他參數,則可以在包裝錯誤時修復該參數:

p.add_argument('output', type=argparse.FileType('wb'))
args = p.parse_args()
if hasattr(args.output, 'buffer'):
    #   If the argument was '-', FileType('wb') ignores the 'b' when
    #   wrapping stdout. Fix that by grabbing the underlying binary writer.
    args.output = args.output.buffer

(提示medhat提及add_argument()type參數。)

就像是:

if input_from_file:
    f = open(file_name, "rt")
else:
    f = sys.stdin
inL = f.readline()
while inL:
    print inL.rstrip()
    inL = f.readline()

KISS 解決方案是:

if file == "-":
    content = sys.stdin.read()
else:
    with open(file) as f:
        content = f.read()
print(content)   # Or whatever you want to do with the content of the file.

暫無
暫無

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

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