【问题标题】:Can a Bash tab-completion script be used in zsh?可以在 zsh 中使用 Bash 选项卡完成脚本吗?
【发布时间】:2011-03-16 00:48:31
【问题描述】:

我有一个用于 Apache Hadoop 的 Bash 选项卡完成脚本。通常,我使用 zsh 作为我的日常 shell。当我需要它时,它往往非常类似于 bash,但看起来它们之间的制表符完成系统完全不同。有没有一种简单的方法可以“转换”现有的 bash-tab-completion 定义以在 zsh 中工作?我不想在这方面投入大量时间,但如果这很容易,我会节省一些精力。

【问题讨论】:

    标签: bash zsh tab-completion


    【解决方案1】:
    autoload bashcompinit
    bashcompinit
    source /path/to/your/bash_completion_file
    

    【讨论】:

    • 这是更好的答案,因为它告诉您如何使用 bashcompinit。干得好。
    • 谢谢,很好的答案,不幸的是,如果脚本使用 _init_completion bash 命令,这将不起作用。
    • 这对我不起作用。我仍然收到complete:13: command not found: compdef 错误。
    • 如果它不起作用,请检查脚本 (doh :)) - 它可能在顶部有一个 if is-bash 检查。
    • @FranklinYu,你能解决吗,我也面临同样的问题,我的原始问题已结束,有利于这个问题:(
    【解决方案2】:
    autoload -U +X compinit && compinit
    autoload -U +X bashcompinit && bashcompinit
    source /path/to/your/bash_completion_script
    

    我正在运行 zsh zsh 5.0.2 (x86_64-apple-darwin13.0) 没有任何 ~/.zshrc 并且上述序列在新生成的 zsh shell 中运行。

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


    阅读以上 3 行的更多详细信息:

    Bash 有很棒的内置自动完成支持,但是 bash 自动完成脚本不能直接在 zsh 中运行,因为 zsh 环境没有基本的 bash 自动完成辅助函数,例如 compgencomplete。这样做是为了让 zsh 会话保持快速。

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

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

    • -U: 在加载 compinit 或 bashcompinit 等函数时忽略任何别名
    • +X:现在只加载命名函数fow,不要执行它

    例如,在我的系统上,echo $fpath 返回 /usr/share/zsh/site-functions/usr/share/zsh/5.0.5/functionscompinitbashcompinit 都可以在 /usr/share/zsh/5.0.5/functions 获得。

    另外,对于大多数人来说,可能只需要 autoload -U +X bashcompinit && bashcompinit,因为 git 自动完成或他们自己的 ~/.zshrc 等其他脚本可能正在执行 autoload -U +X compinit && compinit,但同时运行它们是安全的。

    【讨论】:

    • -U+X是干什么用的?
    • 更新了更多细节的答案。
    • 这仍然没什么意义;手册页描述了+X foo 的要点,就像调用foo 一样执行相同的自动加载,但没有立即执行它……所以autoload +X foo && foo 似乎完全多余。你能解释一下为什么选择这种模式吗?
    • @ELLIOTTCABLE 执行autoload -U +X bashcompinit && bashcompinit 的意义在于(由于&&)它将执行bashcompinit IFF 模块实际找到。正常 autoload foo 总是返回 true。后来,当你尝试运行foo 时,然后 zsh 最终告诉你“找不到函数定义文件”。使用autoload +X,您会立即收到错误消息。
    • 手册页在这一点上仍然有些不清楚,在我看来:autoload +X 加载函数而不执行它 - 这比 autoload 执行的操作更多,没有+X。没有+X,自动加载甚至不会加载函数;它只是将名称标记为引用稍后要加载的函数。在第一次调用该函数之前,不会尝试实际加载。如果要判断命名函数是否加载成功,需要使用+X立即执行加载步骤。
    【解决方案3】:

    来自this page(2010/01/05):

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

    【讨论】:

    • 好消息:我认为这应该可行,非常感谢。坏消息:由于某种原因,当我通过 SSH 登录时,我试图在其上完成此操作的系统似乎没有加载 /etc/zshrc。我对登录过程知之甚少,无法说明为什么会这样。也许是时候问另一个问题了……
    • @Coderer:首先,你说“/etc/zshrc”。在我的系统上,它是/etc/zsh/zshrc。另外,以相反的顺序检查以下文件(在 zsh 启动期间按它们的来源顺序列出):/etc/zsh/zshenv$ZDOTDIR/.zshenv/etc/zsh/zprofile$ZDOTDIR/.zprofile(可能是~/.zprofile)以查看RCS变量未设置。如果是这样,那将阻止在其中未设置的文件之后的后续文件被获取。最后,检查/etc/passwd 中用户的shell 并确保它是zsh 并确保它没有-f 参数。
    • 感谢所有反馈——我求助于#1 经典程序员技巧“stdout 调试”(每个启动脚本中的回显语句)并找到了问题。出于某种原因,我们的 /etc/zprofile 正在获取各种 /etc/profile.d 脚本,然后在 /etc/zshrc 中再次获取这些脚本。只需将自动加载语句移动到 /etc/zprofile 的顶部即可解决问题。
    【解决方案4】:

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

    我遇到了一些麻烦,因为似乎 Antigen 或 OMZ(很难说)只关心从他们的插件加载完成脚本。我终于通过在antigen apply 之后自动加载bashcompinit compinit 来解决这个问题。仅仅自动加载 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 在$ANTIGEN_COMPDUMP 创建它的.zcompdump 文件,对我来说是~/.antigen/.zcompdump

    重新调用 compinit 和 bashcompinit 在 $HOME/.zcompdump 创建第二个 .zcompdump

    似乎一切都解决了,因为我可以使用/path/to/bash_completion 设置的补全。我已经多次删除了这两个 .zcompdump 文件,以确保它们已重新生成并且似乎可以正常工作。

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

    撰写本文时使用的版本:

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

    【讨论】:

      【解决方案5】:

      对于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

      【讨论】:

      • 您应该披露您是链接的 bashx 框架的作者。
      【解决方案6】:

      @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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-02-14
        • 2012-01-08
        • 2010-10-08
        • 1970-01-01
        • 2013-04-17
        • 1970-01-01
        • 2017-07-03
        相关资源
        最近更新 更多