如何在Python中从stdin或文件读取(如果没有数据管道)?

20 投票
6 回答
11141 浏览
提问于 2025-04-15 19:17

我有一个命令行脚本,想让它从一个文件中读取数据。它应该能通过两种方式来读取数据:

  • cat data.txt | ./my_script.py
  • ./my_script.py data.txt

这有点像grep的用法。

我知道的事情:

  • sys.argvoptparse可以让我轻松读取任何参数和选项。
  • sys.stdin可以让我读取通过管道传入的数据。
  • fileinput可以让整个过程自动化。

不幸的是:

  • 使用fileinput时,它会把标准输入和任何参数都当作输入。所以我不能使用那些不是文件名的选项,因为它会尝试打开它们。
  • sys.stdin.readlines()工作得很好,但如果我不输入任何数据,它会一直卡在那里,直到我按下Ctrl + D
  • 我不知道怎么实现“如果标准输入没有数据,就从参数中的文件读取”,因为在布尔上下文中,stdin总是被认为是True

如果可能的话,我希望有一个便携的方式来实现这个功能。

6 个回答

9

在Unix/Linux系统中,你可以通过查看 os.isatty(0) 来判断是否有数据被传入。

$ date | python -c "import os;print os.isatty(0)"
False
$ python -c "import os;print os.isatty(0)"
True

我不太确定在Windows上有没有类似的功能。

补充 好吧,我在Windows XP上用python2.6试了一下。

C:\Python26>echo "hello" | python.exe -c "import os;print os.isatty(0)"  
False

C:\Python26> python.exe -c "import os;print os.isatty(0)"  
True

所以也许在Windows上并不是完全没有希望。

20

Argparse 这个工具可以很简单地处理命令行参数,除非你有兼容性的问题,否则你真的应该用它,而不是 optparse

代码大概是这样的:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--input', type = argparse.FileType('r'), default = '-')

现在你有了一个解析器,它会解析你的命令行参数。如果它发现有文件,就会使用这个文件;如果没有文件,它就会使用标准输入。

12

你可以随意处理那些不是文件名的参数,这样你就能得到一个非选项参数的数组。然后把这个数组作为参数传给 fileinput.input()

import fileinput
for line in fileinput.input(remaining_args):
    process(line)

撰写回答