Ich möchte die Anzahl der Zeichen in jeder Zeile einer Textdatei mit einem Unix-Befehl drucken. Ich weiß, dass es mit Powershell einfach ist
gc abc.txt | % {$_.length}
aber ich brauche Unix-Befehl.
Antworten:
Verwenden Sie Awk.
awk '{ print length }' abc.txt
while IFS= read -r line; do echo ${#line}; done < abc.txt
Es ist POSIX, also sollte es überall funktionieren.
Bearbeiten: -r hinzugefügt, wie von William vorgeschlagen.
Bearbeiten: Vorsicht vor Unicode-Handhabung. Bash und zsh mit korrekt eingestelltem Gebietsschema zeigen die Anzahl der Codepunkte an, während Bindestrich Bytes anzeigt. Sie müssen also überprüfen, was Ihre Shell tut. Und dann gibt es in Unicode sowieso viele andere mögliche Definitionen der Länge, also hängt es davon ab, was Sie tatsächlich wollen.
Bearbeiten: Präfix mit IFS=
, um zu vermeiden, dass führende und nachfolgende Leerzeichen verloren gehen.
IFS=
den read
Befehl, wenn Sie beliebige Daten einlesen möchten. Also IFS= read -r
. read
verwendet das IFS
, um das Teilen von Wörtern durchzuführen, und obwohl alle geteilten Wörter dann wieder in die eine verfügbare Variable ( line
) eingefügt werden, gibt es keine Garantie dafür, dass sie wieder zusammen mit allen ursprünglichen Trennzeichen eingefügt werden, die sie hatten, oder nur einem potenziell unterschiedlichen Einsen. Zum Beispiel mit dem Standard - IFS, die Linie foo bar
könnte werden foo bar
, verliert 7 Räume. (Zum Beispiel, wie der Stapelüberlauf die benachbarten Leerzeichen in dieser Beispielzeichenfolge in diesem Kommentar verloren hat).
IFS
sollten eingestellt werden, aber das Problem, wenn es nicht ist, ist subtiler.
Ich habe die anderen oben aufgeführten Antworten ausprobiert, aber sie sind bei großen Dateien alles andere als anständige Lösungen - insbesondere, wenn die Größe einer einzelnen Zeile mehr als ~ 1/4 des verfügbaren Arbeitsspeichers belegt.
Sowohl bash als auch awk schlürfen die gesamte Linie, obwohl es für dieses Problem nicht benötigt wird. Bash tritt aus, sobald eine Zeile zu lang ist, auch wenn Sie über genügend Speicher verfügen.
Ich habe ein extrem einfaches, ziemlich unoptimiertes Python-Skript implementiert, das beim Testen mit großen Dateien (~ 4 GB pro Zeile) nicht schlürft und bei weitem eine bessere Lösung ist als die angegebenen.
Wenn dies zeitkritischer Code für die Produktion ist, können Sie die Ideen in C umschreiben oder bessere Optimierungen für den Leseaufruf durchführen (anstatt jeweils nur ein Byte zu lesen), nachdem Sie getestet haben, dass dies tatsächlich ein Engpass ist.
Code geht davon aus, dass newline ein Zeilenvorschubzeichen ist, was eine gute Annahme für Unix, aber YMMV unter Mac OS / Windows ist. Stellen Sie sicher, dass die Datei mit einem Zeilenvorschub endet, um sicherzustellen, dass die Anzahl der letzten Zeilenzeichen nicht übersehen wird.
from sys import stdin, exit
counter = 0
while True:
byte = stdin.buffer.read(1)
counter += 1
if not byte:
exit()
if byte == b'\x0a':
print(counter-1)
counter = 0
Hier ist ein Beispiel mit xargs
:
$ xargs -d '\n' -I% sh -c 'echo % | wc -c' < file
Versuche dies:
while read line
do
echo -e |wc -m
done <abc.txt
echo -e | wc -m
, nicht wahr? Es ist nutzlos, Befehle zu verwenden. Shell kann Zeichen in einer Variablen zählen. Plus echo -e
ist völlig inkompatibel und funktioniert in der Hälfte der Shells, während das Beginnen mit einer Escape-Sequenz in einer anderen und nichts in den anderen funktioniert.