Python:除非指定了文件,否则从STDIN读取,如何完成?

时间:2019-03-03 17:16:56

标签: python-3.x stdin argparse

我正在编写一个Python脚本,该脚本需要一个正则表达式模式和一个文件名,并在文件中查找该正则表达式模式。

默认情况下,脚本需要一个文件来处理。

我想更改脚本,因此默认情况下,除非指定了文件(-f文件名),否则它将采用来自STDIN的输入。

我的代码如下:

#!/usr/bin/env python3
# This Python script searches for lines matching regular expression -r (--regex) in file/s -f (--files).

import re
import argparse
#import sys

class colored:
   CYAN = '\033[96m'
   UNDERLINE = '\033[4m'
   END = '\033[0m'

def main(regex, file, underline, color):
    pattern = re.compile(regex)
    try:
        for i, line in enumerate(open(file, encoding="ascii")):
            for match in re.finditer(pattern, line):
                message = "Pattern {} was found on file: {} in line {}. The line is: ".format(regex, file, i+1)
                if args.color and args.underline:
                    #message = "Pattern {} was found on file: {} in line {}. The line is: ".format(regex, file, i+1)
                    l = len(line)
                    print(message + colored.CYAN + line + colored.END, end="")
                    print("                                                                " ,"^" * l)
                    break
                if args.underline:
                    l = len(line)
                    print(message + line, end="")
                    print("                                                                " ,"^" * l)
                    break
                if args.color:
                    print(message + colored.CYAN + line + colored.END, end="")
                    break
                if args.machine:
                    print("{}:{}:{}".format(file, i+1, line), end="")
                    break
                else:
                    print(message + line, end="")
                    break

    except FileNotFoundError:
        print("File not found, please supply")
        pass

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Python regex finder', epilog = './python_parser.py --regex [pattern] --files [file]')
    requiredNamed = parser.add_argument_group('required named arguments')
    requiredNamed.add_argument('-r', '--regex',
                        help='regex pattern', required=True)
    parser.add_argument('-f', '--file',
                        help='file to search pattern inside')
    parser.add_argument('-u', '--underline', action='store_true',
                        help='underline')
    parser.add_argument('-c', '--color', action='store_true',
                        help='color')
    parser.add_argument('-m', '--machine', action='store_true',
                        help='machine')
    args = parser.parse_args()

    main(args.regex, args.file, args.underline, args.color)

您可以看到跑步here的样子。

我尝试使用答案from this SO question,但收到以下错误:

for i, line in enumerate(open(file, encoding="ascii")):
TypeError: expected str, bytes or os.PathLike object, not _io.TextIOWrapper

编辑#1

这是文件:

Itai
# something
uuu
UuU
# Itai
# this is a test
this is a test without comment
sjhsg763
3989746
# ddd ksjdj #kkl

不提供文件时出现上述错误。

编辑#2

当我将文件参数更改为该参数时:

parser.add_argument('-f', '--file',
                        help='file to search pattern inside',
                        default=sys.stdin,
                        type=argparse.FileType('r'),
                        nargs='?'
                        )

然后像这样运行脚本:

~ echo Itai | ./python_parser.py -r "[a-z]" -m
Traceback (most recent call last):
  File "./python_parser.py", line 59, in <module>
    main(args.regex, args.file, args.underline, args.color)
  File "./python_parser.py", line 16, in main
    for i, line in enumerate(open(file, encoding="ascii")):
TypeError: expected str, bytes or os.PathLike object, not NoneType
➜  ~

args.file = tmpfile

这是脚本运行所在目录中的文件。

我在做什么错了?

1 个答案:

答案 0 :(得分:2)

您是这样写的:

def main(regex, file, underline, color):
...
        for i, line in enumerate(open(file, encoding="ascii")):

对于file是文件名还是打开的文件描述符,您有些困惑。您希望它是一个打开的文件描述符,因此您可以传入sys.stdin。这意味着main()不应尝试open(),而应依靠调用者传递已经打开的文件描述符。

将调用open()推到main()的责任将使您默认分配file = sys.stdin,然后重新分配open()的结果,如果发现已指定文件名。