argparse(以及已弃用的 optparse)如何响应 bash 中 python 程序名称后面的“tab”按键?

问题描述 投票:0回答:1

我已经测试了

optcomplete
使用
optparse
模块。它的示例是一个简单的文件,因此我可以让它工作。我还使用
argparse
模块对其进行了测试,因为前一个模块已被弃用。但我真的不明白 python 程序是如何以及由谁在按下选项卡时调用的。我怀疑
bash
以及
shebang
线和
argparse
(或
optparse
)模块以某种方式参与其中。我一直在试图解决这个问题(现在要阅读源代码)。

我有一个更复杂的程序结构,其中包括处理参数的代码片段的包装器。它的

argparse.ArgumentParser()
实例化和对
add_argument()
的调用(被超类到另一个中间模块以避免重复代码,以及正在调用的包装器)位于函数内部。

我想了解这个制表符补全在 bash 和 python(或者任何其他解释器,如

perl
)之间的工作方式。

注意:我对 bash 完成有一个很好的理解(我刚刚学到),并且我认为我理解 bash(仅)自定义完成。

注意:我读过其他类似的问题,但没有人真正回答这个问题。

编辑:这里是bash函数。
我已经了解了 python 模块如何通过读取

os.environ
变量值来了解在命令行中键入的单词

$COMP_WORDS
$COMP_CWORD
$COMP_LINE
$COMP_POINT
$COMPREPLY

这些变量仅在按下 Tab 时才具有值。 我的问题是 python 模块是如何被触发的?

python bash autocomplete argparse shebang
1个回答
16
投票

为了了解这里发生了什么,让我们检查一下 bash 函数实际上做了什么:

COMPREPLY=( $( \
    COMP_LINE=$COMP_LINE  COMP_POINT=$COMP_POINT \
    COMP_WORDS="${COMP_WORDS[*]}"  COMP_CWORD=$COMP_CWORD \
    OPTPARSE_AUTO_COMPLETE=1 $1 ) )

看到最后的

$1
了吗?这意味着它实际上调用了我们想要执行的带有特殊环境变量设置的Python文件!为了追踪发生的情况,让我们准备一个小脚本来拦截
optcomplete.autocomplete
所做的事情:

#!/usr/bin/env python2
import os, sys
import optparse, optcomplete
from cStringIO import StringIO

if __name__ == '__main__':    
    parser = optparse.OptionParser()

    parser.add_option('-s', '--simple', action='store_true',
                      help="Simple really simple option without argument.")

    parser.add_option('-o', '--output', action='store',
                      help="Option that requires an argument.")

    opt = parser.add_option('-p', '--script', action='store',
                            help="Option that takes python scripts args only.")
    opt.completer = optcomplete.RegexCompleter('.*\.py')
    
    # debug env variables
    sys.stderr.write("\ncalled with args: %s\n" % repr(sys.argv))
    for k, v in sorted(os.environ.iteritems()):
        sys.stderr.write("  %s: %s\n" % (k, v))

    # setup capturing the actions of `optcomplete.autocomplete`
    def fake_exit(i):
      sys.stderr.write("autocomplete tried to exit with status %d\n" % i)
    sys.stdout = StringIO()
    sys.exit = fake_exit

    # Support completion for the command-line of this script.
    optcomplete.autocomplete(parser, ['.*\.tar.*'])

    sys.stderr.write("autocomplete tried to write to STDOUT:\n")
    sys.stderr.write(sys.stdout.getvalue())
    sys.stderr.write("\n")

    opts, args = parser.parse_args()

当我们尝试自动完成它时,这会为我们提供以下内容:

$ ./test.py [tab]
called with args: ['./test.py']
  ...
  COMP_CWORD: 1
  COMP_LINE: ./test.py 
  COMP_POINT: 10
  COMP_WORDS: ./test.py 
  ...
  OPTPARSE_AUTO_COMPLETE: 1
  ...
autocomplete tried to exit with status 1
autocomplete tried to write to STDOUT:
-o -h -s -p --script --simple --help --output

所以

optcomplete.autocomplete
只是读取环境,准备匹配,将它们写入STDOUT并退出。然后结果
-o -h -s -p --script --simple --help --output
被放入 bash 数组 (
COMPREPLY=( ... )
) 并返回到 bash 以向用户呈现选择。不涉及魔法:)

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.