可以在zsh中使用Bash制表符完成脚本吗?


87

我有一个用于Apache Hadoop的Bash制表符补全脚本。通常,我将zsh用作日常外壳。当我需要它时,它往往看上去很像bash,但是看起来它们之间的制表符完成系统根本不同。有没有一种简单的方法可以“转换”现有的bash-tab-completion定义以使其在zsh中工作?我不想为此花很多时间,但是如果简单的话,我会省些力气。

Answers:


39

从此页面(日期为2010/01/05):

Zsh可以处理bash补全功能。zsh的最新开发版本具有bashcompinit函数,该函数在运行时将允许zsh读取bash完成规范和函数。zshcompsys手册页中对此进行了记录。要使用它,您需要做的就是在compinit之后的任何时间运行bashcompinit。它将定义与bash内置程序相对应的complete和compgen函数。


好消息:我认为这应该可行,非常感谢。坏消息:由于某种原因,当我通过SSH登录时,我试图在其上完成此操作的系统似乎未加载/ etc / zshrc。我对登录过程了解不足,无法说明为什么会这样。也许是时候问另一个问题了……
Coderer

1
@Coderer:首先,您说“ / etc / zshrc”。在我的系统上是/etc/zsh/zshrc。此外,还要检查以下文件以相反的顺序(在他们的zsh启动期间货源的顺序排列): ,,和(可能),看看是否变量为no。如果是的话,那将防止源于未设置该文件的文件之后的后续文件。最后,检查用户所在的外壳程序,并确保该外壳程序没有参数。/etc/zsh/zshenv$ZDOTDIR/.zshenv/etc/zsh/zprofile$ZDOTDIR/.zprofile~/.zprofileRCS/etc/passwdzsh-f
暂停,直到另行通知。

感谢所有反馈-我求助于#1经典程序员hack,“ stdout调试”(每个启动脚本中的echo语句),然后发现了问题。出于某种原因,我们的/ etc / zprofile采购了各种/etc/profile.d脚本,然后再次从/ etc / zshrc中获取它们。只需将自动加载语句移动到/ etc / zprofile的顶部即可解决此问题。
Coderer

157
autoload bashcompinit
bashcompinit
source /path/to/your/bash_completion_file

10
这是更好的答案,因为它告诉您如何使用bashcompinit。不错的工作。
pyrospade

5
谢谢,很好的答案,不幸的是,如果脚本使用_init_completion bash命令,则此方法不起作用。
0fnt 2014年

6
这对我不起作用。我仍然遇到complete:13: command not found: compdef错误。
贾汀·库马尔

如果它不起作用,请检查脚本(doh :))-可能if is-bash在顶部有一个勾号。
olejorgenb

对于某些_get_comp_words_by_ref未使用定义的脚本,这不起作用bashcompinit。不过,大多数补全不使用此功能。
富兰克林·于

39
autoload -U +X compinit && compinit
autoload -U +X bashcompinit && bashcompinit
source /path/to/your/bash_completion_script

我正在zsh 5.0.2 (x86_64-apple-darwin13.0) 不带任何〜/ .zshrc的情况下运行zsh 并且以上序列在新近产生的zsh shell中起作用。

感谢git-completion.bash脚本的提示:D


请继续阅读以获取上述3行的更多详细信息:

Bash有内置的自动完成支持真棒但zsh的环境不具备基本的bash自动完成辅助功能喜欢的bash脚本自动完成不直接工作的zsh compgencomplete。这样做是为了保持zsh会话的快速。

这些天,zsh附带了适当的完成脚本,例如compinitbashcompinit,它们具有支持bash自动完成脚本的必需功能。

autoload <func_name>注意:自动加载是在zsh中定义的,而不是bash。autoloadfpath命令返回的目录路径中查找命名的文件,并标记一个函数,使其在首次调用时加载该文件。

  • -U:加载诸如compinit或bashcompinit之类的函数时,忽略任何别名
  • + X:只需立即加载命名函数就不要执行

例如在我的系统echo $fpath恢复/usr/share/zsh/site-functions/usr/share/zsh/5.0.5/functions无一不compinitbashcompinit可在/usr/share/zsh/5.0.5/functions

而且对于大多数人来说可能只是autoload -U +X bashcompinit && bashcompinit需要的,因为其他一些脚本(例如git autocomplete或他们自己的脚本~/.zshrc可能正在执行)autoload -U +X compinit && compinit,但是只运行两个脚本是安全的。


什么是-U+X呢?
jmk 2015年

