在Bash脚本中find基于文件名的自动完成

有一个我一直想要的命令行function,我想过如何最好地实现它,但我什么都没有…

所以我想要的是当我开始input一个文件名并点击标签,例如:

# git add Foo<tab> 

我想要它运行一个find . -name "*$1*" find . -name "*$1*"并基本自动完成匹配的文件到我的命令行的完整path。

我到目前为止:

我知道我将不得不编写一个函数,用我想要的参数调用应用程序,例如git add 。 之后,它需要捕捉tab-keystroke事件并执行上面提到的查找,并显示结果如果多,或者填写结果(如果有)。

我无法弄清楚的是:

如何捕捉函数内的一个函数内的Tab键事件。

所以基本上是伪代码:

 gadd() {git add autocomplete_file_search($1)} autocomplete_file_search(keyword) { if( tab-key-pressed ){ files = find . -name "*$1*"; if( filecount > 1 ) { show list; } if( files == 1 ) { return files } } } 

有任何想法吗?

谢谢。

Solutions Collecting From Web of "在Bash脚本中find基于文件名的自动完成"

你应该看看这个介绍bash完成 。 简而言之,bash有一个用于配置和扩展标签页完成的系统。 其他炮弹也是这样做的,每个炮弹都有不同的设置方式。 使用这个系统不需要自己做所有的事情,并且为一个命令添加自定义参数完成是相对容易的。

匹配文件名中的任何地方是相当复杂的,我不确定它真的有用。 匹配文件名的开始更有意义,甚至递归地实现也更容易。

现在,你提到find是一个需求,但bash(从4.0版本开始)也可以递归地查找文件,让bash做这个部分应该更有效率。 要在bash中递归匹配,可以通过运行shopt -s globstar启用globstar shell选项,然后连续两个星号**将递归匹配。

接下来,考虑到你想在git仓库中递归地匹配文件,我们最好有办法检测到我们实际上在git仓库中,否则,如果你不小心触发它/例如,你的提示将挂起等待bash搜索整个文件系统。 下面的函数在确定我们是否在git仓库中应该是相当有效的。 给定当前的工作目录,例如/foo/bar/baz ,它会查找/.git并返回true if它找到一个,否则为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>

这是否工作?

 $ cat .bash_completion _foo() { local files cur=${COMP_WORDS[COMP_CWORD]} local files=$(for x in `find -type f`; do echo ${x}; done) COMPREPLY=( $( compgen -W "${files}" -- ${cur} ) ) return 0 } complete -F _foo foo $ . /etc/bash_completion $ foo ./[tab] 

我写了git-number,以便在将文件指定为git时,从来不需要点击选项卡。

使用git-number,我可以使用数字来表示我想要处理的文件名。