3

有一个命令行功能我一直想要很长时间,我一直在考虑如何最好地实现它,但我什么也没得到......

所以我想要的是当我开始输入文件名并点击标签时,例如:

# git add Foo<tab>

我希望它运行一个find . -name "*$1*"并且基本上自动完成匹配文件的完整路径到我的命令行。

到目前为止我所拥有的:

我知道我必须编写一个函数,该函数将使用我想要的参数调用应用程序,例如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
    }
  }
}

有任何想法吗?

谢谢。

4

4 回答 4

2

匹配文件名中的任何位置都相当复杂,我不确定它是否真的有用。在文件名的开头进行匹配更有意义,并且更容易实现,即使是递归的。

现在,您提到 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>.

于 2012-08-19T10:27:10.807 回答
1

您应该看一下bash 完成的介绍。简而言之,bash 有一个用于配置和扩展制表符补全的系统。其他 shell 也这样做,并且每个 shell 都有不同的设置方式。使用这个系统不需要自己做所有的事情,并且向命令添加自定义参数完成相对容易。

于 2011-01-25T11:09:00.853 回答
0

我写了git-number以便在将文件指定给 git 时不必点击选项卡。

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

于 2011-04-05T14:35:13.197 回答
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]
于 2012-08-19T09:40:10.697 回答