Mit read -n "$n"(keine POSIX-Funktion) und wenn stdin ein Endgerät ist, wird readdas Terminal aus dem icanonModus versetzt, da sonst readnur vollständige Zeilen angezeigt werden, die vom internen Zeileneditor der Terminalleitungsdisziplin zurückgegeben werden, und dann jeweils ein Byte gelesen werden, bis $nZeichen oder eine neue Zeile wurden gelesen (möglicherweise werden unerwartete Ergebnisse angezeigt, wenn ungültige Zeichen eingegeben werden).
Es liest bis zu $nZeichen aus einer Zeile. Sie müssen auch leer sein, $IFSdamit keine IFS-Zeichen von der Eingabe entfernt werden.
Da wir den icanonModus verlassen , ^Dist das nichts Besonderes mehr. Wenn Sie also drücken Ctrl+D, wird das ^DZeichen gelesen.
Sie würden eof nicht vom Endgerät sehen, wenn das Terminal nicht irgendwie getrennt wäre. Wenn stdin ein anderer Dateityp ist, wird möglicherweise eof angezeigt (z. B. : | IFS= read -rn 1; echo "$?"wenn stdin eine leere Pipe ist oder wenn stdin von umgeleitet wird /dev/null).
readgibt 0 zurück, wenn $nZeichen (Bytes, die nicht Teil gültiger Zeichen sind, die als 1 Zeichen gezählt werden) oder eine vollständige Zeile gelesen wurden.
In dem speziellen Fall, dass nur ein Zeichen angefordert wird:
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 zu machen ist ziemlich kompliziert.
Das wäre ungefähr so (unter der Annahme eines ASCII-basierten Systems (im Gegensatz zu beispielsweise EBCDIC)):
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"
}
Beachten Sie, dass wir nur zurückkehren, wenn ein vollständiges Zeichen gelesen wurde. Wenn sich die Eingabe in der falschen Codierung befindet (anders als die Codierung des Gebietsschemas), z. B. wenn Ihr Terminal éin iso8859-1 (0xe9) codiert sendet , wenn wir UTF-8 (0xc3 0xa9) erwarten, können Sie so viele eingeben, éwie Sie möchten wird die Funktion nicht zurückkehren. bash's read -n1würde beim zweiten 0xe9 zurückkehren (und beide in der Variablen speichern), was ein etwas besseres Verhalten ist.
Wenn Sie auch ein ^CZeichen lesen möchten Ctrl+C(anstatt es Ihr Skript töten zu lassen; auch für ^Z, ^\...) oder
^S/ ^Qauf Ctrl+S/Q(anstelle der Flusskontrolle), können Sie -isig -ixonder sttyZeile ein hinzufügen . Beachten Sie, dass bash‚s read -n1es nicht tut entweder (es stellt auch isigwenn es aus).
Dadurch werden die tty-Einstellungen nicht wiederhergestellt, wenn das Skript beendet wird (z. B. wenn Sie drücken Ctrl+C. Sie könnten ein hinzufügen trap, dies würde jedoch möglicherweise andere traps im Skript überschreiben .
Sie können auch verwenden , zshstatt bash, wo read -k(die früher ksh93oder bash‚s read -n/-N) liest ein Zeichen aus dem Terminal und Griffe ^Dspeziell für sich allein (kehrt nicht Null , wenn das Zeichen eingegeben wird ) und nicht behandeln Newline.
if read -k k; then
printf '1 character entered: %q\n' $k
fi
^D, warum können wir\ndann nicht erfassen ?