在 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".
显示Tab(Ctrl-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 bash
。set convert-meta off
为了更好地支持非 ASCII 字符,其中的设置可能值得特别提及。
答案2
通常可以完成的方法是将 // 特殊字符(“备用行尾”)设置为termios(3)
Tab 。在支持它的系统上,也可以使用/ 。stty(1)
VEOL
eol
VEOL2
eol2
不幸的是,read
内置的 shell 总是尝试读取换行符(或bash
if中-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 : INT
将trap - INT
阻止 Control-C 杀死 shell/循环(以及随之而来的所有复杂性和特定于 shell 的行为),并让它只杀死dd
and 命令替换。
接下来$(...; echo x)
是${var%x}
一个防止尾随换行符从命令替换中被删除的技巧;为了能够区分用户仅按下Enter
空变量和Control-C
/或Control-D
退出循环,这是必要的。
最后,将从${var%[$'\n\t']}
变量中删除尾随的换行符或制表符。在不支持or$'...'
等字符串的shell 中,可以将其替换为:dash
yash
nltab='<literal tab here>
'
...
var=${var%[$nltab]}