匹配文件名中的任何地方相当复杂,我不确定它真的有用。匹配文件名的开始更有意义,并且更容易实现,即使是递归的。
现在,你提到查找作为一个需求,但bash(从版本4.0开始)也可以递归地查找文件,并且让bash执行该部分应该更高效。要在bash中递归匹配,请通过运行shopt -s globstar
来启用globstar shell选项,然后连续两个星号**
将递归匹配。
接下来,因为你想递归匹配的Git仓库里的文件,我们最好有一种方法来检测,我们在一个Git仓库实际上是,否则,如果你不小心触发它/
例如,您提示符会在等待bash搜索整个文件系统时挂起。以下函数在确定我们是否在git存储库中时应该相当有效。鉴于当前的工作目录,例如/foo/bar/baz
,它会查找/foo/bar/baz/.git
,/foo/bar/.git
,/foo/.git
,/.git
,如果找到一个则返回true,否则返回false。
isgit() {
local p=$PWD
while [[ $p ]]; do
[[ -d $p/.git ]] && return
p=${p%/*}
done
return 1
}
为了简单起见,我们将创建一个gadd
命令添加完成为。完成功能只能应用于命令的第一个单词。例如。我们可以添加完成git
,但不是git add
,因此我们将创建一个新的命令,将git add
变成一个单词。
gadd() {
git add "[email protected]"
}
现在为实际完成功能。当触击TAB时,该函数将被调用三个参数。 $1
是正在完成的命令,$2
是命令行正在完成的当前字,并且$3
是上一行字。所以我们要搜索的文件将由glob **/"$2"*
匹配;所有以"$2"
开头的文件。我们遍历这些文件名,并将它们追加到COMPREPLY数组中。如果COMPREPLY数组只在函数完成时包含一个值,则该字将被该值替换。如果它包含多个值,则再次点击选项卡以获取所有匹配的列表。
shopt -s globstar
_git_add_complete() {
local file
isgit || return
for file in **/"$2"*; do
# If the glob doesn't match, we'll get the glob itself, so make sure
# we have an existing file
[[ -e $file ]] || continue
# If it's a directory, add a trailing/
[[ -d $file ]] && file+=/
COMPREPLY+=("$file")
done
}
complete -F _git_add_complete gadd
添加上述三个代码块你~/.bashrc
,然后打开一个新的终端,进入一个Git仓库,并尝试gadd something<tab>
。
真棒。谢谢! – 2011-01-25 12:13:14