Angenommen, ein Verzeichnis enthält 100 Dateien, die mit dem Buchstaben 'a' beginnen.
grep <some string> a*
Wie wird die Shell damit umgehen, wenn ich eine vom Terminal aus mache ?
Wird es den regulären Ausdruck erweitern, eine Liste aller Dateien erhalten, die mit a beginnen, und für jede dieser Dateien nacheinander grep? Oder gibt es einen anderen Weg?
Angenommen, ich habe ein Array der oben genannten Dateinamen, die mit 'a' beginnen. Wird es mehr oder weniger Zeit dauern, wenn ich eine for-Schleife schreibe und die Iteration selbst in einem Shell-Skript oder einem AC-Programm durchführe?
glob
kein regulärer Ausdruck. Großer Unterschied.Antworten:
Erstens ein Nitpick: Ein String wie
a*
in der normalen Shell-Syntax ist ein Glob, der anders funktioniert als reguläre Ausdrücke.In einer allgemeinen Übersicht erweitert der Shell-Interpreter (dh Bash) die Zeichenfolge
a*
zu einer Liste aller Dateinamen, die dem Muster entsprechena*
. Diese werden dann Teil der Befehlszeilenparameter für eine einzelne Instanz vongrep
(für die Programmierer werden alle erweiterten Wörter als separate Zeichenfolgen in dasargv
Argument von eingefügtmain
). Dieser einzelnegrep
Befehl analysiert dann die Argumente auf die von ihm gewählte Weise, und es liegt angrep
diesen Argumenten, sie als Dateinamen, Optionen, Optionsargumente, reguläre Ausdrücke usw. zu interpretieren und die entsprechenden Maßnahmen zu ergreifen. Alles erfolgt nacheinander (AFAIK keinegrep
Implementierung verwendet mehrere Threads).Wenn Sie eine Schleife in einem Shell-Skript implementieren, um dasselbe zu tun, ist sie aus den folgenden Gründen fast garantiert langsamer als der oben beschriebene Prozess. Wenn Sie für jede Datei einen neuen Grep-Prozess erzeugen, wird dieser mit Sicherheit langsamer, da der Aufwand für die Prozesserstellung unnötig multipliziert wird. Wenn Sie die Argumentliste selbst im Shell-Skript erstellt und eine einzelne Instanz von verwendet haben
grep
, ist alles, was Sie in der Shell tun, immer noch langsamer, da Shell-Befehle (per Bash) interpretiert werden müssen, wodurch eine zusätzliche Codeebene hinzugefügt wird Implementieren Sie einfach neu, was bash intern bereits in kompiliertem Code schneller gemacht hat.Wenn Sie es selbst in C schreiben, können Sie wahrscheinlich leicht eine vergleichbare Leistung wie im ersten Absatz beschrieben erzielen, aber es ist unwahrscheinlich, dass Sie einen ausreichenden Leistungsgewinn gegenüber den aktuellen Grep / Bash-Implementierungen erzielen können, um die Zeit zu rechtfertigen ausgegeben, ohne sich mit maschinenspezifischen Leistungsoptimierungen zu befassen oder die Portabilität zu beeinträchtigen. Vielleicht könnten Sie versuchen, eine willkürlich parallelisierbare Version von zu entwickeln
grep
, aber selbst das hilft möglicherweise nicht, da Sie eher an E / A als an CPU gebunden sind. Glob Expansion und Grep sind für die meisten "normalen" Zwecke bereits "schnell genug".quelle
zcat
undzgrep
; keine Notwendigkeit, sieJa, es wird zu einer Liste von Dateien erweitert und die resultierende Liste dem
grep
Programm zugeführt. Zumindest steht dasman bash
im Unterabschnitt Pfadnamenerweiterung .Es gibt eine andere Möglichkeit, die Erweiterung in einfachen Fällen zu verwenden, wie Sie bereits erwähnt haben: Schreiben
grep <some_string> a
und vor dem Drücken*
drücken ESC. Dadurch wird die Liste der übereinstimmenden Dateien direkt in der Befehlszeile erweitert, sodass Sie überprüfen können, ob die Liste in Ordnung ist, bevor Sie auf drücken Enter.Der zweite Teil Ihrer Frage hängt davon ab. Wenn Sie eine for-Schleife schreiben möchten, die nacheinander grep für jede der Dateien ausführt, ist dies definitiv langsamer, da das grep-Programm nicht einmal, sondern einmal pro Datei ausgeführt wird. Doch was ist wichtig im Auge zu behalten ist , dass es eine bestimmte ist Grenze auf der erweiterten Länge der Befehlszeilenargumente können Sie verwenden, obwohl es in der Regel recht hoch ist. Um das zu sehen, können Sie es versuchen
grep adasdsadf /usr/*/*/* >/dev/null
.quelle
ESC+*
ist nicht genau das Gleiche wie das Erweitern von bash *, daESC+*
Punktdateien (Namen, die mit a beginnen.
) eingefügt werden, während die Erweiterung von*
von derdotglob
shopt
Einstellung abhängt . Die Tastenfolge zum Erweitern und Einfügen von Globs istC-x *
standardmäßig und wird dem Befehl readline zugeordnetglob-expand-word
.a*
Expansion nicht zu ändern , ist aber in einem breiteren Bereich sicherlich wichtig.zsh
Hinweis: Durch einfaches Drücken der Tabulatortaste bei erweiterbaren Parametern (Glob-Muster, Klammererweiterung, Befehlssubstitution usw.) werden diese erweitert.C-x
Verknüpfung getestet und sie erweitert nicht die Liste der Dateien auf meinem System (mit bash).C-x *
Nur Globs, die nur Dateinamen verwenden, aberEsc *
tatsächlich viel mehr, da dies der Fall istinsert-completions
, wie bei allen möglichen Vervollständigungen. Dies bedeutet, dass bei VerwendungEsc *
einer leeren Befehlszeile beispielsweise der Name jeder einzelnen ausführbaren Datei in Ihre Datei eingefügt$PATH
wird.