Es scheint, als prefix-*
sollte es leicht sein, daraus zu wechseln, zum Beispiel prefix-1 prefix-2
, da wir es gewohnt sind, Verzeichnisse sortiert zu sehen. Es stellt sich jedoch heraus, dass nur wenige Dateisysteme tatsächlich sortierte Dateinamenlisten erzeugen können, und außerdem gibt es keine Standard-API für die Abfrage von sortierten Dateinamenlisten.
Wenn ein Programm - wie beispielsweise ls
oder in diesem Zusammenhang bash
- eine Liste von Dateinamen benötigt, muss es die gesamte Verzeichnisliste lesen, die in einer zufälligen Reihenfolge erstellt wird (oft hängt die Reihenfolge mit der Erstellungszeit zusammen, manchmal auch mit dem Erstellungszeitpunkt) Es basiert auf einem Hash des Dateinamens, aber in ziemlich keinem Fall handelt es sich um eine einfache alphabetische Reihenfolge. Um sie aufzulösen prefix-*
, müssen Sie das gesamte Verzeichnis lesen und jeden Dateinamen anhand des Musters prüfen. Da das teuerste Teil dieser Prozedur das Lesen des Verzeichnisses ist, macht es wenig aus, wie komplex das Muster ist oder wie viele Dateinamen mit dem Muster übereinstimmen.
Zusammenfassend wird die Erweiterung des Pfadnamens ("Auflösen von Globs") in einem großen Verzeichnis langsam sein. Das ist ein Grund, um große Verzeichnisse zu vermeiden, und nicht als Grund, um Globs zu vermeiden.
Aber es gibt eine weiteren wichtigen Datenpunkt: prefix-
ist nicht Pfadname Expansion. Es handelt sich hierbei um " Klammererweiterung " und um eine Erweiterung des Posix-Shell-Standards (obwohl fast alle Shells es implementieren). Es gibt eine Reihe von Unterschieden zwischen der Erweiterung der Klammer und der Erweiterung des Pfadnamens. Ein wichtiger und relevanter Unterschied besteht jedoch darin, dass die Erweiterung der Klammer nicht von der Existenz von Dateien abhängt . Brace Expansion ist eine einfache Stringoperation.
Daher prefix-
wird immer erweitert prefix-1 prefix-2
, unabhängig davon, ob diese Dateien vorhanden sind oder nicht. Das heißt, es kann erweitert werden, ohne das Verzeichnis zu lesen und ohne stat
eine Datei zu erstellen. Das wird natürlich schnell gehen. Es gibt jedoch einen Nachteil: Es gibt keine Möglichkeit festzustellen, ob das Ergebnis echten Dateien entspricht.
Betrachten Sie das folgende einfache Beispiel:
$ mkdir test && cd test $ touch file1 file2 file4 $ ls file* file1 file2 file4 $ ls file[1234] file1 file2 file4 $ ls file ls: cannot access file3: No such file or directory file1 file2 file4
Schlusspunkt: Die Erweiterung des Pfadnamens erfolgt durch die Shell, nicht durch ls
. Mit der Erweiterung des Pfadnamens könnten wir genauso gut Folgendes verwenden echo
:
$ echo file* file1 file2 file4 $ echo file[1234] file1 file2 file4
Und echo
die Liste wird etwas schneller erstellt, da nur echo
die Argumente gedruckt werden müssen, während ls
(die dieselben Argumente erhalten) stat
jedes Argument vorhanden ist, um zu überprüfen, ob es sich um eine Datei handelt. Das stat
- was kein billiger Aufruf ist - ist bei einer Erweiterung des Pfadnamens völlig überflüssig, da die Shell die Verzeichnisliste bereits verwendet hat, um die Dateiliste zu filtern, und daher ist jeder übergebene Dateiname ls
bekannt. (Es sei denn, der Glob hat überhaupt keine Dateien gefunden.)
Außerdem ist echo ein bash
integriertes System, sodass es aufgerufen werden kann, ohne einen untergeordneten Prozess zu erstellen.
Im Falle der Klammerausdehnung führt dies echo
jedoch nicht zum gleichen Ergebnis:
$ echo file file1 file2 file3 file4
Wir könnten also die ls
Fehlerausgabe in den Bit-Bucket umleiten:
$ ls file file1 file2 file4
In diesem Fall sind die stat
Aufrufe nicht redundant, da die Dateinamen nicht von der Shell überprüft wurden.
Wenn Ihre Verzeichnisse nicht wirklich riesig sind, wird dies alles keinen großen Unterschied machen und der Glob wird viel einfacher zu schreiben sein. Wenn Ihre Verzeichnisse sehr umfangreich sind, sollten Sie sie in kleinere Unterverzeichnisse aufteilen.
Zum Beispiel anstelle von Pfaden wie:
/var/log/remote/serverX.domain.local/ps/ps2.log.2014-mm-dd.gz
Du könntest benutzen:
/var/log/remote/serverX/domain.local/ps/ps2.log.2014-mm-dd-gz
Wenn Sie die Protokolle für immer aufbewahren, möchten Sie möglicherweise das Jahr extrahieren, um die Verzeichnisgröße nicht unendlich zu vergrößern:
/var/log/remote/2014/serverX/domain.local/ps/ps2.log.2014-mm-dd-gz
( 2014
wird absichtlich wiederholt.)
Das Scherben der Verzeichnisse ist in der Regel ein großer Gewinn, da es einen Mechanismus zur Optimierung des Globings bietet. Wie oben erwähnt, kann die Schale nicht optimiert werden
/var/log/remote/server[2357].domain.local/ps/ps2.log.2014-10-*-gz
aber es kann optimieren
/var/log/remote/server[2357]/domain.local/ps/ps2.log.2014-10-*-gz
Im zweiten Fall muss server[2357]
nur mit den Verzeichnisnamen abgeglichen werden. Sobald dies geschehen ist, müssen ps2.log.2014-10-*-gz
nur die Dateinamen in den übereinstimmenden Verzeichnissen abgeglichen werden.