在bash中,argparse(以及不推荐使用的optparse)如何响应python程序名后的"tab"按键?

0xc*_*0de 11 python bash autocomplete shebang argparse

我已经测试过optcomplete使用该optparse模块.它的例子是一个简单的文件,所以我可以让它工作.我也使用该argparse模块对其进行了测试,因为之前的模块已被弃用.但我真的不明白python程序是如何以及由谁在tab press上调用的.我怀疑bashshebang线和argparse(或optparse)模块一起涉及某种方式.我一直试图解决这个问题(现在要阅读源代码).

我有一个更复杂的程序结构,其中包含处理参数的代码片段的包装器.它的argparse.ArgumentParser()实例化和调用add_argument()- 它被超级映射到另一个中间模块以避免重复代码,以及被调用的包装 - 在函数内部.

我想了解这个标签完成在bash和python之间的工作方式(或者就任何其他解释器而言perl).

注意:我对bash完成有一个公平的理解(我刚刚学到了),我想我理解bash(仅)自定义完成.

注意:我已经阅读了其他类似的SO问题,并且没有人真正回答这个问题.

编辑:是bash函数.
我已经理解了python模块如何通过读取os.environ变量值 来了解在命令行中输入的单词

$COMP_WORDS
$COMP_CWORD
$COMP_LINE
$COMP_POINT
$COMPREPLY
Run Code Online (Sandbox Code Playgroud)

这些变量仅在按Tab键上具有值.我的问题是如何触发python模块?

Nik*_* B. 14

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

COMPREPLY=( $( \
    COMP_LINE=$COMP_LINE  COMP_POINT=$COMP_POINT \
    COMP_WORDS="${COMP_WORDS[*]}"  COMP_CWORD=$COMP_CWORD \
    OPTPARSE_AUTO_COMPLETE=1 $1 ) )
Run Code Online (Sandbox Code Playgroud)

看到$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()
Run Code Online (Sandbox Code Playgroud)

当我们尝试自动填充时,这会给我们以下内容:

$ ./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
Run Code Online (Sandbox Code Playgroud)

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