自定义bash完成输出:每行建议新行

前端之家收集整理的这篇文章主要介绍了自定义bash完成输出:每行建议新行前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
当您输入内容时,您经常使用bash自动完成:例如,您开始编写命令,然后键入TAB以获取其余的单词。

您可能已经注意到,当多个选项与您的命令匹配时,bash显示如下:

foobar@myserv:~$ admin-
admin-addrsync         admin-adduser          admin-delrsync         admin-deluser          admin-listsvn
admin-addsvn           admin-chmod            admin-delsvn           admin-listrsync

我正在寻找一种解决方案来显示新行上的每个可能的解决方案,类似于ls -l上的最后一列。更好的是,如果我可以应用这样的规则,这将是完美的:“如果您发现少于10个建议,请逐行显示,如果更多=>实际显示”。

4.2之前的bash不允许对完成的输出格式进行任何控制,不幸的是。

Bash 4.2允许在全球范围内切换到1行建议的输出,如Grisha Levit’s helpful answer所述,它也链接clever workaround以实现每个完成功能解决方案。

以下是自定义完成的棘手解决方法
解决这个问题一般来说,对于所有定义的完成,将会更加困难(如果有一种方法可以直接调用readline函数,可能会更容易,但是我没有找到一种方法)。

测试下面的概念证明:

>保存到文件并将其(。文件)导入到交互式shell中 – 这将:

>定义一个名为foo的命令(一个shell函数)
>其参数根据当前目录中的匹配文件名完成。
>(当foo实际被调用时,它只是以诊断形式打印其参数。)

>调用为:
foo [fileNamePrefix],然后按Tab键:

>如果当前目录中的2到9个文件匹配,您将看到所需的逐行显示
>否则(1场比赛或10场以上比赛),将会正常完成。

限制:

>仅在正在编辑的命令行上应用于LAST参数时,完成才能正常工作。
>当完成实际插入到命令行中(一旦匹配是明确的),则不附加空格(解决方法需要此行为)。
>打印自定义格式化输出后第一次重新提示提示可能无法正常工作:重新绘制包含提示的命令行必须被模拟,因为没有直接方法获取存储在$ PS1中的提示定义字符串的扩展版本,使用了一个解决方案(灵感来自http://stackoverflow.com/a/24006864/45375),它应该在典型的情况下工作,但不是万无一失的。

做法:

>定义和分配一个自定义完成shell函数到感兴趣的命令。
>自定义函数确定匹配,如果它们的计数在所需的范围内,则绕过正常完成机制并创建自定义格式的输出
>自定义格式的输出(每行匹配在自己的行上)直接发送到终端> / dev / tty,然后提示符和命令行手动“重绘”以模拟标准完成行为。
>请参阅源代码中的注释以了解实现细节。

# Define the command (function) for which to establish custom command completion.
# The command simply prints out all its arguments in diagnostic form.
foo() { local a i=0; for a; do echo "\$$((i+=1))=[$a]"; done; }

# Define the completion function that will generate the set of completions
# when <tab> is pressed.
# CAVEAT:
#  Only works properly if <tab> is pressed at the END of the command line,#  i.e.,if completion is applied to the LAST argument.
_complete_foo() {

  local currToken="${COMP_WORDS[COMP_CWORD]}" matches matchCount

  # Collect matches,providing the current command-line token as input.
  IFS=$'\n' read -d '' -ra matches <<<"$(compgen -A file "$currToken")"

  # Count matches.
  matchCount=${#matches[@]}

  # Output in custom format,depending on the number of matches.
  if (( matchCount > 1 && matchCount < 10 )); then

      # Output matches in CUSTOM format:
      # print the matches line by line,directly to the terminal.
    printf '\n%s' "${matches[@]}" >/dev/tty
      # !! We actually *must* pass out the current token as the result,# !! as it will otherwise be *removed* from the redrawn line,# !! even though $COMP_LINE *includes* that token.
      # !! Also,by passing out a nonempty result,we avoid the bell
      # !! signal that normally indicates a Failed completion.
      # !! However,by passing out a single result,a *space* will
      # !! be appended to the last token - unless the compspec
      # !! (mapping established via `complete`) was defined with 
      # !! `-o nospace`.
    COMPREPLY=( "$currToken" )
      # Finally,simulate redrawing the command line.
        # Obtain an *expanded version* of `$PS1` using a trick
        # inspired by http://stackoverflow.com/a/24006864/45375.
        # !! This is NOT foolproof,but hopefully works in most cases.
    expandedPrompt=$(PS1="$PS1" debian_chroot="$debian_chroot" "$BASH" --norc -i </dev/null 2>&1 | sed -n '${s/^\(.*\)exit$/\1/p;}')
    printf '\n%s%s' "$expandedPrompt" "$COMP_LINE" >/dev/tty


  else # Just 1 match or 10 or more matches?

      # Perform NORMAL completion: let bash handle it by 
      # reporting matches via array variable `$COMPREPLY`.
    COMPREPLY=( "${matches[@]}" )    

  fi 

}

# Map the completion function (`_complete_foo`) to the command (`foo`).
# `-o nospace` ensures that no space is appended after a completion,# which is needed for our workaround.
complete -o nospace -F _complete_foo -- foo

猜你在找的Bash相关文章