Shell 脚本通过 Enter 键和 Tab 键接受“读取”

Shell 脚本通过 Enter 键和 Tab 键接受“读取”

在 shell 脚本中,当您有以下内容时:

read my_variable

Enter是保存您输入的键。

有没有办法在不删除 的功能的情况Tab下完成相同的任务?EnterEnter

答案1

它可能有点过分,但您可以通过使用来获得它read -e,这会启用实用程序上的 Readline 工具read。那时,您只需按一下键即可得到想要的结果。

但要小心的是,Readline 还带来了许多其他功能,例如完成、历史记录等,对于简单的read my_variable.如果这些是不需要的,您必须显式清除键绑定并禁用您不需要的功能read -e

来自命令行的概念验证示例:

(bind 'TAB: accept-line'; IFS= read -re var && echo "$var" || echo ko)

您也可以在脚本中执行此操作,尽管bind会发出警告(您仍然可以通过重定向将其静音2>/dev/null)。

脚本中命令的替代方法bind是在调用您希望受影响的脚本之前提供自定义 inputrc 文件。不需要真正的文件,一个 Here Document 就足够了。

上面的例子是通过脚本实现的:

#!/bin/bash

export INPUTRC=/dev/fd/3

script2.sh 3<<EOF
TAB: accept-line
set history-size 0
EOF
# this example 'inputrc'-like file also disables history support

上面的脚本将自定义 inputrc 文件准备为文件描述符 3 上的 Here Document,运行的 shellscript2.sh将按照INPUTRC环境变量的指示读取该文件。

然后script2.sh

#!/bin/bash

echo start
bind -q accept-line 2>/dev/null  # shows which keys are configured to accept input
IFS= read -re var && echo "$var" || echo ko
echo end

在等待输入之前read,脚本将打印如下内容:

accept-line can be invoked via "\C-i", "\C-j", "\C-m".

显示TabCtrl-I即上面显示的\C-i)接受一行以及Return(即Ctrl-M回车)或换行符(Ctrl-J)。

对于一个更“真实世界”的例子:

#!/bin/bash

bind 'TAB: accept-line' &>/dev/null

echo "enter your name:"
IFS= read -re var 

echo "your name is: $var"

如果您沿着这条路走下去,请看一下Readline 用户指南,至少你的 中减少了一项man bashset convert-meta off为了更好地支持非 ASCII 字符,其中的设置可能值得特别提及。

答案2

通常可以完成的方法是将 // 特殊字符(“备用行尾”)设置为termios(3)Tab 。在支持它的系统上,也可以使用/ 。stty(1) VEOLeolVEOL2eol2

不幸的是,read内置的 shell 总是尝试读取换行符(或bashif中-d使用的另一个分隔符,不支持多个分隔符)。

可以解决的一种方法是使用var=$(dd count=1 bs=big)命令替换而不是read.下面是这种拼凑的一个例子:

while :; do

        t=$(stty -g)
        stty eol ^I
        trap : INT
        var=$(dd bs=10k count=1 2>/dev/null; echo x)
        stty "$t"
        trap - INT
        var=${var%x}
        [ "$var" ] || break
        var=${var%[$'\n\t']}

        printf '{%s}\n' "$var"

done

t=(stty -g)stty "$t"保存和恢复终端设置。

andtrap : INTtrap - INT阻止 Control-C 杀死 shell/循环(以及随之而来的所有复杂性和特定于 shell 的行为),并让它只杀死ddand 命令替换。

接下来$(...; echo x)${var%x}一个防止尾随换行符从命令替换中被删除的技巧;为了能够区分用户仅按下Enter空变量和Control-C/或Control-D退出循环,这是必要的。

最后,将从${var%[$'\n\t']}变量中删除尾随的换行符或制表符。在不支持or$'...'等​​字符串的shell 中,可以将其替换为:dashyash

nltab='<literal tab here>
'
...
var=${var%[$nltab]}

相关内容