匹配文件名中的任何位置都相当复杂,我不确定它是否真的有用。在文件名的开头进行匹配更有意义,并且更容易实现,即使是递归的。
现在,您提到 find 是一项要求,但 bash(从 4.0 版开始)也可以递归查找文件,让 bash 做这部分应该更有效。要在 bash 中递归匹配,您可以通过运行启用 globstar shell 选项shopt -s globstar
,然后两个连续的星号**
, 将递归匹配。
接下来,假设您想在 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 "$@"
}
现在为实际的完成功能。当通过按 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>
.