Bash-Builtins vs. externe Befehle: Ein Leistungsvergleich
Beschleunigen Sie Bash-Skripte, indem Sie Shell-Builtins für Tests, Arithmetik und Zeichenkettenoperationen verwenden und externe Befehle bündeln.
Bash-Builtins vs. externe Befehle: Ein Leistungsvergleich
Wenn ein Bash-Skript sich langsam anfühlt, liegt die Ursache oft in einer Schleife, die tausende externe Prozesse startet. Bash-Builtins vs. externe Befehle ist eine praktische Leistungsentscheidung: Nutzen Sie die eigenen Funktionen der Shell für einfache Arbeiten und sparen Sie externe Werkzeuge für Aufgaben, die sie besser bewältigen.
Diese Anleitung zeigt, wo Builtins helfen, wo externe Befehle weiterhin sinnvoll sind und wie Sie die häufigsten Fallen der Prozesserzeugung vermeiden.
Verstehen der Befehlsausführung in Bash
Wenn Bash auf einen Befehl trifft, löst es Aliase, Shell-Schlüsselwörter, Funktionen, Builtins und dann über PATH gefundene Befehle auf. Diese Auflösung ist wichtig, weil alles, was innerhalb der aktuellen Shell behandelt wird, das Starten eines separaten Programms vermeidet.
1. Built-in-Befehle
Bash-Builtin-Befehle sind Funktionen, die direkt im Bash-Shell-Programm selbst implementiert sind. Sie erfordern keine Systemaufrufe wie fork() und exec() des Betriebssystems. Da die Ausführung vollständig innerhalb des bestehenden Shell-Prozesses stattfindet, bieten Builtins überlegene Leistung, minimalen Overhead und direkten Zugriff auf Shell-Variablen und -Zustand.
Wesentliche Merkmale von Builtins:
- Geschwindigkeit: Schnellster Ausführungspfad.
- Overhead: Nahezu kein Overhead, da kein neuer Prozess erstellt wird.
- Umgebung: Sie arbeiten direkt in der aktuellen Shell-Umgebung.
2. Externe Befehle
Externe Befehle sind separate ausführbare Dateien (oft in Verzeichnissen wie /bin, /usr/bin usw.). Wenn Bash einen externen Befehl ausführt, muss es:
- Einen neuen Kindprozess mit
fork()erzeugen. - Das externe Programm mit
exec()in diesem Kindprozess ausführen. - Auf die Beendigung des Kindprozesses warten.
Dieser Overhead, der für eine einzelne Ausführung trivial ist, summiert sich schnell in Schleifen oder bei häufigen Operationen und macht externe Befehle deutlich langsamer als ihre Builtin-Pendants.
Der Leistungsvergleich: Builtins in Aktion
Um den Leistungsunterschied zu veranschaulichen, betrachten wir häufige Aufgaben, bei denen Bash sowohl eine Builtin- als auch eine externe Alternative bietet.
Beispiel 1: Zeichenkettenmanipulation und Längenberechnung
Die Berechnung der Länge einer Variablen ist ein klassischer Leistungstest.
| Befehlstyp | Befehl | Beschreibung |
|---|---|---|
| Builtin | ${#variable} |
Parameterexpansion für die Länge. Extrem schnell. |
| Extern | expr length "$variable" |
Ruft das externe Dienstprogramm expr auf. Langsam. |
Leistungstipp: Verwenden Sie immer die Parameterexpansion (${#var}) für die Längenberechnung anstelle von expr length oder der Weiterleitung an wc -c.
Beispiel 2: Zeichenkettenersetzung
Das Ersetzen von Teilzeichenketten innerhalb einer Variablen ist eine weitere häufige Operation.
| Befehlstyp | Befehl | Beschreibung |
|---|---|---|
| Builtin | ${variable//pattern/replacement} |
Parameterexpansion-Substitution. Schnell. |
| Extern | sed 's/pattern/replacement/g' |
Ruft das externe Dienstprogramm sed auf. Langsam. |
Beispiel-Code-Vergleich:
TEXT="hallo welt hallo"
# Builtin (Schnell)
NEUER_TEXT_1=${TEXT//hallo/tschüss}
# Extern (Langsam)
NEUER_TEXT_2=$(echo "$TEXT" | sed 's/hallo/tschüss/g')
Beispiel 3: Schleifen und Iteration
Beim Iterieren ist der innerhalb der Schleife verwendete Befehl enorm wichtig.
| Befehlstyp | Befehl | Beschreibung |
|---|---|---|
| Builtin | read |
Wird verwendet, um Eingaben zeilenweise effizient zu lesen. |
| Extern | grep, awk, cut |
Das Weiterleiten von Daten an externe Werkzeuge innerhalb einer Schleife erzwingt wiederholte Prozesserzeugung. |
Das while read Anti-Pattern vs. Builtins:
Ein häufiges langsames Muster ist das Weiterleiten von Dateiinhalten an externe Befehle innerhalb einer Schleife:
# LANGSAM: Erzeugt für jede einzelne Zeile einen 'grep'-Prozess
while read ZEILE; do
echo "Verarbeite: $ZEILE" | grep "wichtig"
done < eingabe.txt
Optimierungsstrategie: Verwenden Sie nach Möglichkeit Bash-Builtins oder interne Umleitungen, um externe Befehle innerhalb von Schleifen zu vermeiden.
Wichtige Bash-Builtin-Befehle für die Leistung
Die Priorisierung dieser Builtins gegenüber ihren externen Äquivalenten wird zu erheblichen Geschwindigkeitsverbesserungen in Ihren Skripten führen:
| Aufgabenkategorie | Builtin-Befehl | Externe Alternative (Langsamer) |
|---|---|---|
| Arithmetik | (( Ausdruck )) |
expr, bc |
| Dateitests | [[ ... ]] oder Bashs eingebautes [ ... ] |
Externes /usr/bin/test oder /usr/bin/[ |
| Zeichenkettenmanipulation | ${var/pat/rep}, ${#var} |
sed, awk, expr |
| Schleifen/Dateilesen | read |
grep, awk, sed (bei iterativer Verwendung) |
| Laden von Shell-Code | source oder . Dateiname |
Ausführen eines anderen Skripts als Kindprozess |
Arithmetik-Beispiel
Builtin (Schnell):
ZAEHLER=0
(( ZAEHLER++ ))
if (( ZAEHLER > 10 )); then echo "Fertig"; fi
Extern (Langsam):
ZAEHLER=$(expr "$ZAEHLER" + 1)
if [ "$ZAEHLER" -gt 10 ]; then echo "Fertig"; fi
Wann externe Befehle notwendig sind
Während Builtins die Standardwahl für grundlegende Operationen sein sollten, bleiben externe Dienstprogramme für Aufgaben unverzichtbar, die Bash nicht nativ oder effizient bewältigen kann. Sie müssen externe Befehle verwenden, wenn:
- Fortgeschrittene Textverarbeitung: Komplexer Mustervergleich, mehrzeilige Manipulation oder spezifische Formatierung, die von Werkzeugen wie
awk,sedoderperlangeboten werden. - Systemdienstprogramme: Befehle, die tief mit dem Betriebssystem interagieren, wie
ls,ps,find,mountoder Netzwerkwerkzeuge (curl,ping). - Externe Dateien: Lesen oder Schreiben von Dateien in komplexen Formaten, mit denen Bash-Umleitungen Schwierigkeiten haben.
Best Practice für die Verwendung externer Befehle
Wenn Sie unbedingt einen externen Befehl verwenden müssen, versuchen Sie, die Anzahl seiner Aufrufe zu minimieren. Anstatt einen externen Befehl innerhalb einer Schleife auszuführen, strukturieren Sie die Logik so um, dass der gesamte Datenstapel in einem einzigen externen Aufruf verarbeitet wird.
Ineffizient: Verarbeitung von 1000 Dateien einzeln mit stat.
Effizient: Verwendung eines einzigen Aufrufs von find in Kombination mit stat oder eines einzelnen awk-Skripts, um alle erforderlichen Metadaten auf einmal zu sammeln.
Fazit
Leistungsoptimierung in Bash beginnt mit der Vermeidung unnötiger Prozesserzeugung. Verwenden Sie standardmäßig Builtins für Arithmetik, Tests und einfache Zeichenkettenoperationen. Wenn ein externes Werkzeug das richtige ist, führen Sie es einmal über einen Stapel aus, anstatt einmal pro Zeile oder Datei.
- Standardmäßig Builtins verwenden: Für Arithmetik (
(( ))), Zeichenkettenmanipulation (${...}) und Tests ([[ ]]) wählen Sie immer das Shell-Builtin. - I/O in Schleifen vermeiden: Strukturieren Sie Schleifen um, um Batch-Verarbeitung mit einem einzigen externen Befehlsaufruf anstelle vieler kleiner Aufrufe durchzuführen.
- Parameterexpansion verwenden: Bevorzugen Sie
${#var}gegenüberwcoderexprfür die Zeichenkettenlänge. - Abwägungen erkennen: Verwenden Sie externe Dienstprogramme, wenn die erforderliche Funktionalität in Bash nicht verfügbar oder umständlich ist.