举个例子:
我是一个在mac上的bash v3.2.17,我使用的git安装通过macports与bash_completion变体。
当我输入git checkout m<tab>。例如,我把它完成了。
然而,我有一个别名git结帐,gco。当我输入gco m<tab>时,我没有得到自动完成的分支名称。
理想情况下,我想自动完成只是神奇地为我所有的别名工作。这可能吗?如果做不到这一点,我想为每个别名手动定制它。那么,我该怎么做呢?
举个例子:
我是一个在mac上的bash v3.2.17,我使用的git安装通过macports与bash_completion变体。
当我输入git checkout m<tab>。例如,我把它完成了。
然而,我有一个别名git结帐,gco。当我输入gco m<tab>时,我没有得到自动完成的分支名称。
理想情况下,我想自动完成只是神奇地为我所有的别名工作。这可能吗?如果做不到这一点,我想为每个别名手动定制它。那么,我该怎么做呢?
在git-completion。Bash有一行:
complete -o default -o nospace -F _git git
查看这一行(和_git函数),你可以将这一行添加到你的.bash_profile:
complete -o default -o nospace -F _git_checkout gco
您还可以尝试使用Git别名。例如,在我的~/。gitconfig文件,我有一个看起来像这样的部分:
[alias]
co = checkout
所以你可以输入git com <TAB>,这应该扩展到git co master,这是git checkout命令。
我也遇到了这个问题,并提出了这个代码片段。这将自动为您提供所有别名的补全。在声明所有(或任何)别名后运行它。
# 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
这个论坛页面展示了一个解决方案。
把这些行放到你的.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的脚本,但只有这个对我有效。(巴尔谢策的脚本对我的一些别名有问题。)
我有一个别名g='git',结合我的git别名,我键入如下内容
$ g co <branchname>
对于我的特定用例,更简单的解决方法是在git-completion中添加一行代码。
就在这条线下面:
__git_complete git _git
我添加了这一行来处理我的单个'g'别名:
__git_complete g _git
如上面的评论所述,
complete -o default -o nospace -F _git_checkout gco
将不再工作。然而,在git-completion中有一个__git_complete函数。Bash可以用来为别名设置补全,如下所示:
__git_complete gco _git_checkout
另一个选项是使用~/。bash_completion文件。要创建git checkout的gco别名,只需输入以下内容:
_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完成文件,因此您不需要在~/.bashrc中放入任何其他内容。
接受的答案要求您复制.git- complete .sh并从~/中获取它。bashrc文件,我发现蹩脚。
PS:我仍在努力弄清楚如何不将整个git-completion脚本源到我的bash环境中。如果你找到了方法,请评论或编辑。
您只需要找到完整的命令并复制具有别名的行即可。
我有别名d-m=“码头机”。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
理想情况下,我想自动完成只是神奇地为我所有的别名工作。这可能吗?
是的,对于complete-alias项目(在Linux上),这是可能的。对Mac的支持是实验性的,但用户已经报告成功。
首先,查找原始的补全命令。例子:
$ 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之后才会动态加载。因此,如果你没有使用原始命令,并尝试alias + TAB,你可能会得到一个错误,如“bash: completion: function '_docker' not found”。
这个问题有很多答案,就像我自己一样,我打赌很多读者都很困惑。对于我来说,我还需要让我的dotfile在多个平台上使用不同版本的Git。我也没有使用g=git的别名,而是将g定义为一个函数。
为了做到这一点,我必须把不同的答案拼凑成一个解决方案。虽然这重复了之前的答案,但我认为在我的船上的人可能会发现这个汇编很有用,就像我第一次遇到这个问题时一样。
这假设旧的和新的Git完成,Ubuntu默认,并在MacOS上brew安装Git。在后一种情况下,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
Felipe Contreras对Git补全功能(参见Git 2.30中的Zsh补全)非常积极,他提出(可能是Git 2.31, Q1 2021)一个公共函数将有助于别名自动补全。
他的建议:
Back in 2012 I argued for the introduction of a helper that would allow users to specify aliases like: git_complete gf git_fetch Back then there was pushback because there was no clear guideline for public functions (git_complete vs _git_complete vs _GIT_complete), and some aliases didn't actually work. Fast-forward to 2020 and there's still no guideline for public functions, and those aliases still don't work (even though I sent the fixes). This has not prevented people from using this function that is clearly needed to setup custom aliases (this page), and in fact it's the recommended way. But it is cumbersome that the user must type: __git_complete gf _git_fetch Or worse: __git_complete gk __gitk_main 8 years is more than enough time to stop waiting for the perfect to come; let's define a public function (with the same name) that is actually user-friendly: __git_complete gf git_fetch __git_complete gk gitk While also maintaining backwards compatibility. The logic is: If $2 exists, use it directly If not, check if __$2_main exists If not, check if _$2 exists If not, fail
您可以将Tab绑定到alias-expand-line并在~/.inputrc中完成(它的默认动作)。要做到这一点,你首先需要将每个动作绑定到一个键,然后将它们链接在一起:
"\M-z":alias-expand-line
"\M-x":complete
TAB:"\M-z\M-x"
你可以使用任何你喜欢的组合键,我使用元键,因为它是免费的。更多信息见男子3阅读线。
现在,如果你打开一个新终端,输入别名:
gco m<TAB>
线路将被改造成
git checkout master
当然,即使不涉及别名,Tab也将照常工作。
我知道这个问题是关于bash的,但如果你使用zsh,这个改变@hesky-fisher回答将修复它。
From
# 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'\'' /')"
to:
# For each defined alias, extract the necessary elements and use them
# to call wrap_alias.
eval "$(alias | sd '^([^=]+)=(.+)' 'wrap_alias $1=$2')"
你需要sd(这可以用sed代替,但sd在我看来更好)
这样做是因为zsh没有别名-p,并且zsh中的别名输出不输出
alias <something>=<value>
就像在狂欢,但是
<something>=<value>
顺便说一下,我把初始化代码放在。zlogin文件中