Frage Gibt es einen Bash-Befehl, der Dateien zählt?


Gibt es einen Bash-Befehl, der die Anzahl der Dateien zählt, die einem Muster entsprechen?

Ich möchte zum Beispiel die Anzahl aller Dateien in einem Verzeichnis ermitteln, die diesem Muster entsprechen: log*


75
2017-07-03 08:35


Ursprung


Antworten:


Dieser einfache One-Liner sollte in jeder Shell funktionieren, nicht nur in der Bash:

ls -1q log* | wc -l

ls -1q gibt Ihnen eine Zeile pro Datei, auch wenn sie Leerzeichen oder Sonderzeichen wie Zeilenumbrüche enthalten.

Der Ausgang wird an wc -l übergeben, der die Anzahl der Zeilen zählt.


101
2017-07-03 08:41



Sie können dies sicher tun (d. H. Nicht von Dateien mit Leerzeichen oder \n in ihrem Namen) mit bash:

$ shopt -s nullglob
$ logfiles=(*.log)
$ echo ${#logfiles[@]}
$ shopt -u nullglob

Sie müssen aktivieren nullglob damit du das Literal nicht bekommst *.log in dem $logfiles  Array wenn keine Dateien übereinstimmen.


33
2017-07-03 08:43



Versuche dies:

echo *.log | wc -w


30
2017-07-03 08:41



Viele Antworten hier, aber einige berücksichtigen nicht

  • Dateinamen mit Leerzeichen, Zeilenumbrüchen oder Steuerzeichen in ihnen
  • Dateinamen, die mit Bindestrichen beginnen (stellen Sie sich eine Datei mit dem Namen -l)
  • leere Verzeichnisse (d. h. das Ergebnis ist 0)
  • extrem große Verzeichnisse (alle aufzählen könnte Speicher erschöpfen)

Hier ist eine Lösung, die alle behandelt:

ls 2>/dev/null -Ub1 -- log* | wc -l

Erläuterung:

  • -U Ursachen ls um die Einträge nicht zu sortieren, bedeutet dies, dass nicht die gesamte Verzeichnisliste im Speicher geladen werden muss
  • -b Druckt C-Style-Escapes für nichtgraphische Zeichen, die entscheidend dazu führen, dass Newlines als gedruckt werden \n.
  • 2>/dev/null leitet stderr um, so dass, wenn es 0 Protokolldateien gibt, die Fehlermeldung ignoriert. (Beachten Sie, dass shopt -s nullglob würde dazu führen ls um stattdessen das gesamte Arbeitsverzeichnis aufzulisten.)
  • wc -l konsumiert die Verzeichnisliste, wie sie erzeugt wird, also die Ausgabe von ls ist zu keinem Zeitpunkt in Erinnerung.
  • -- Dateinamen werden mit dem Befehl getrennt -- um nicht als Argumente verstanden zu werden ls (im Fall log* ist entfernt)

die Muschel werden erweitern log* zu der vollen Liste von Dateien, die Speicher ausschöpfen können, wenn es viele Dateien sind, also ist es besser, sie durch grep laufen zu lassen:

ls -Ub1 | grep ^log | wc -l

Dieser letztere behandelt extrem große Verzeichnisse von Dateien, ohne viel Speicher zu verwenden (obwohl er eine Subshell verwendet).


28
2017-11-24 11:01



Die akzeptierte Antwort für diese Frage ist falsch, aber ich habe einen niedrigen Ruf und kann daher keinen Kommentar hinzufügen.

Die richtige Antwort auf diese Frage gibt Mat:

shopt -s nullglob
logfiles=(*.log)
echo ${#logfiles[@]}

Das Problem mit der angenommenen Antwort ist, dass wc -l die Anzahl der Zeilenumbruchzeichen zählt und sie zählt, auch wenn sie als "?" in der Ausgabe von 'ls -l'. Dies bedeutet, dass die akzeptierte Antwort fehlschlägt, wenn ein Dateiname ein Zeilenvorschubzeichen enthält. Ich habe den vorgeschlagenen Befehl getestet:

ls -l log* | wc -l

und es meldet fälschlicherweise einen Wert von 2, selbst wenn nur eine Datei dem Muster entspricht, dessen Name zufällig ein Zeilenumbruchzeichen enthält. Beispielsweise:

touch log$'\n'def
ls log* -l | wc -l

5
2017-10-30 06:11



Wenn Sie viele Dateien haben und Sie nicht das elegante verwenden möchten shopt -s nullglob und bash array solution können Sie find und so weiter verwenden, solange Sie den Dateinamen nicht ausdrucken (der Zeilenumbrüche enthalten könnte).

find -maxdepth 1 -name "log*" -not -name ".*" -printf '%i\n' | wc -l

Dadurch werden alle Dateien gefunden, die dem Protokoll * entsprechen und nicht mit beginnen .* - Der "not name. *" Ist redunant, aber es ist wichtig zu beachten, dass der Standard für "ls" ist, keine dot-Dateien anzuzeigen, aber der Standard für find ist, sie aufzunehmen.

Dies ist eine korrekte Antwort und behandelt alle Arten von Dateinamen, die Sie ausgeben können, da der Dateiname nie zwischen Befehlen übergeben wird.

Aber die shopt nullglob Antwort ist die beste Antwort!


4
2017-08-22 19:16



Hier ist mein One Liner dafür.

 file_count=$( shopt -s nullglob ; set -- $directory_to_search_inside/* ; echo $#)

2
2017-11-04 19:48



ls -1 log* | wc -l

Das bedeutet, dass Sie eine Datei pro Zeile auflisten und sie dann zum Wortzählbefehl leiten, wobei der Parameter auf Zeilen zählen umschaltet.


1
2017-07-03 20:17