参数

论据的作用类似于 options 但都是位置性的。由于其语法特性,它们也只支持options的一部分特性。Click也不会试图为您记录参数并希望您这样做 document them manually 为了避免难看的帮助页。

基本论点

最基本的选项是一个值的简单字符串参数。如果没有提供类型,则使用默认值的类型;如果没有提供默认值,则假定类型为 STRING .

例子:

@click.command()
@click.argument('filename')
def touch(filename):
    """Print FILENAME."""
    click.echo(filename)

看起来像是:

$ touch foo.txt
foo.txt

可变参数

第二个最常见的版本是可变参数,其中接受特定(或无限)数量的参数。这可以用 nargs 参数。如果设置为 -1 ,则接受无限数量的参数。

然后将值作为元组传递。请注意,只能将一个参数设置为 nargs=-1 因为它会吞噬所有的参数。

例子:

@click.command()
@click.argument('src', nargs=-1)
@click.argument('dst', nargs=1)
def copy(src, dst):
    """Move file SRC to DST."""
    for fn in src:
        click.echo(f"move {fn} to folder {dst}")

看起来像是:

$ copy foo.txt bar.txt my_folder
move foo.txt to folder my_folder
move bar.txt to folder my_folder

请注意,这不是您编写此应用程序的方式。原因是在这个特定的例子中,参数被定义为字符串。然而,文件名不是字符串!它们可能在某些操作系统上,但不一定在所有操作系统上。要获得更好的编写方法,请参阅下一节。

关于非空变量参数的说明

如果你来自 argparse ,您可能缺少对设置的支持 nargs+ 以指示至少需要一个参数。

这是由设置支持的 required=True . 但是,如果您可以避免使用它,则不应该使用它,因为我们认为,如果变量参数为空,脚本应该优雅地降级为noops。这样做的原因是,经常使用命令行中的通配符输入调用脚本,如果通配符为空,则它们不应出错。

文件参数

由于所有示例都已经使用了文件名,因此解释如何正确处理文件是很有意义的。如果命令行工具以unix的方式处理文件(也就是接受),那么它们会更有趣。 - 作为引用stdin/stdout的特殊文件。

Click通过 click.File 智能处理文件的类型。它还正确地处理所有版本的python的unicode和字节,因此脚本保持非常可移植性。

例子:

@click.command()
@click.argument('input', type=click.File('rb'))
@click.argument('output', type=click.File('wb'))
def inout(input, output):
    """Copy contents of INPUT to OUTPUT."""
    while True:
        chunk = input.read(1024)
        if not chunk:
            break
        output.write(chunk)

它的作用是:

$ inout - hello.txt
hello
^D
$ inout hello.txt -
hello

文件路径参数

在上一个示例中,文件被立即打开。但是如果我们只需要文件名呢?na_ve方法是使用默认的字符串参数类型。但是,请记住,click是基于Unicode的,因此字符串始终是Unicode值。不幸的是,文件名可以是Unicode或字节,具体取决于使用的操作系统。因此,类型不足。

相反,您应该使用 Path 类型,它将自动处理此模糊性。它不仅返回字节或Unicode,这取决于什么更有意义,而且还可以为您执行一些基本检查,例如存在性检查。

例子:

@click.command()
@click.argument('filename', type=click.Path(exists=True))
def touch(filename):
    """Print FILENAME if the file exists."""
    click.echo(click.format_filename(filename))

它的作用是:

$ touch hello.txt
hello.txt

$ touch missing.txt
Usage: touch [OPTIONS] FILENAME
Try 'touch --help' for help.

Error: Invalid value for 'FILENAME': Path 'missing.txt' does not exist.

文件打开安全

这个 FileType 类型有一个问题需要处理,那就是决定何时打开文件。默认行为是“智能”的。这意味着它将打开stdin/stdout并立即打开要读取的文件。当文件无法打开时,这将给用户直接反馈,但它只会在首次执行IO操作时打开要写入的文件,方法是将文件自动包装在一个特殊的包装器中。

这种行为可以通过传球来强制 lazy=Truelazy=False 给建设者。如果文件以延迟方式打开,它将通过引发 FileError .

由于打开用于写入的文件通常会立即清空该文件,因此只有在开发人员完全确定这是预期行为时,才应禁用惰性模式。

强制惰性模式对于避免资源处理混乱也非常有用。如果文件以惰性模式打开,它将收到 close_intelligently 方法来帮助确定文件是否需要关闭。这对于参数不需要,但对于使用 prompt() 函数,因为您不知道像stdout这样的流是打开的(以前已经打开过)还是需要关闭的真正文件。

从click 2.0开始,还可以通过传递以原子模式打开文件 atomic=True . 在原子模式下,所有的写操作都将进入同一文件夹中的一个单独的文件中,完成后,文件将移到原始位置。如果修改了其他用户定期读取的文件,则此功能非常有用。

环境变量

和选项一样,参数也可以从环境变量中获取值。但是,与选项不同,它只支持显式命名的环境变量。

示例用法:

@click.command()
@click.argument('src', envvar='SRC', type=click.File('r'))
def echo(src):
    """Print value of SRC environment variable."""
    click.echo(src.read())

从命令行:

$ export SRC=hello.txt
$ echo
Hello World!

在这种情况下,它也可以是选择第一个环境变量的不同环境变量的列表。

一般来说,不建议使用此功能,因为它会导致用户产生很多混淆。

类选项参数

有时,您希望处理看起来像选项的参数。例如,假设您有一个名为 -foo.txt . 如果以这种方式将其作为参数传递,则Click会将其视为选项。

要解决这个问题,请Click“执行任何POSIX样式的命令行脚本所执行的操作”,即接受字符串 -- 作为选项和参数的分隔符。后 -- 标记,接受所有其他参数作为参数。

示例用法:

@click.command()
@click.argument('files', nargs=-1, type=click.Path())
def touch(files):
    """Print all FILES file names."""
    for filename in files:
        click.echo(filename)

从命令行:

$ touch -- -foo.txt bar.txt
-foo.txt
bar.txt

如果你不喜欢 -- marker,您可以将ignore_unknown_options设置为true以避免检查未知选项:

@click.command(context_settings={"ignore_unknown_options": True})
@click.argument('files', nargs=-1, type=click.Path())
def touch(files):
    """Print all FILES file names."""
    for filename in files:
        click.echo(filename)

从命令行:

$ touch -foo.txt bar.txt
-foo.txt
bar.txt