Bash 是否可以为“菜单完成”定义完成规范?
我有一个文件夹Bash 是否可以为“菜单完成”定义完成规范?,bash,bash-completion,Bash,Bash Completion,我有一个文件夹~/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_202
~/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
列出所有候选项:
> 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 ...
这不是我想要的行为
我想要的是像Windows一样的自动完成。我知道我可以通过这样修改.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
定义一个完成规范,以便只在~/builds
的子目录上执行我想要的行为。我看到可以为执行此操作,但在菜单“完成”
上找不到执行此操作的信息
有可能吗?正如@chepner所说,
菜单完成
委托完成与完成
相同的完成(请参阅)。因此,最初我认为不可能根据是通过complete
还是menu 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
希望这就足够了:)如果您需要帮助以您描述的行为实际编写
complete
函数,我建议从当前实现开始另问一个问题(使用complete-p[command]
查看当前完成情况,然后键入[function name]
要查看完成的实现情况),应该直接从那里调整现有的行为。正如@chepner所说,菜单完成
将委托给与完成
相同的完成操作(请参阅)。因此,最初我认为不可能根据是通过complete
还是menu 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
希望这就足够了:)如果您需要帮助以您描述的行为实际编写
complete
函数,我建议从当前实现开始另问一个问题(使用complete-p[command]
查看当前完成情况,然后键入[function name]
要查看完成的实现),应该可以直接从那里调整现有的行为。complete
和menu complete
只是两个Readline函数,它们以不同的方式显示可编程完成的结果。这并不是您想要的,但是如果你以前没见过,请看一看。它提供了一个更强大、更灵活的功能。complete
和menu complete
我认为只是两个以不同方式显示可编程完成结果的Readline函数。这并不是您想要的功能,但如果您以前没有看到过,请看一看。它提供了一个更强大、更灵活的解决方案。