如果在Python中没有数据传输,如何从stdin或文件中读取?

时间:2010-02-15 09:42:17

标签: python pipe stdin command-line-interface

我有一个CLI脚本,希望它从文件中读取数据。它应该能够以两种方式阅读:

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

- 有点像grep,例如。

我所知道的:

  • sys.argvoptparse让我轻松阅读任何参数和选项。
  • sys.stdin让我阅读
  • 中的数据
  • fileinput自动完成整个过程

不幸的是:

  • 使用fileinput使用stdin和任何args作为输入。所以我不能使用非文件名的选项,因为它试图打开它们。
  • sys.stdin.readlines()工作正常,但如果我不管道任何数据,它会挂起,直到我输入 Ctrl + D
  • 我不知道如何实现“如果stdin中没有任何内容,则从args中的文件中读取”,因为stdin在布尔上下文中始终是True

如果可能的话,我想要一种可移植的方式来做到这一点。

6 个答案:

答案 0 :(得分:20)

Argparse允许以相当简单的方式完成此操作,除非您遇到兼容性问题,否则您应该使用它而不是optparse

代码会是这样的:

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

现在你有一个解析你的命令行参数的解析器,如果它看到一个文件就使用它,或者如果没有则使用标准输入。

答案 1 :(得分:10)

按照你想要的方式处理你的非文件名参数,所以最后得到一个非选项参数数组,然后将该数组作为参数传递给fileinput.input():

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

答案 2 :(得分: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来说并非毫无希望。

答案 3 :(得分:4)

我是菜鸟,所以这可能不是一个好的答案,但我正在尝试做同样的事情(在命令行上允许一个或多个文件,否则默认为STDIN)。

我把最后的组合放在一起:

parser = argparse.ArgumentParser()
parser.add_argument("infiles", nargs="*")
args = parser.parse_args()

for line in fileinput.input(args.infiles):
    process(line)

这似乎是在一个优雅的包中获得所有所需行为的唯一方法,而不需要命名args。就像使用unix命令一样:

cat file1 file2
wc -l < file1

cat --file file1 --file file2

希望得到资深惯用Pythonistas的反馈/确认,以确保我得到最好的答案。没有看到其他任何地方提到的完整解决方案,只是片段。

答案 4 :(得分:3)

没有可靠的方法来检测sys.stdin是否与任何东西相关联,也不适合这样做(例如,用户想要粘贴数据)。检测文件名的存在作为参数,如果没有找到则使用stdin。

答案 5 :(得分:2)

您可以使用此功能来检测输入是否来自管道。

sys.stdin.isatty()

如果输入来自管道,则返回false,否则返回true。