52

如何argparse在 Python 脚本中使 shell 选项卡完成配合?

#!/usr/bin/env python
import argparse

def main(**args):
    pass

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('positional', choices=['spam', 'eggs'])
    parser.add_argument('--optional', choices=['foo1', 'foo2', 'bar'])
    args = parser.parse_args()
    main(**vars(args))

在 .py 文件上设置可执行标志后,预期结果应类似于:

$ ./example.py sp<tab>             
   ->  completes to "./example.py spam"
$ ./example.py --op<tab> 
   ->  completes to "./example.py --optional"
$ ./example.py --optional b<tab>
   ->  completes to "./example.py --optional bar"
$ ./example.py --optional f<tab>   
   ->  completes to "./example.py --optional foo"
       and, additionally, prints  "foo1  foo2"  choices on stdout on a new line
4

2 回答 2

76

看看Andrey Kislyuk的 argcomplete。

安装它:

pip install argcomplete

在调用之前导入模块并在源代码中添加一行parser.parse_args()

#!/usr/bin/env python

import argparse as ap
import argcomplete

def main(**args):
  pass

if __name__ == '__main__':
  parser = ap.ArgumentParser()
  parser.add_argument('positional', choices=['spam', 'eggs'])
  parser.add_argument('--optional', choices=['foo1', 'foo2', 'bar'])
  argcomplete.autocomplete(parser)
  args = parser.parse_args()
  main(**vars(args))

并确保 bash 知道这个脚本,你使用

eval "$(register-python-argcomplete your_script)"

您应该将该行放入您的~/.bashrc或遵循 argcomplete 的文档并激活“全局”完成。

之后,您按要求完成工作。

它的工作方式是 eval 行创建一个_python_argcomlete使用注册的函数complete。(运行register-python-argcomplete your_script以查看 eval 进入 bash 的内容)。自动完成功能会查找 bash 完成机制设置的环境变量,看它是否需要行动。如果它起作用,它就会退出程序。如果它不动作,这是对程序的正常调用,该函数什么都不做,程序的正常流程继续。

于 2013-03-08T07:41:05.593 回答
4

要使自动完成功能起作用,您需要一个 bash 函数来生成可能的选项,然后您需要运行complete -F <function_name> <program_name>

最好的方法是让程序根据自己的解析算法生成完成函数,以避免重复。但是,快速浏览一下 argparse,我找不到访问其内部结构的方法,但我建议您寻找它。

这是一个适用于上述程序的 bash 函数:

function _example_auto() {
    local cur=${COMP_WORDS[COMP_CWORD]}
    local prev=${COMP_WORDS[COMP_CWORD-1]}

    case "$prev" in
    --optional ) 
        COMPREPLY=( $(compgen -W "foo1 foo2 bar" -- $cur) )
        return 0
        ;;
    *)
        COMPREPLY=( $(compgen -W "--optional spam eggs" -- $cur) )
        return 0
        ;;
    esac
}
于 2013-03-06T11:06:38.957 回答