是否可以为菜单完成定义完成规范?

时间:2020-04-15 13:22:17

标签: bash bash-completion

我有一个文件夹def sieve_of_Eratosthenes(n): L= list(range(2,n+1)) # creates a list from 2 to n i=2 while i*i <=n: # going to remove multiples of i, starting at i^2 k=i # if j <i then ij already checked while i*k <= max(L): try: L.remove(i*k) # there is an error if the element is not in # the list so need to add these two lines except ValueError: pass # do nothing! k=k+1 i=L[i-1] # list index starts at 0, want i to be next element in the list # print(L) return L ,其中包含以下子目录:

~/builds

当前,当我编写一个以子文件夹之一作为参数并使用自动完成功能的命令时,> tree ~/builds ~/builds ├── projectA │   ├── build_2020_04_10_ok │ ├── build_2020_04_11_ko │ ├── build_2020_04_12_ok │   └── ... └── projectB ├── build_2020_04_10_ok ├── build_2020_04_11_ok ├── build_2020_04_12_ok └── ... 会列出所有候选:

bash

那不是我想要的行为。

我想要的更像是Windows式的自动完成功能。我知道可以通过以下方式修改> mycmd ~/builds/projectA/[TAB] > mycmd ~/builds/projectA/build_2020_04_1[TAB][TAB] build_2020_04_10_ok build_2020_04_11_ko build_2020_04_12_ok ... 来使用它:

.bashrc

现在,当我按bind '"\C-g": menu-complete' 时会发生以下情况:

Ctrl+g

这几乎是我想要的。我想更改子文件夹的显示顺序(首先是最新的,然后从大到小)。另外,我想放弃所有的> mycmd ~/builds/projectA/[Ctrl+g] > mycmd ~/builds/projectA/build_2020_04_10_ok[Ctrl+g] > mycmd ~/builds/projectA/build_2020_04_11_ko[Ctrl+g] > mycmd ~/builds/projectA/build_2020_04_12_ok 构建。换句话说,我想要此命令定义的顺序:

ko

因此,我想为ls -dr build*ok build_2020_04_12_ok/ build_2020_04_10_ok/ 定义一个完成规范,以仅在menu-complete的子目录上执行我想要的行为。我发现有可能针对https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/进行此操作,但没有发现有关~/builds进行此操作的信息。

有可能吗?

1 个答案:

答案 0 :(得分:5)

正如@chepner所说,menu-complete委派与complete相同的补全(请参见man readline)。因此,起初我认为不可能根据完成的completemenu-complete来不同地配置完成。但是我检查了是否根据调用哪个钩子和是否有突出表现设置了不同的值:

# Get the current set of environment variables
# the sed expression strips functions to just print variables
# There's probably a better way to do this...
bash-5.0$ get_env() {
  set | sed -n '/^[^=]*$/q;p' | sort
}

# Define a function to use as a completion that simply prints the changes
# in the environment between the normal shell and from within a completion
bash-5.0$ diff_env() {
  echo # extra echo's for readability
  sdiff -s /tmp/env.txt <(get_env)
}
# Register it as a completion (the command doesn't actually need to exist)
bash-5.0$ complete -F diff_env foo

bash-5.0$ bind '"\C-g": menu-complete'

# Persist the initial environment
bash-5.0$ get_env > /tmp/env.txt

bash-5.0$ foo [TAB]
BASH_LINENO=([0]="12")            |    BASH_LINENO=([0]="1" [1]="13")
BASH_SOURCE=([0]="main")          |    BASH_SOURCE=([0]="main" [1]="main")
                                  >    COMP_CWORD=1
                                  >    COMP_KEY=9
                                  >    COMP_LINE='foo '
                                  >    COMP_POINT=4
                                  >    COMP_TYPE=9
                                  >    COMP_WORDS=([0]="foo" [1]="")
                                  >    _=echo
FUNCNAME=([0]="get_env")          |    FUNCNAME=([0]="get_env" [1]="diff_env")
_=get_env                         <

^C
bash-5.0$ foo [Ctrl+g]
BASH_LINENO=([0]="12")            |    BASH_LINENO=([0]="1" [1]="14")
BASH_SOURCE=([0]="main")          |    BASH_SOURCE=([0]="main" [1]="main")
                                  >    COMP_CWORD=1
                                  >    COMP_KEY=9
                                  >    COMP_LINE='foo '
                                  >    COMP_POINT=4
                                  >    COMP_TYPE=37
                                  >    COMP_WORDS=([0]="foo" [1]="")
                                  >    _=echo
FUNCNAME=([0]="get_env")          |    FUNCNAME=([0]="get_env" [1]="diff_env")
_=get_env                         <
^C

发现了吗? COMP_TYPE不一样! man bash说明根据完成行为将其设置为整数;对于给定的完成类型,描述有点不透明,但是值是ASCII码点(对于 tab 为9,对于%为37)。

因此,我们可以定义一个完成函数来检查该值以更改其行为:

bash-5.0$ clever_complete() {
  case "$COMP_TYPE" in
    9) COMPREPLY=("tab!") ;;
    37) COMPREPLY=("ctrl-g!") ;;
    # should probably behave the same as [TAB], but I split it out to demonstrate
    *) COMPREPLY=("IDK... $COMP_TYPE") ;;
  esac
}
bash-5.0$ complete -F clever_complete bar
bash-5.0$ bar [TAB]tab! ^C
bash-5.0$ bar [Ctrl+g]ctrl-g! ^C

希望这足以继续进行:)如果您需要帮助,以您描述的行为实际编写complete函数,我建议您在当前实现中开始一个单独的问题(使用complete -p [command]进行查看)当前的完成,以及type [function-name]来查看完成的实现),应该可以从那里直接调整现有行为。