只不过read -r
是由 POSIX 指定; read -n NUM
,用于读取NUM
字符,不是。从 stdin 读取给定数量的字符后是否有一种可移植的方法自动返回?
我的用例是打印如下提示:
Do the thing? [y/n]
如果可能的话,我希望程序在输入y
或后自动继续n
,而不需要用户随后按 Enter 键。
答案1
读取一个字符意味着一次读取一个字节,直到获得完整的字符。
要使用 POSIX 工具箱读取一个字节,有dd bs=1 count=1
.
但请注意,当该设备处于icanon
模式(通常是默认情况下)时,从终端设备读取数据只会在您按下Return(又名Enter)时返回,因为在此之前,终端设备驱动程序实现了一种行编辑器形式,允许您使用或其他编辑字符来修改您输入的内容,并且仅当您提交正在编辑的行(使用或+ )Backspace时,您输入的内容才可用于阅读应用程序。ReturnCtrlD
因此,ksh
'sread -n/N
或zsh
's read -k
,当它们检测到 stdin 是终端设备时,将该设备退出该icanon
模式,以便终端发送字节后就可以读取它们。
现在请注意,这ksh
只是read -n n
读取向上到n
字符从单行,当读取换行符时它仍然停止(用于-N n
读取n
字符)。bash
,与 ksh93 相反,仍然对-n
和进行 IFS 和反斜杠处理-N
。
模仿zsh
'sread -k
或ksh93
'sread -N1
或bash
's IFS= read -rN 1
,即从 stdin 读取一个且仅一个字符,POSIXly:
readc() { # arg: <variable-name>
if [ -t 0 ]; then
# if stdin is a tty device, put it out of icanon, set min and
# time to sane value, but don't otherwise touch other input or
# or local settings (echo, isig, icrnl...). Take a backup of the
# previous settings beforehand.
saved_tty_settings=$(stty -g)
stty -icanon min 1 time 0
fi
eval "$1="
while
# read one byte, using a work around for the fact that command
# substitution strips trailing newline characters.
c=$(dd bs=1 count=1 2> /dev/null; echo .)
c=${c%.}
# break out of the loop on empty input (eof) or if a full character
# has been accumulated in the output variable (using "wc -m" to count
# the number of characters).
[ -n "$c" ] &&
eval "$1=\${$1}"'$c
[ "$(($(printf %s "${'"$1"'}" | wc -m)))" -eq 0 ]'; do
continue
done
if [ -t 0 ]; then
# restore settings saved earlier if stdin is a tty device.
stty "$saved_tty_settings"
fi
}
答案2
引用自这个答案...这对我来说适用于 bash:
echo -n "Is this a good question (y/n)? "
old_stty_cfg=$(stty -g)
stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg # Careful playing with stty
if echo "$answer" | grep -iq "^y" ;then
echo Yes
else
echo No
fi
答案3
dd 的其他解决方案:
key=$(stty -icanon; dd ibs=1 count=1 2>/dev/null)