bash python argparse中的自定义选项卡完成

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14597466/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 04:23:20  来源:igfitidea点击:

Custom tab completion in python argparse

pythonbashcommand-line-interfaceargparsetab-completion

提问by wim

How to get shell tab completion cooperating with argparsein a Python script?

如何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))

With an executable flag set on the .py file, the expected results should be something like:

在 .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

回答by Anthon

Have a look at argcompleteby Andrey Kislyuk.

看看安德烈·基斯柳(Andrey Kislyuk) 的 argcomplete。

Install it with:

安装它:

pip install argcomplete

Import the module and add one line in your source before calling parser.parse_args():

在调用之前导入模块并在源代码中添加一行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))

and to make sure that bash knows about this script, you use

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

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

you should put that line in your ~/.bashrcor follow argcomplete's docs and activate 'global' completion.

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

After that you completion works as requested.

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

The way this works is that the eval line creates a function _python_argcomletewhich is registered using complete. (Run register-python-argcomplete your_scriptto just have a look at what gets eval-ed into bash). The autocomplete function looks for environment variables set by the bash completion mechanism to see if it needs to act. If it acts, it exits the program. If it doesn't act, this is a normal call to the program that function does nothing and the normal flow of the program continues.

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

回答by Sorin

For auto-complete to work you need a bash function to generate the possible options, and then you need to run complete -F <function_name> <program_name>

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

The best way of doing this is to have the program generate the completion function based on it's own parsing algorithm to avoid duplication. However, at a quick glance on argparse, I could not find a way to access it's internal structure, but I suggest you look for it.

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

Here is a bash function that will do for the above program:

这是一个用于上述程序的 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
}