Ich habe versucht, mit bash eine Datei zeichenweise zu lesen.
Nach langem Ausprobieren habe ich festgestellt, dass dies funktioniert:
exec 4<file.txt
declare -i n
while read -r ch <&4;
n=0
while [ ! $n -eq ${#ch} ]
do echo -n "${ch:$n:1}"
(( n++ ))
done
echo ""
done
Das heißt, ich kann es Zeile für Zeile lesen und dann jede Zeile char für char durchlaufen.
Vorher hatte ich es versucht:
exec 4<file.txt && while read -r -n1 ch <&4; do; echo -n "$ch"; done
aber es würde alle Leerzeichen in der Datei überspringen .
Könnten Sie bitte erklären, warum? Gibt es eine Möglichkeit, die zweite Strategie (dh das Lesen von Zeichen für Zeichen mit Bashs Lesen) zum Funktionieren zu bringen?
IFS
nichts ein, damit Leerzeichen die Wortaufteilung überleben.Antworten:
Sie müssen Leerzeichen aus dem
$IFS
Parameter entfernenread
, um das Überspringen führender und nachfolgender Zeichen zu beenden (wobei-n1
das Leerzeichen, falls vorhanden, sowohl führende als auch nachfolgende Zeichen ist, also übersprungen):Aber selbst dann
read
überspringen Bashs Zeilenumbruchzeichen, mit denen Sie umgehen können:Obwohl Sie
IFS= read -d '' -rn1
stattdessen oder sogar besserIFS= read -N1
(hinzugefügt in 4.1, kopiert vonksh93
(hinzugefügt ino
)) verwenden können, ist dies der Befehl zum Lesen eines Zeichens.Beachten Sie, dass Bashs
read
nicht mit NUL-Zeichen umgehen können. Und ksh93 hat die gleichen Probleme wie bash.Mit zsh:
(zsh kann mit NUL-Zeichen umgehen).
Beachten Sie, dass diese
read -k/n/N
eine Anzahl von Zeichen und keine Bytes lesen . Bei Multibyte-Zeichen müssen sie möglicherweise mehrere Bytes lesen, bis ein vollständiges Zeichen gelesen wird. Wenn die Eingabe ungültige Zeichen enthält, erhalten Sie möglicherweise eine Variable, die eine Folge von Bytes enthält, die keine gültigen Zeichen bilden und die die Shell möglicherweise als mehrere Zeichen zählt . Zum Beispiel in einem UTF-8-Gebietsschema:Das
\375
würde ein 6-Byte-UTF-8-Zeichen einführen. Das sechste (A
) oben ist jedoch für ein UTF-8-Zeichen ungültig. Sie erhalten immer noch\375\200\200\200\200A
in$a
, wasbash
als 6 Zeichen zählt, obwohl die ersten 5 keine wirklichen Zeichen sind, sondern nur 5 Bytes, die nicht Teil eines Zeichens sind.quelle
read -rN1
stattdessen das Newline-Problem lösen und somit die Notwendigkeit beseitigen, beim Drucken standardmäßig eine Newline bereitzustellen$a
.read -n1
(char by char) dauert 4 Minuten und 51 Sekunden und heizt den Laptop auf 90 Grad auf. Die Verwendungread -r
(Zeile für Zeile) dauert 1,3 Sekunden und der Laptop bleibt bei 54 Grad, während zwei Lüfter leise sind.Dies ist ein einfaches Beispiel mit
cut
einerfor
Schleife &wc
:KISS, nicht wahr?
quelle
bash
Lösung :file="$(</etc/passwd)"; bytes="${#file}"; for ((i=0;i<bytes;i++)); do echo "${file:i:1}"; done
?bash
"Es ist zu groß und zu langsam." gemäß dem Abschnitt BUGS der Manpage. Trotzdem ist es immer noch schneller, eine Zeichenfolge in den Speicher zu schneiden, als für jedes Zeichen immer wieder eine Datei zu lesen. Zumindest auf meinem Rechner: pastebin.com/zH5trQQs