我写了一个使用 getopt 解析命令行参数的命令行实用程序。我还想让文件名成为可选参数,就像在其他实用程序(如 grep、cut 等)中一样。因此,我希望它具有以下用法:
tool -d character -f integer [filename]
如何实现以下功能?
- 如果给定了文件名,则从文件中读取。
- 如果未指定文件名,则从标准输入中读取。
我写了一个使用 getopt 解析命令行参数的命令行实用程序。我还想让文件名成为可选参数,就像在其他实用程序(如 grep、cut 等)中一样。因此,我希望它具有以下用法:
tool -d character -f integer [filename]
如何实现以下功能?
fileinput 模块可能可以满足您的需求 - 假设非选项参数在 args
中,则:
import fileinput
for line in fileinput.input(args):
print line
如果args
为空,则fileinput.input()
将从标准输入读取;否则,它会类似于Perl的while(<>)
,依次从每个文件中读取。getargs
(就像 OP 一样),那么你可能只想传递剩余的参数而不是 sys.argv[1:]
(这是默认值)。 - SimonJargs
是 一个空序列,那么它将从标准输入读取。如果它是 None
,那么就好像它没有被提供一样;即,fileinput.input
将对命令行进行自己的解析,并将每个标记视为要打开的文件名。 - Karl Knechtel简单来说:
import sys
# parse command line
if file_name_given:
inf = open(file_name_given)
else:
inf = sys.stdin
在这个阶段,你可以使用inf
从文件中读取内容。根据是否指定了文件名,这将从指定的文件或标准输入流(stdin)中读取。
当你需要关闭文件时,你可以执行以下操作:
if inf is not sys.stdin:
inf.close()
但在大多数情况下,如果你已经不需要使用 sys.stdin
,关闭它是无害的。
sys.stdin
中读取。 - Greg Hewgillsys.stdin = open(file_name)
。 - tripleee我更喜欢使用“-”表示应该从标准输入读取,这更加明确:
import sys
with open(sys.argv[1], 'r') if sys.argv[1] != "-" else sys.stdin as f:
pass # do something here
sys.stdin
,因此在 with
语句之后调用 input
函数将引发 ValueError
异常。 - Timofei Bondarevsys.argv[1] != "-"
而不是 sys.argv[1] is not "-"
。 - janto我喜欢使用上下文管理器的通用语言风格,但是(过于)简单的解决方案会在离开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()
来实现类似的效果,但是我编写的代码变得更加复杂和神奇,而上面的方法有点笨重但非常直接。
argparse.FileType
变得太烦人(对我来说经常发生),以下代码也非常有用。 - travc为了使用Python的with
语句,可以使用以下代码:
import sys
with open(sys.argv[1], 'r') if len(sys.argv) > 1 else sys.stdin as f:
# read data using f
# ......
sys.stdin
,因此在with
语句之后调用input
函数将引发ValueError
。 - Timofei Bondarev虽然不是直接的答案,但与问题相关。
通常,在编写Python脚本时,您可以使用argparse
包。如果是这种情况,您可以使用:
parser = argparse.ArgumentParser()
parser.add_argument('infile', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
'?'。如果可能,将从命令行消耗一个参数,并作为单个项目生成。如果没有命令行参数,则将产生默认值。sys.stdin
;因此,如果存在文件,它将读取该文件,否则它将从stdin获取输入“注意:在上面的示例中,我们使用位置参数”使用 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())
-
作为参数时让FileType
处理stdin:p.add_argument('input', type=FileType(encoding='UTF-8'))
'b'
) I/O。如果您只需要这个,可以使用上面的默认参数技术,但要提取二进制 I/O 对象,例如 default=sys.stdout.buffer
用于 stdout。然而,如果用户仍然指定了 -
,这仍然会出错。(对于 -
,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
add_argument()
的type
参数。)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.
sys.stdin.readlines()
或者 f.readlines()
。 - 8c6b5df0d16ade6c类似这样:
if input_from_file:
f = open(file_name, "rt")
else:
f = sys.stdin
inL = f.readline()
while inL:
print inL.rstrip()
inL = f.readline()