read -r
のみ POSIXで指定 ; NUM
文字の読み取りに使用されるread -n NUM
は、そうではありません。 stdinから指定された数の文字を読み取った後に自動的に戻るポータブルな方法はありますか?
私のユースケースは、次のようなプロンプトを出力しています:
Do the thing? [y/n]
可能であれば、y
またはn
を入力した後、ユーザーが後でEnterキーを押す必要なく、プログラムを自動的に続行させたいと思います。
1文字を読み取るとは、完全な文字を取得するまで、一度に1バイトを読み取ることです。
POSIXツールチェストで1バイトを読み取るために、dd bs=1 count=1
があります。
ただし、端末デバイスがicanon
モードの場合(通常はデフォルト)、端末デバイスからの読み取りは、 Return (別名 Enter)それまでは、端末のデバイスドライバーは、使用できるラインエディターの形式を実装しているため Backspace または入力した内容を修正するためのその他の編集文字。入力した内容は、編集中の行を送信したときにのみ、読み取りアプリケーションで使用できるようになります( Return または Ctrl+D)。
そのため、ksh
のread -n/N
またはzsh
のread -k
は、stdinが端末デバイスであることを検出したら、そのデバイスをicanon
モードから外します。 、端末から送信されるとすぐにバイトを読み取ることができるようにします。
ここで、ksh
のread -n n
はpからn
文字1行からのみを読み取りますが、改行すると停止します。文字が読み取られます(-N n
を使用してn
文字を読み取ります)。 bash
は、ksh93とは異なり、-n
と-N
の両方に対してIFSおよびバックスラッシュ処理を実行します。
zsh
のread -k
またはksh93
のread -N1
またはbash
のIFS= read -rN 1
を模倣する、つまり、POSIXlyのstdinから1文字だけを読み取る:
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
}
this answer ...から引用すると、これは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