我正在尝试编写一个 bash 完成功能,它可以让我完成其他 shell 所在的目录名称。
例如,假设我在 中打开了另一个 shell /very/long/path/name
,并且我当前位于包含子目录foo
和bar
. 当我输入时cd <Tab>
,我想看到:
$ cd <Tab>
foo/ bar/ /very/long/path/name
我有这个命令来生成潜在完成列表:
ps -Cbash -opid= | xargs pwdx | cut -d" " -f2 | sort -u | while read; do echo ${REPLY#$PWD/}; done | grep -v "^$"
为简洁起见,我将其写为...pipeline...
.
在我的系统上,有一个_cd
生成常规完成的函数:
$ complete -p cd
complete -o nospace -F _cd cd
我想重用这个_cd
函数,因为它很重要(大约 30 行代码,根据type _cd
)。如果解决方案重用已定义的任何完成,无论它是否基于名为_cd
.
我认为该-C
选项complete
听起来很有希望,但我无法让它发挥作用:
$ complete -C '...pipeline...' cd
$ cd <Tab>grep: cd: No such file or directory
grep: : No such file or directory
grep: cd: No such file or directory
编写我自己的包装函数 for -F
,它附加到COMPREPLY
数组中,也不太奏效:
$ function _cd2() { _cd; COMPREPLY=( ${COMPREPLY[@]} $(...pipeline...) ); }
$ cd <Tab>
foo/ bar/ name/
它剥离了除最后一个之外的所有路径组件。我认为它一定是这样_cd
做的,但我不知道如何抵消它。
如果我_cd
从 中删除调用_cd2
,我会看到完成,但它们没有正确完成部分目录名称。如果我键入cd /ve<Tab>
,它仍然显示完整路径,而实际上并没有完成我的命令行。
我怎样才能让它做我想做的事?
附录: 的完整定义_cd
:
$ type _cd
_cd is a function
_cd ()
{
local cur prev words cword;
_init_completion || return;
local IFS='
' i j k;
compopt -o filenames;
if [[ -z "${CDPATH:-}" || "$cur" == ?(.)?(.)/* ]]; then
_filedir -d;
return 0;
fi;
local -r mark_dirs=$(_rl_enabled mark-directories && echo y);
local -r mark_symdirs=$(_rl_enabled mark-symlinked-directories && echo y);
for i in ${CDPATH//:/'
'};
do
k="${#COMPREPLY[@]}";
for j in $( compgen -d $i/$cur );
do
if [[ ( -n $mark_symdirs && -h $j || -n $mark_dirs && ! -h $j ) && ! -d ${j#$i/} ]]; then
j+="/";
fi;
COMPREPLY[k++]=${j#$i/};
done;
done;
_filedir -d;
if [[ ${#COMPREPLY[@]} -eq 1 ]]; then
i=${COMPREPLY[0]};
if [[ "$i" == "$cur" && $i != "*/" ]]; then
COMPREPLY[0]="${i}/";
fi;
fi;
return 0
}