我已经想要了很长一段时间的命令行功能,我已经考虑过如何最好地实现它,但我一无所获......
所以我想要的是当我开始输入文件名并点击标签时,例如:
# git add Foo<tab>
我希望它运行find . -name "*$1*"
并基本上自动填充匹配的文件到命令行的完整路径。
到目前为止我有什么:
我知道我必须编写一个函数,用我想要的参数调用app
例如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
}
}
}
有什么想法吗?
感谢。
答案 0 :(得分:2)
匹配文件名中的任何位置都相当复杂,我不确定它真的有用。在文件名开头匹配更有意义,更容易实现,甚至递归。
现在,你提到了find作为一个要求,但是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 "$@"
}
现在为实际完成功能。当通过命中TAB触发时,将使用三个参数调用该函数。 $1
是正在完成的命令,$2
是正在完成的命令行的当前单词,而$3
是该行的前一个单词。所以我们要搜索的文件将由glob **/"$2"*
匹配;所有以"$2"
开头的文件。我们迭代这些文件名,并将它们附加到COMPREPLY数组。如果COMPREPLY数组在函数完成时只包含一个值,则该字将被该值替换。如果它包含多个值,请再次按Tab键以获取所有匹配项的列表。
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>
。
答案 1 :(得分:1)
你应该看看这个introduction to bash completion。简而言之,bash有一个用于配置和扩展选项卡完成的系统。其他shell也会这样做,每个shell都有不同的设置方式。使用这个系统,没有必要自己做所有事情,并且为命令添加自定义参数完成相对容易。
答案 2 :(得分:0)
我写了git-number,这样我就不必在将文件指定为git时点击标签。
使用git-number,我可以使用数字来表示我希望git处理的文件名。
答案 3 :(得分:0)
这有用吗?
$ 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]