Zählen Sie keine durch Trennzeichen getrennten Elemente in der Datei

8

Ich habe ein Shell-Skript, mit find -print0dem eine Liste der zu verarbeitenden Dateien in einer temporären Datei gespeichert wird. Im Rahmen der Protokollierung möchte ich die Anzahl der gefundenen Dateien ausgeben. Daher benötige ich einen Weg, um diese Anzahl zu ermitteln. Wenn die -print0Option nicht aus Sicherheitsgründen verwendet würde, könnte ich sie verwenden wc -l, um die Zählung zu erhalten.

qqx
quelle

Antworten:

11

Einige Optionen:

tr -cd '\0' | wc -c

tr '\n\0' '\0\n' | wc -l      # Generic approach for processing NUL-terminated
                              # records with line-based utilities (that support
                              # NUL characters in their lines like GNU ones).

grep -cz '^'                  # GNU grep

sed -nz '$='                  # recent GNU sed, no output for empty input

awk -vRS='\0' 'END{print NR}' # not all awk implementations

Beachten Sie, dass für einen Eingang, die Daten nach den letzten NUL - Zeichen (oder nicht-leere Eingabe ohne NUL - Zeichen) enthält, die trwerden Ansätze immer die Anzahl der NUL - Zeichen zählen, aber die awk/ sed/ grepAnsätze werden eine zusätzliche Aufzeichnung für diese zusätzlichen Bytes zählen .

Stéphane Chazelas
quelle
Ich habe diese an 5 GB zufälligen Daten gemessen ( head -c 5G /dev/urandom > f). Ergebnisse: grep 1.7s (gleich für grep -Fcz '') • tr + wc-c 7.7s • tr + wc-l 7.4s • sed 34.7s • awk 1m11.7s
Socowi
@Socowi, YMMV mit der Implementierung und dem Gebietsschema. Mit GNU awkmöchten Sie das Gebietsschema auf C(oder ein beliebiges, das keine Multibyte-Zeichen verwendet) festlegenLC_ALL=C awk ... < f
Stéphane Chazelas
Danke für den Tipp. Früher habe ich schon LC_ALL=Cauf , sortwo es hat nicht die Dinge beschleunigen, deshalb Zum Glück habe ich noch die Datei haben aus der Zeit vor: LC_ALL=C awk ...nimmt 6.7s.
Socowi
4

Die beste Methode, an die ich denken konnte, ist die Verwendung grep -zc '.*'. Dies funktioniert, aber es fühlt sich falsch an, grep mit einem Muster zu verwenden, das zu allem passt.

qqx
quelle
1

Mit perl:

perl -0ne 'END {print $.}'

oder:

perl -nle 'print scalar split "\0"'

oder:

perl -nle 'print scalar unpack "(Z*)*", $_'
cuonglm
quelle
Der erste zählt einen zusätzlichen Datensatz, wenn nach dem letzten NUL Daten vorhanden sind. Die beiden anderen funktionieren nicht, wenn die Eingabe Zeilenumbrüche enthält.
Stéphane Chazelas
@ StéphaneChazelas: Oh, mein schlechtes. Könnten Sie eine Verbesserung geben?
Cuonglm
Ich würde nur die erste behalten und die Tatsache erwähnen, dass eine nicht abgegrenzte Aufzeichnung (im Gegensatz zu wc -l) als Notiz (wie gewünscht) gezählt wird.
Stéphane Chazelas