Skript, das einen Stream weiter liest

7

Manchmal catmag ich einen Stream /dev/input/event0.

Ich möchte ein Skript schreiben, das jedes Mal etwas tut, wenn mehr ausgegeben wird.

Die Definition von mehr Ausgabe kann jedes Mal sein, wenn ein Byte gelesen wird.

Wie kann das gemacht werden? Gibt es einen Befehl, der das macht?

Chao Xu
quelle

Antworten:

5

Ab einem Shell-Skript sind Sie auf vollständige Zeilen beschränkt. Sie müssen C / Perl / Python / was auch immer verwenden, um feiner lesen zu können.

while read line; do
  # do something based on content of $line; remember to quote it
done </dev/input/event0
Geekosaurier
quelle
6
Viele Muscheln unterstützen das Lesen von weniger als einer Zeile, es ist einfach kein Standard. ksh kann (zB) fünf Bytes mit lesen read -N5, bash kann fünf (möglicherweise Multibyte-) Zeichen mit lesen read -rN5, zsh kann 5 (möglicherweise Multibyte-) Zeichen mit lesen read -u0 -k5. Sowohl bash als auch zsh können mithilfe des C-Gebietsschemas (oder wahrscheinlich eines beliebigen 8-Bit-Zeichen-Typs) Bytes anstelle von Zeichen lesen.
Chris Johnsen
2
@ Chris Erwägen Sie, eine Antwort zu schreiben!
Steven D
Anscheinend read -Nist neu in Bash 4.2, so dass es möglicherweise nicht überall ist. Außerdem scheint Bash LC_CTYPE=C IFS= read -rN 1 bestimmte Bytes zu essen (0x00, 0xff). ksh scheint 0x00 zu essen (wahrscheinlich aufgrund der internen Verwendung von NUL-terminierten Strings). zsh scheint aber richtig zu funktionieren.
Chris Johnsen
4

Eine Variation der Antwort von Geekosaurier:
Vielleicht möchten Sie versuchen read -n 1 byte, jeweils ein Byte zu lesen und dann etwas damit zu tun $byte.

BEARBEITEN:

Ich habe es gerade versucht, da ich diesen Befehl noch nie zuvor verwendet hatte (habe nur nachgeschlagen info bash), aber es scheint alle Leerzeichen und Zeilenenden zu verschlingen. Ich habe noch keine Erklärung dafür.

Versuchen Sie die folgenden Skripte, um die Befehlsargumente zu optimieren:

(for j in $(seq 1 10); do for i in $(seq 1 100); do echo -n "$i, "; sleep .02; done; echo "& $j."; done) | (while read line; do echo $line; done)

(for j in $(seq 1 10); do for i in $(seq 1 100); do echo -n "$i, "; sleep .05; done; echo "& $j."; done) | (while read -n 1 byte; do echo -n "$byte"; done)

Dies ergibt leider nicht das erwartete Ergebnis.

EDIT (mit Chris 'Hilfe):

(for j in $(seq 1 10); do for i in $(seq 1 100); do echo -n "$i, "; sleep .02; done; echo "& $j."; done) | (while IFS= read -N 1 byte; do echo -n "$byte"; done)

Dies ergibt genau das erwartete Ergebnis.
Hinweis: ob ich -n, -Noder -rNdas Ergebnis nicht ändern, es ist alles gut (mit Text, ich habe nicht testen Sie die Einschränkung , dass Chris spricht über: 0x00 und 0xFF).

asoundmove
quelle
Dieses "Kauen" ist der Grund, warum ich sagte "denk daran, es zu zitieren"; Wenn Sie sagen echo $foo, $foowerden alle Leerzeichen (alle Zeichen in $IFS, um pedantisch zu sein) zu einzelnen Leerzeichen komprimiert, während echo "$foo"sie beibehalten werden. Sie müssen es jedoch konsequent verwenden , um sicherzustellen, dass das Leerzeichen immer in Anführungszeichen steht.
Geekosaurier
1
@geekosaur, es ist kein Zitatproblem, es liegt an der Tatsache, dass bash IFS-Mitglieder in read -n(und read -Nin 4.2) zu ignorieren scheint . Die Problemumgehung ist zu verwenden IFS= read -rn 1(selbst dann isst bash immer noch 0x00 und 0xff).
Chris Johnsen
Deshalb würde ich nicht verwenden bash; es scheint immer solche dummen Fehler zu haben. (Mein "Lieblings" bash-Fehler war in einer 2.x-Version, in der Backslashes für den Fall, dass Muster nicht aufhören *, ein Glob-Match zu sein.)
Geekosaurier