単一文字を読む、null<EOF>
と\n
?を区別する方法は?
たとえば、
f() { read -rn 1 -p "Enter a character: " char &&
printf "\nYou entered '%s'\n" "$char"; }
印刷可能な文字を含む:
$ f
Enter a character: x
You entered 'x'
押すときEnter:
$ f
Enter a character:
You entered ''
Ctrl+を押すとD:
$ f
Enter a character: ^D
You entered ''
$
最後の2つのケースの出力が同じ理由は何ですか?どのように区別できますか?
POSIXシェルと比較して他のアプローチはありますかbash
?
ベストアンサー1
(POSIX機能ではありません)stdinread -n "$n"
が端末装置の場合は、端末をそのモードread
から取り出します。それ以外の場合は、ターミナル行ルールの内部行エディタから返された行全体を確認し、一度に1バイトずつ読みます。文字または改行文字を読みました(間違った文字を入力すると、予期しない結果が表示されることがあります)。icanon
read
$n
$n
1行から最大1文字を読みます。また、$IFS
入力からIFS文字が削除されないようにするには、それを消去する必要があります。
icanon
今私たちはパターンから外れたので、もはや^D
特別ではありません。だから押すとCtrl+D文字が読み込まれます。^D
何らかの方法でターミナル接続が切断されない限り、ターミナルデバイスでeofを見ることはできません。 stdinが他の種類のファイルの場合は、eofが表示されることがあります(: | IFS= read -rn 1; echo "$?"
stdinが空のパイプであるか、stdinがからリダイレクトされます/dev/null
)。
read
$n
文字(有効な文字の一部を構成しないバイトは1文字としてカウントされます)、または行全体を読み取ると0が返されます。
したがって、1つの文字のみを要求する特別な場合は、次のようになります。
if IFS= read -rn 1 var; then
if [ "${#var}" -eq 0 ]; then
echo an empty line was read
else
printf %s "${#var} character "
(export LC_ALL=C; printf '%s\n' "made of ${#var} byte(s) was read")
fi
else
echo "EOF found"
fi
POSIXlyは実行するのが非常に複雑です。
これは次のとおりです(EBCDICではなくASCIIベースのシステムを想定)。
readk() {
REPLY= ret=1
if [ -t 0 ]; then
saved_settings=$(stty -g)
stty -icanon min 1 time 0 icrnl
fi
while true; do
code=$(dd bs=1 count=1 2> /dev/null | od -An -vto1 | tr -cd 0-7)
[ -n "$code" ] || break
case $code in
000 | 012) ret=0; break;; # can't store NUL in variable anyway
(*) REPLY=$REPLY$(printf "\\$code");;
esac
if expr " $REPLY" : ' .' > /dev/null; then
ret=0
break
fi
done
if [ -t 0 ]; then
stty "$saved_settings"
fi
return "$ret"
}
文字全体を読んだ後にのみ返されることに注意してください。誤ったエンコーディング(ロケールエンコーディングとは異なります)を入力した場合、たとえば、端末がé
iso8859-1(0xe9)エンコーディングを送信し、UTF-8(0xc3 0xa9)を期待している場合は、任意の数値コンテンツを入力できますが、関数é
は返品。bash
はread -n1
2番目の0xe9を返し、両方とも変数に保存しますが、これは少し良い動作です。
(スクリプトを終了する代わりに、、...でも動作します)または/ on(フロー制御の代わりに)^C
で文字を読みたい場合は、行にaを追加できます。でもこれをしないことに注意してください(ダウンすると再起動することがあります)。Ctrl+C^Z
^\
^S
^Q
Ctrl+S/Q-isig -ixon
stty
bash
read -n1
isig
スクリプトが終了すると(たとえば、押すと)tty設定は復元されませんCtrl+C。を追加できますが、これによりスクリプトの他の設定が上書きされる可能性trap
があります。trap
zsh
代わりにbash
where read -k
(beforeksh93
またはbash
's)を使用することもできますread -n/-N
。これは、端末から文字を読み取って^D
直接処理し(文字が入力された場合はゼロ以外の値を返します)、改行文字は特に処理しません。
if read -k k; then
printf '1 character entered: %q\n' $k
fi