繁体   English   中英

如何使用 argparse 在 python 脚本中通过 pipe 发送参数?

[英]How send parameters through a pipe in a python script using argparse?

我必须创建一个可与 Linux 管道一起使用的 python 脚本

我想运行一个脚本,其中可以使用 pipe 或在同一行中发送一些参数

将我的脚本与预期的 output 一起使用的一些示例:

echo "a" > list.txt
echo "b" >> list.txt

./run.py p1 p2   # ['p1', 'p2'] expected output
cat list.txt | ./run.py  # ['a', 'b'] expected output
cat list.txt | ./run.py p1 p2 # ['p1', 'p2', 'a', 'b'] expected output

我试过了:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('args', nargs=argparse.REMAINDER)
args = parser.parse_args().args
print args

它仅适用于同一行中的参数:

./run.py p1 p2  #['p1', 'p2'] OK
cat list.txt | ./run.py  # []  Not OK
cat list.txt | ./run.py p1 p2 # ['p1', 'p2'] expected output

仅使用argparse的解决方案

import argparse
import sys

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

if not sys.stdin.isatty():
    stdin = parser.parse_args().stdin.read().splitlines()
else:
    stdin = []

print(args + stdin)

nargs='?' 使stdin可选, sys.stdin.isatty()检查sys.stdin是否为空

我发现xargs在这种情况下很有用。

我没有尝试过,但也许

cat list.txt | xargs ./run.py p1 p2

适合你吗?

如果您需要特定参数的位置,可以使用xargs占位符选项-J

cat list.txt | xargs -J{} ./run.py p1 {} p2

将“ab”放在“p1”和“p2”之间。

我建议不要为 stdin 添加 arg,因为它只会提升您的 argparse 帮助。 相反,添加一个常规位置参数,然后如果提供了标准输入,只需读取它并分配给该参数。

#!/usr/bin/env python3

import sys
import argparse


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("-f", "--flag", action="store_true", help="set a flag")
    parser.add_argument("PARAMS", nargs="*")
    args = parser.parse_args()
    if not sys.stdin.isatty():
        #print("stdin detected!")
        args.PARAMS.extend(sys.stdin.read().splitlines())
    print(repr(args))


if __name__ == "__main__":
    main()

这个方法给你很好的帮助:

$ ./run.py -h          
usage: run.py [-h] [-f] [PARAMS ...]

positional arguments:
  PARAMS

optional arguments:
  -h, --help  show this help message and exit
  -f, --flag  set a flag

它可以满足您在问题中的要求:

./run.py p1 p2                   # Namespace(flag=False, PARAMS=['p1', 'p2'])
printf '%s\n' a b | ./run.py -f  # Namespace(flag=True, PARAMS=['a', 'b'])
cat list.txt | ./run.py a b      # Namespace(flag=False, PARAMS=['a', 'b', 'x', 'y', 'z'])

所以当我第一次看到这篇文章时,我做了一些类似于mattmc3 的回答。 但是后来我想如果我们不能用自定义操作来做到这一点,下面是结果。 它的代码比其他答案多得多,但更容易包装到一个模块中并在多个地方重用。 由于我使用 super 的方式,这只适用于 Python 3 但如果您仍然需要它,可以轻松修改为在 Python 2 中工作。

#!/usr/bin/env python3

import argparse
import sys

class ExtendFromPipe(argparse._StoreAction):

    def __init__(self, *pargs, **kwargs):
        super().__init__(*pargs, **kwargs)
        # Values from STDIN will extend a list so forcing nargs to '*' will
        # ensure this argument always creates a list.
        self.nargs = '*'

    def __call__(self, parser, namespace, values, option_string=None):
        # Calling super here ensures that there will be a default list
        # After we check to see if the STDIN is coming from a TTY interface
        # if we are being piped information this will be False. We then give
        # a default type conversion if there wasn't one provide and split
        # the input lines from the STDIN and convert them using the type
        # We then get the current value from the name space extend it with
        # the STDIN values and then update the namespace with the new values.
        super().__call__(parser, namespace, values, option_string)
        if not sys.stdin.isatty():
            typecon = self.type if self.type else str
            fromstdin = [typecon(k) for k in sys.stdin.read().splitlines()]
            temp = getattr(namespace, self.dest)
            temp.extend(fromstdin)
            setattr(namespace, self.dest, temp)

if __name__ == "__main__":

    desc = 'Implements Action class that reads from STDIN'
    parser = argparse.ArgumentParser(description=desc)

    parser.add_argument('input', action=ExtendFromPipe)

    cli_args = parser.parse_args()

    print(cli_args.input)

这将完全按照要求返回输出,如果通过并且全部在 argparser 框架的范围内,它甚至会注意类型转换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM