Python Argparse将无法识别参数

Python Argparse将无法识别参数,python,argparse,Python,Argparse,此脚本将打印环境变量。 使用Python3.9。 目标是能够在需要时运行任何子命令。我得到的错误是,如果添加了任何其他短标志,“ignore-environment”参数将尝试对其进行解析。我不要这个。附加的短标志用于在--eval之后分配的任何内容 parser.py import argparse, os def parseargs(p): p.usage = '%(prog)s [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]

此脚本将打印环境变量。

使用Python3.9。 目标是能够在需要时运行任何子命令。我得到的错误是,如果添加了任何其他短标志,“ignore-environment”参数将尝试对其进行解析。我不要这个。附加的短标志用于在
--eval
之后分配的任何内容

parser.py

import argparse, os 

def parseargs(p):
    p.usage = '%(prog)s [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]'
    p.add_argument(
        "-i",
        "--ignore-environment",
        action="store_const",
        const=dict(),
        dest="env",
        help="start with an empty environment",
        default=os.environ,
    )
    p.add_argument(
        "--export",
        nargs=1,
        help="Set argument with --export NAME=VALUE"
    )
    p.add_argument(
        "--eval",
        nargs="+",
        help="Run any commands with newly updated environment, " 
            "--eval COMMAND ARGS"
    )
return p
执行如下

>>> p = argparse.ArgumentParser()
>>> parseargs(p) # assigns arguments to parser
>>> p.parse_args('--export FOO=bar --eval cat test.py'.split()) # This is ok and works correctly. cat is the bash command
Namespace([os.environs..], eval=['cat', 'test.py'], export=['FOO=bar']) 
>>>p.parse_args('--export FOO=bar --eval ls -l'.split()) # This is fails
error: unrecognized arguments: -l

如何让“-l”被“-I/ignore environment”忽略,但传递给eval,就像使用
cat test.py
。我尝试过使用sub_解析器,但没有用。同样的结果也会出现。

问题在于,
parse_args
在考虑任何实际选项的语义之前,尝试从词汇上识别可能的选项

因为一个选择变量的数目几乎必须是最后使用的选项,请考虑使用<代码> -EVA/CODE>一个标志,它用来告诉程序如何解释剩余的正负参数。然后,

ls
-l
可以被
--
抵消,防止
解析参数
思考
-l
是一个未定义的选项

p.add_argument(
    "--eval",
    action='store_true',
    help="Run any commands with newly updated environment, " 
)

# zero or more, so that you don't have to provide a dummy argument
# when the lack of --eval makes a command unnecessary.
# Wart: you can still use --eval without specifying any commands.
# I don't believe argparse alone is capable of handling this,
# at least not in a way that is simpler than just validating
# arguments after calling parse_args().
p.add_argument('cmd_and_args', nargs='*')
那么您的命令行可能看起来像

>>> p.parse_args('--export FOO=bar --eval -- ls -l'.split())
甚至

>>> p.parse_args('--eval --export FOO=bar -- ls -l'.split())
稍后,您将使用
args.eval
的布尔值来决定如何处理列表
args.cmd_和_args

重要提示:其中的一个缺点是,您将这些选项附加到任意的预先存在的解析器上,这些解析器可能定义了它们自己的位置参数,因此,如果不是不可能的话,让这些选项与原始解析器配合使用可能会很困难


另一个选项是采用单个参数进行内部解析

p.add_arguments("--eval")

...

args = p.parse_args()
cmd_and_args = shlex.split(args.eval)  # or similar
然后

(请注意,使用
str.split
对于像
--export FOO=bar--eval“ls-l”
这样的命令行是行不通的)

如果位置参数必须以-并且看起来不像负数,则可以插入伪参数“--”,它告诉parse_args()后面的所有内容都是位置参数[…]

因此,在您的情况下,您无法更改添加或定义参数的方式,但是您提供的要解析的字符串应该在eval选项的参数前面有
--
,如下所示:

--export FOO=bar --eval ls -- -l

--eval ls \-l
?@9769953 shell在执行脚本之前执行引号删除
argparse
仍将看到
--eval
ls
、和
-l
@chepner这里没有shell。但实际上,argparse在尝试时会将其解析为一个literal```。对,因为反斜杠转义是一个特定于shell的特性
argparse
没有任何这样的概念。但是,
-l
是一个位置参数,而不是
--eval
选项的参数。您必须对解析器进行重大调整。我不知道
--
。非常感谢。
--export FOO=bar --eval ls -- -l