更新的答案具有更多详细信息。
贾汀·库玛

6
这仍然毫无意义。该手册页描述了+X foo执行与调用时相同的自动加载foo,但是没有立即执行它的意义……因此autoload +X foo && foo似乎完全多余。您能解释一下为什么选择这种模式吗?
ELLIOTTCABLE

2
@ELLIOTTCABLE这样做的autoload -U +X bashcompinit && bashcompinit目的是(由于&&)它将bashcompinit在实际找到该模块的情况下执行IFF。正常autoload foo总是返回true。后来,当你尝试运行foo然后zsh的最后告诉你“没有找到函数定义文件”。随着autoload +X您立即得到错误。
FeRD

1
在我看来,手册页在这一点上尚不清楚:autoload +X在不执行函数的情况下加载函数-这比不使用时要。没有,autoload甚至不会加载该函数。它仅将名称标记为引用稍后要加载的函数。在首次调用该函数之前,不会尝试实际加载。如果要确定命名函数是否成功加载,则需要使用来立即执行加载步骤。autoload+X+X+X
FeRD

4

对于zsh使用:

  • compdef
  • compadd

我的例子:

# bash completion for bxrun (/home/ecuomo/projects/bashx/bxrun)
_bxrun_methods() {
    grep "^\s*\(function\s\+\)\?__.\+()\s*{.*$" "${1}" | while read line ; do
        echo "$line" | sed "s/()\s*{.*//g" | sed "s/\s*\(function\s\+\)\?__//g"
    done
}
_bxrun_lst() {
    if [ -d "/home/ecuomo/projects/bashx/src/actions" ]; then
        for f in /home/ecuomo/projects/bashx/src/actions/* ; do
            if [ -f "${f}" ]; then
                basename "${f}" | sed 's/\..*$//g'
            fi
        done
    fi
    _bxrun_methods "/home/ecuomo/projects/bashx/bxrun"
    _bxrun_methods "/home/ecuomo/projects/bashx/src/bashx.sh"
}
_bxrun() {
    local cur
    COMPREPLY=()
    cur=${COMP_WORDS[COMP_CWORD]}
    COMPREPLY=( $( compgen -W '$( _bxrun_lst )' -- $cur  ) )
}
_bxrun_zsh() {
    compadd `_bxrun_lst`
}
if type complete >/dev/null 2>/dev/null; then
    # bash
    complete -F _bxrun bxrun
else if type compdef >/dev/null 2>/dev/null; then
    # zsh
    compdef _bxrun_zsh bxrun
fi; fi

来源:我的代码https://github.com/reduardo7/bashx


1
您应该披露自己是链接的bashx框架的作者。
2016年

4

我将Antigen作为Oh-My-Zsh插件管理器运行。我有一些同事写的bash完成脚本,我想用一个简单的脚本加载到Zsh中source /path/to/completion

我遇到了一些麻烦,因为似乎Antigen或OMZ(很难说)只关心从插件中加载完成脚本。我终于通过自动加载bashcompinit compinit之后解决了这个问题antigen apply。仅仅自动加载bashcompinit是不够的。

source ~/.antigen/antigen.zsh
antigen use oh-my-zsh
antigen apply

autoload -U +X compinit && compinit
autoload -U +X bashcompinit && bashcompinit

source /path/to/bash_completion

Antigen创建的.zcompdump文件$ANTIGEN_COMPDUMP对我来说是~/.antigen/.zcompdump

重新调用compinit和bashcompinit会在以下位置创建第二个.zcompdump $HOME/.zcompdump

似乎可以解决所有问题,因为我可以使用设置的完成功能/path/to/bash_completion。我已经删除了两个.zcompdump文件几次,以确保它们已重新生成并且似乎可以正常工作。

由于尝试制表完成时抛出错误,我不得不在计算机重新启动后rm .zcompdump文件几次,但是我不确定这是由于此设置还是其他原因。rm ~/.zcompdump && rm $ANTIGEN_COMPDUMP一个新的外壳为我解决了这个问题。

撰写本文时使用的版本:

Antigen = v2.2.3 = d3d4ee0
Oh-my-zsh = c3b072e
Zsh = 5.3

0

@JatinKumar的回答使我处在正确的轨道上,但我不得不使用complete而不是source。所以一起:

autoload -Uz compinit && compinit
autoload -U +X bashcompinit && bashcompinit

complete -C /usr/local/bin/terraform terraform
complete -C /usr/local/aws/bin/aws_completer aws
complete -C /usr/local/bin/az az
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.