Ash*_*Ash 7 shell-script posix portability
只有read -r
是通过POSIX规定; read -n NUM
,用于读取NUM
字符,不是。从标准输入读取给定数量的字符后,是否有一种可移植的方式自动返回?
我的用例正在打印这样的提示:
Do the thing? [y/n]
Run Code Online (Sandbox Code Playgroud)
如果可能,我希望程序在键入后自动运行y
或n
,而无需用户随后按 Enter 键。
读取一个字符意味着一次读取一个字节,直到获得一个完整的字符。
要使用 POSIX 工具箱读取一个字节,有dd bs=1 count=1
.
但是请注意,从终端设备读取时,当该设备处于icanon
模式时(通常默认情况下),只有在您按下Return(aka Enter)时才会返回,因为在此之前终端设备驱动程序实现了一种行编辑器形式,允许您使用Backspace或其他编辑字符来修改您输入的内容,并且您输入的内容仅在您提交您一直在编辑的行(使用Return或Ctrl+ D)时才可用于阅读应用程序。
出于这个原因,ksh
'sread -n/N
或zsh
's read -k
,当它们检测到 stdin 是终端设备时,将该设备退出该icanon
模式,以便一旦终端发送字节就可以读取字节。
现在注意ksh
的read -n n
只读取了以n
字符从一个单一的线,它在一个换行符读取(使用仍然停止-N n
读取n
字符)。bash
相反ksh93的,仍然没有两个IFS和反斜线处理-n
和-N
。
要模仿zsh
'sread -k
或ksh93
'sread -N1
或bash
's IFS= read -rN 1
,即从标准输入中读取一个且仅一个字符,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 the last character.
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
}
Run Code Online (Sandbox Code Playgroud)