我正在尝试为命令设置自动完成功能,该命令只需要一个参数,一个文件夹名称,
在 中/secure/kernel_builds/
,我有以下三个子文件夹:
3.5.6/ 3.6.2/ source/
现在我想要自动完成,列出所有可能的子文件夹名称,但不列出名为 的子文件夹名称source
,现在我正在使用一种非常愚蠢的方法来做到这一点,通过检查完成词是否以数字开头,
_avail_kernel_builds()
{
case $COMP_CWORD in
1)
if [[ "${COMP_WORDS[COMP_CWORD]}" =~ ^[0-9] ]];then
COMPREPLY=( /secure/kernel_builds/"${COMP_WORDS[COMP_CWORD]}"* )
else
COMPREPLY=( /secure/kernel_builds/"${COMP_WORDS[COMP_CWORD]}"[0-9]*/ )
fi
COMPREPLY=( "${COMPREPLY[@]#/secure/kernel_builds/}" )
COMPREPLY=( "${COMPREPLY[@]%/}" )
;;
esac
}
有更好的方法吗?
答案1
内置函数为此目的compgen
有一个参数:-X
-X 过滤模式 filterpat 是用于文件名扩展的模式。它应用于列表 由前面的选项和参数生成的可能的补全,以及每个 完成匹配的filterpat将从列表中删除。领先!在过滤器中 否定该模式;在这种情况下,任何不匹配 filterpat 的补全都会被删除。
所以你可能可以这样做:
_avail_kernel_builds() {
case $COMP_CWORD in
1) COMPREPLY=( $(cd /secure/kernel_builds; compgen -d -X "source") ) ;;
esac
}
所以compgen -d
说“列出当前目录中的文件夹”,并-X "source"
说“......但过滤掉任何名为“源”的内容。
答案2
您可以在循环中检查您(不)想要的字符串:
declare -a accept
declare -a reject
for s in "${COMPREPLY[@]}"; do
if [[ "$s" =~ want ]]; then
accept=( "${accept[@]}" "$s" )
else
reject=( "${reject[@]}" "$s" )
fi
done