Wenn Sie ruhig in den Gängen von Unix & Linux stehen und genau zuhören, hören Sie eine gespenstische Stimme, die erbärmlich jammert: "Was ist mit Dateinamen, die Zeilenumbrüche enthalten?"
ls -d *snp* | wc -l
oder, in äquivalenter Weise ,
printf "%s\n" *snp* | wc -l
gibt alle Dateinamen aus, die snpjeweils eine neue Zeile enthalten,
aber auch alle neuen Zeilen in den Dateinamen enthalten , und zählt dann die Anzahl der Zeilen in der Ausgabe. Wenn es eine Datei gibt, deren Name ist
f o o
s n p \n
b a r
. t s v
dann wird dieser Name als ausgeschrieben
foosnp
bar.tsv
was natürlich als zwei Zeilen gezählt wird.
Es gibt einige Alternativen, die zumindest in einigen Fällen besser sind:
printf "%s\n" * | grep -c snp
Das zählt die Zeilen, die enthalten snp, so dass das foosnp(\n)bar.tsvBeispiel von oben nur einmal zählt. Eine leichte Abweichung davon ist
ls -f | grep -c snp
Die beiden oben genannten Befehle unterscheiden sich darin:
- Das
ls -fwird Dateien enthalten, deren Namen mit beginnen .; printf … *Dies ist nicht der Fall, es sei denn, die dotglobShell-Option ist festgelegt.
printfist eine eingebaute Muschel; lsist ein externer Befehl. Daher lskönnten die etwas mehr Ressourcen verbrauchen.
- Wenn die Shell a verarbeitet
*, sortiert sie die Dateinamen.
ls -fsortiert die Dateinamen nicht. Daher verbrauchen die lsmöglicherweise etwas weniger Ressourcen.
Aber sie haben etwas gemeinsam: Sie geben beide falsche Ergebnisse, wenn Dateinamen vorhanden sind, die Zeilenumbrüche enthalten und snpsowohl vor als auch nach dem Zeilenumbruch stehen .
Ein weiterer:
filenamelist=(*snp*)
echo ${#filenamelist[@]}
Dadurch wird eine Shell-Array-Variable erstellt, in der alle enthaltenen Dateinamen aufgelistet snpsind. Anschließend wird die Anzahl der Elemente im Array angegeben. Die Dateinamen werden als Zeichenfolgen und nicht als Zeilen behandelt, sodass eingebettete Zeilenumbrüche kein Problem darstellen. Es ist denkbar, dass dieser Ansatz ein Problem haben könnte, wenn das Verzeichnis sehr groß ist, da die Liste der Dateinamen im Shell-Speicher gespeichert werden muss.
Noch ein anderer:
Früher, als wir sagten printf "%s\n" *snp*, printfwiederholte (wiederverwendete) der Befehl die "%s\n"Formatzeichenfolge einmal für jedes Argument in der Erweiterung von *snp*. Hier nehmen wir eine kleine Änderung vor:
printf "%.0s\n" *snp* | wc -l
Dadurch wird die "%.0s\n"Formatzeichenfolge für jedes Argument in der Erweiterung von einmal wiederholt (wiederverwendet) *snp*. Bedeutet "%.0s"aber, die ersten Nullzeichen jeder Zeichenfolge zu drucken - dh nichts. Dieser printfBefehl gibt nur eine neue Zeile (dh eine leere Zeile) für jede Datei aus, die snpihren Namen enthält . und dann wc -lwerden sie zählen. Und wieder können Sie die .Dateien durch Festlegen einschließen dotglob.