问题描述
我正在尝试编写一个bash补全,以便让我可以补全其他shell所在的目录名称.
I'm trying to write a bash completion that will let me complete directory names that other shells are in.
例如,假设我在/very/long/path/name
中打开了另一个外壳,并且当前我所在的目录包含子目录 foo
和 bar
.当我输入 cd< Tab>
时,我想查看:
For example, suppose I have another shell open in /very/long/path/name
, and I'm currently in a directory that contains subdirs foo
and bar
. When I type cd <Tab>
, I want to see:
$ cd <Tab>
foo/ bar/ /very/long/path/name
我有以下命令来生成可能完成的列表:
I have this command to produce the list of potential completions:
ps -Cbash -opid= | xargs pwdx | cut -d" " -f2 | sort -u | while read; do echo ${REPLY#$PWD/}; done | grep -v "^$"
为简便起见,我将其写为 ... pipeline ...
.
For brevity, I'll write this as ...pipeline...
.
在我的系统上,有一个 _cd
函数可产生常规补全:
On my system there's a _cd
function that produces the regular completion:
$ complete -p cd
complete -o nospace -F _cd cd
我想重用此 _cd
函数,因为它很简单(根据 type _cd
而言,大约30行代码).奖励指出解决方案是否可以重用已经定义的完成方式,无论它是否基于名为 _cd
的函数.
I would like to reuse this _cd
function, because it's nontrivial (~30 lines of code, according to type _cd
). Bonus points if the solution reuses whatever completion is already defined, whether or not it's based on a function called _cd
.
我认为-完整
的 -C
选项听起来很有希望,但我无法使其正常工作:
I thought the -C
option to complete
sounded promising, but I can't get it to work:
$ 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
为 -F
编写我自己的包装函数,将其附加到 COMPREPLY
数组,但效果也不佳:
Writing my own wrapper function for -F
, which appends to the COMPREPLY
array, also didn't quite work:
$ function _cd2() { _cd; COMPREPLY=( ${COMPREPLY[@]} $(...pipeline...) ); }
$ cd <Tab>
foo/ bar/ name/
它去除了除最后一个路径之外的所有路径分量.我认为这一定是由 _cd
设置的,但是我不确定如何抵消它.
It strips off all the path components except the last. I figure it must be something set up by _cd
that does this, but I'm not sure how to counteract it.
如果我从 _cd2
中删除 _cd
调用,我会看到补全,但是它们不能正确补全部分目录名称.如果我键入 cd/ve< Tab>
,它仍然显示完整路径,而没有实际完成我的命令行.
If I remove the _cd
call from _cd2
, I do see the completions, but they don't properly complete partial directory names. If I type cd /ve<Tab>
, it still shows the full path, without actually completing my command line.
我怎样才能做到这一点?
How can I get this to do what I want?
附录: _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
}
推荐答案
您需要根据组合选项列表评估当前匹配项.这是一个说明运动部件的测试脚本:
You need to evaluate the current match against the list of combined options. Here's a test script that illustrates the moving parts:
#!/bin/bash
mkdir -p {my,other}/path/to/{a,b,c}
function _cd() {
COMPREPLY=( my/path/to/a my/path/to/b );
}
complete -o nospace -F _cd cd
function _cd2() {
local cur opts;
cur="${COMP_WORDS[COMP_CWORD]}";
_cd;
opts="${COMPREPLY[@]} other/path/to/c"; # here we combine options
COMPREPLY=($(compgen -W "${opts}" -- ${cur})); # here is the secret sauce
}
complete -F _cd2 cd
complete -p cd
最重要的一点是 _cd2
的 compgen
部分:该选项从组合的选项集中选择最合适的选项(在 $ opts 代码>).
The most important points are in the compgen
portion of _cd2
: that chooses the most suitable options from the combined set of choices (in $opts
).
这篇关于Bash完成以使"cd"命令从其他正在运行的shell中完成工作目录?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!