如何获得bash补全以使用别名?


195

例子:

我在Mac上使用bash v3.2.17,正在使用通过具有bash_completion变体的macports安装的git。

当我键入git checkout m<tab>。例如,我完成了master

但是,我有一个别名git checkoutgco。当我输入时gco m<tab>,我没有自动完成分支名称。

理想情况下,我希望自动补全可以神奇地为我的所有别名工作。可能吗?失败的话,我想为每个别名手动自定义它。那么,我该怎么办?


3
完整-o默认-o nospace -F现在不起作用
八眼2013年

5
投票数超出最高答案的问题通常意味着功能要求
Ciro Santilli郝海东冠状病六四事件法轮功2014年

2
超级用户的另一个答案是,有人向我指出,我的问题是对此有误。superuser.com/questions/436314/…–
dstarh 2014年

Answers:


183

如以上评论所述,

complete -o default -o nospace -F _git_checkout gco

将不再起作用。但是,__git_completegit-completion.bash中有一个函数可以用来为别名设置完成,如下所示:

__git_complete gco _git_checkout

6
这是我在许多错误答案中唯一看到的正确答案。
2013年

45
如果您为git使用全局别名“ g”,则还可以添加__git_complete g __git_main以使代码完成对所有git命令起作用。
Ondrej Machulda

5
^^对于git / shell / bash的新手。上面的注释指的是全局shell别名,而不是本地git别名。
伊莱贾·林恩

14
我该放在哪里?
benregn

15
终于弄清楚了如何正确地做到这一点!步骤1)复制git-completion.bash<your git install folder>/etc/bash-completion.d/~/.git-completion.bash 步骤2)添加source ~/.git-completion.bash到您的.bash_profile 步骤3)添加__git_complete gco _git_checkout在你的.bash_profile上述行之后的任何地方。步骤4)重新启动Shell,享受您的别名自动完成!:)
kpsfoo 2014年

53

我也遇到了这个问题,并提出了这个代码片段。这将自动为您完成所有别名。在声明所有(或任何)别名后运行它。

