gpt4 book ai didi

bash - 自定义 bash 完成输出 : each suggestion on a new line

转载 作者:行者123 更新时间:2023-11-29 08:44:44 24 4
gpt4 key购买 nike

当您键入内容时,您通常会使用 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 个建议,则逐行显示它们,如果更多 => 实际显示”.

最佳答案

不幸的是,

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

Bash 4.2+ 允许切换到每行输出 1 个建议全局,如 Grisha Levit's helpful answer 中所述,它也链接到一个 clever workaround实现每个完成函数解决方案。

以下是自定义完成的棘手解决方法一般性地解决这个问题,对于所有定义的完成,将困难得多(如果有一种方法可以调用readline 直接运行,这可能更容易,但我还没有找到这样做的方法)。

测试下面的概念验证:

  • 保存到一个文件并在您的交互式 shell 中获取它(.file)——这将:
    • 定义一个名为 foo 的命令(一个 shell 函数)
    • 其参数根据当前目录中的匹配文件名完成。
    • (当实际调用 foo 时,它只是以诊断形式打印其参数。)
  • 调用为: foo [fileNamePrefix],然后按 tab:
    • 如果当前目录中有 2 到 9 个文件匹配,您将看到所需的逐行显示。
    • 否则(1 场比赛或 10 场或更多场比赛),将正常完成。

限制:

  • 补全仅在应用于正在编辑的命令行上的 LAST 参数时才能正常工作。
  • 当在命令行中实际插入完成时(一旦匹配明确),不会向其附加空格(解决方法需要此行为)。
  • 在打印自定义格式的输出后第一次重绘提示可能无法正常工作:重绘包括提示在内的命令行必须模拟并且因为没有直接的方法来获得 $PS1 中存储的提示定义字符串的扩展 版本,使用了解决方法(受 https://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 https://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 - 自定义 bash 完成输出 : each suggestion on a new line,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24781739/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com