# wrap_alias takes three arguments:
# $1: The name of the alias
# $2: The command used in the alias
# $3: The arguments in the alias all in one string
# Generate a wrapper completion function (completer) for an alias
# based on the command and the given arguments, if there is a
# completer for the command, and set the wrapper as the completer for
# the alias.
function wrap_alias() {
  [[ "$#" == 3 ]] || return 1

  local alias_name="$1"
  local aliased_command="$2"
  local alias_arguments="$3"
  local num_alias_arguments=$(echo "$alias_arguments" | wc -w)

  # The completion currently being used for the aliased command.
  local completion=$(complete -p $aliased_command 2> /dev/null)

  # Only a completer based on a function can be wrapped so look for -F
  # in the current completion. This check will also catch commands
  # with no completer for which $completion will be empty.
  echo $completion | grep -q -- -F || return 0

  local namespace=alias_completion::

  # Extract the name of the completion function from a string that
  # looks like: something -F function_name something
  # First strip the beginning of the string up to the function name by
  # removing "* -F " from the front.
  local completion_function=${completion##* -F }
  # Then strip " *" from the end, leaving only the function name.
  completion_function=${completion_function%% *}

  # Try to prevent an infinite loop by not wrapping a function
  # generated by this function. This can happen when the user runs
  # this twice for an alias like ls='ls --color=auto' or alias l='ls'
  # and alias ls='l foo'
  [[ "${completion_function#$namespace}" != $completion_function ]] && return 0

  local wrapper_name="${namespace}${alias_name}"

  eval "
function ${wrapper_name}() {
  let COMP_CWORD+=$num_alias_arguments
  args=( \"${alias_arguments}\" )
  COMP_WORDS=( $aliased_command \${args[@]} \${COMP_WORDS[@]:1} )
  $completion_function
  }
"

  # To create the new completion we use the old one with two
  # replacements:
  # 1) Replace the function with the wrapper.
  local new_completion=${completion/-F * /-F $wrapper_name }
  # 2) Replace the command being completed with the alias.
  new_completion="${new_completion% *} $alias_name"

  eval "$new_completion"
}

# For each defined alias, extract the necessary elements and use them
# to call wrap_alias.
eval "$(alias -p | sed -e 's/alias \([^=][^=]*\)='\''\([^ ][^ ]*\) *\(.*\)'\''/wrap_alias \1 \2 '\''\3'\'' /')"

unset wrap_alias

6
由于let COMP_CWORD+=$num_alias_arguments某些原因,该行在Mac OS X上不起作用。((COMP_CWORD+=$num_alias_arguments))尽管用修复固定了它
Mario F

5
哇,太棒了-谢谢! wrap_alias别名定义中的双引号引起了窒息,我想对于多命令别名(alias 'foo=bar; baz')并没有多大意义,因此我在| grep -v '[";|&]'后面加上了一个多余的内容alias -p。同样,对于数百个别名定义,它会有点慢,但是我很高兴地确认,使用echo代替eval输出并将其输出到缓存文件中(然后可以eval一次性编辑)可以很好并且非常快。
Jo Liss

2
另一个提示:wrap_alias需要设置完成,因此我不得不移到代码source /etc/bash_completion前面wrap_alias
Jo Liss

2
这改变了行之后为我工作在OS X 10.7.2 let COMP_CWORD+=$num_alias_argumentslet \"COMP_CWORD+=$num_alias_arguments\"
irh 2011年

7
请参阅superuser.com/a/437508/102281上此脚本的更新版本(例如,我添加了对一些git完成所需的COMP_LINE和COMP_POINT的支持)。
约翰·梅勒

18

git-completion.bash其中一行:

complete -o default -o nospace -F _git git

查看该行(和_git函数),可以将此行添加到您的.bash_profile

complete -o default -o nospace -F _git_checkout gco

4
某些git * bash函数不再使用此方法工作
cmcginty 2011年

是的,在git_completion.bash中的某些内容发生更改之前,它一直都很好用...现在,它可以使用完整命令,但不能使用别名。
迈克尔·史密斯

有关在现代git中有效的答案,请参见本页末。
八眼2013年

我们不应该将接受的答案更改为“正确答案”,还是至少更新接受的答案以反映更改?
Tony K.

效果很好-将其添加到我的.bash_profile中,到目前为止,无论
Larry

15

我将g ='git'用作别名,并结合git别名输入类似

$ g co <branchname>

对于我的特定用例,最简单的解决方法是在git-completion中添加一行。

在此行的正下方:

__git_complete git _git

我添加了以下行来处理我的单个“ g”别名:

__git_complete g _git

2
(我正在使用Cygwin。)我在中找不到文件git-completion或该行/etc/bash_completion.d/git,但是我complete -o default -o nospace -F _git g在别名中添加之后.bash_aliases,它就起作用了!
idbrii 2012年

请注意,如果您在中/etc/bash-completion.d/或在中新编辑文件/usr/share/bash-completion/,则每次使用包管理器更新该文件时,所做的更改都会丢失。
kub1x

14

理想情况下,我希望自动补全可以神奇地为我的所有别名工作。可能吗?

是的,完全别名项目(在Linux上)是可能的。对Mac的支持是试验性的,但用户报告成功。


4
非常感谢,这比弄清楚世界上每个实用程序如何实现bash完成要好得多。
artm

2
确实,节省了我一些时间来配置别名的补全。
Samir Alajmovic

2
在Linux上像超级按钮一样工作(在Mac上未经测试)。感谢您编写!
bitmask

1
这真是太棒了!它可以正常工作,不用大惊小怪,更好!谢谢!
emi

5

您也可以尝试使用Git别名。例如,在我的~/.gitconfig文件中,有一个部分如下所示:

[alias]
        co = checkout

因此,您可以输入git co m<TAB>,然后应将其扩展为git co master,这是git checkout命令。


5

该论坛页面显示了一个解决方案。

将这些行放入您的.bashrc.bash_profile

# Author.: Ole J
# Date...: 23.03.2008
# License: Whatever

# Wraps a completion function
# make-completion-wrapper <actual completion function> <name of new func.>
#                         <command name> <list supplied arguments>
# eg.
#   alias agi='apt-get install'
#   make-completion-wrapper _apt_get _apt_get_install apt-get install
# defines a function called _apt_get_install (that's $2) that will complete
# the 'agi' alias. (complete -F _apt_get_install agi)
#
function make-completion-wrapper () {
    local function_name="$2"
    local arg_count=$(($#-3))
    local comp_function_name="$1"
    shift 2
    local function="
function $function_name {
    ((COMP_CWORD+=$arg_count))
    COMP_WORDS=( "$@" \${COMP_WORDS[@]:1} )
    "$comp_function_name"
    return 0
}"
    eval "$function"
}

# and now the commands that are specific to this SO question

alias gco='git checkout'

# we create a _git_checkout_mine function that will do the completion for "gco"
# using the completion function "_git"
make-completion-wrapper _git _git_checkout_mine git checkout

# we tell bash to actually use _git_checkout_mine to complete "gco"
complete -o bashdefault -o default -o nospace -F _git_checkout_mine gco

此解决方案类似于balshetzer的脚本,但只有该解决方案对我有效。(balshetzer的脚本在使用某些别名时出现问题。)


;这几乎可行-我遇到了几个错误,但是完成过程还是很顺利的。我还能做什么? -bash: eval: line 28: unexpected EOF while looking for matching ''' -bash: eval: line 29: syntax error: unexpected end of file
pforhan 2011年

@pforhan我可以在上面看到引号问题... 字符串中的"引号function应引为\"。这可能会吃掉您的'报价中的某处。
汤姆·黑尔

5

另一种选择是使用~/.bash_completion文件。要创建gco别名,git checkout只需将其放入其中:

_xfunc git __git_complete gco _git_checkout

然后,~/.bashrc您只需要输入别名本身:

alias gco='git checkout'

两行。而已。

说明:

这些~/bash_completion获取来自主bash_completion脚本末尾。我在gentoo中找到了主要脚本/usr/share/bash-completion/bash_completion

_xfunc git位负责git-completion为您寻找文件,因此您无需放入任何其他内容~/.bashrc

接受的答案要求您.git-completion.sh~/.bashrc我认为很me脚的文件中复制并获取它。


PS:我仍在尝试弄清楚如何不将整个git-completion脚本提供到我的bash环境中。如果找到方法,请发表评论或编辑。


为什么_xfunc git需要?
汤姆·黑尔

@TomHale我试图改善答案。与其做,source ~/.git-completion.sh_xfunc不为我做。仅在.NET中感觉更好,更干净~/.bash_completion。没有_xfunc(或采购)__git_complete功能将不存在。
kub1x

1
不需要~/.bash_completion文件-该_xfunc行对我有效.bashrc
汤姆·黑尔

2

您只需要找到 complete命令并复制具有别名的行即可。

我有alias d-m="docker-machine"。换句话说,d-m应为的别名docker-machine

因此,在Mac上(通过brew),完成文件位于中cd `brew --prefix`/etc/bash_completion.d/
就我而言,我编辑了名为的文件docker-machine
一直到底部:

complete -F _docker_machine docker-machine

所以我刚刚添加了另一行,并加上了别名:

complete -F _docker_machine docker-machine
complete -F _docker_machine d-m

这是简单(一对一)别名(例如docker别名为)的最佳解决方案d。虽然对于问题中的示例,git checkout别名gco为更复杂。
wisbucky

1

首先,查找原始的完成命令。例:

$ complete | grep git

complete -o bashdefault -o default -o nospace -F __git_wrap__git_main git

现在将它们添加到您的启动脚本中(例如〜/ .bashrc):

# copy the original statement, but replace the last command (git) with your alias (g)
complete -o bashdefault -o default -o nospace -F __git_wrap__git_main g

# load dynamically loaded completion functions (may not be required)
_completion_loader git

_completion_loader行可能不是必需的。但是在某些情况下,仅在键入命令并TAB第一次按下后才动态加载完成功能。因此,如果您未使用原始命令,并尝试使用别名+ TAB,则可能会收到诸如“ bash:complete:function'_docker'not found”的错误。


1

这个问题有很多答案,像我一样,我打赌很多困惑的读者。就我而言,我还要求将点文件在具有不同版本Git的多个平台上工作。我也没有,alias g=git但是有g定义为一个函数。

为了实现这一点,我不得不将这里的不同答案组合成一个解决方案。尽管这已经重申了答案,但我认为我的船上有人可能会像我初次提出该问题时那样会发现此汇编有用。

假设使用的是旧版本和较新版本的Git,Ubuntu默认设置以及brew install git在MacOS上。在后一种情况下,bash不会处理brew安装的完成项(稍后我会诊断)。

# Alias g to git

g() {
  if [[ $# > 0 ]]; then
    git "$@"
  else
    git status -sb
  fi
}

# Preload git completion in Ubuntu which is normally lazy loaded but we need
# the __git_wrap__git_main function available for our completion.
if [[ -e /usr/share/bash-completion/completions/git ]]; then
  source /usr/share/bash-completion/completions/git
elif [[ -e /usr/local/etc/bash_completion.d/git-completion.bash ]]; then
  source /usr/local/etc/bash_completion.d/git-completion.bash
fi

if command_exists __git_complete; then
  __git_complete g _git
elif command_exists __git_wrap__git_main; then
  complete -o bashdefault -o default -o nospace -F __git_wrap__git_main g
fi

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.