Werkzeuge für die Arbeit im Terminal-Fenster Bash-Befehle per Skript, Funktion oder Alias?

Von Mirco Lang

Das Schöne an der Arbeit im Terminal: Sie ist flexibel, lässt sich aber immer effizient und schlank halten – vor allem auch Dank diverser „Abkürzungen“ für Befehle und Befehlsfolgen. Und hier bietet Bash mindestens drei Werkzeuge.

In der Bash lassen sich alle möglichen Befehle und Befehlsfolgen skripten, hier schauen wir uns die Möglichkeiten an.
In der Bash lassen sich alle möglichen Befehle und Befehlsfolgen skripten, hier schauen wir uns die Möglichkeiten an.
(© LuckyStep - stock.adobe.com)

Es gibt viele Möglichkeiten, die Arbeit mit und in Bash zu automatisieren – aber wann ist welche Variante angesagt? Muss es ein Skript sein oder genügt eine Funktion oder gar ein Alias?

Jedes dieser Werkzeuge hat einen ganz speziellen Zweck, aber es gibt eben auch eine große Schnittmenge. Wann also bietet sich ein Alias an, wann eine Funktion und wann ein Skript? Oder mal suggestiv gefragt: Wann wird ein Problem zu komplex für einen Alias, wann für eine Funktion?

Alias: Keine Funktion

Ein Alias ist in Bash im Grunde genau das, was ein Alias auch in der realen Welt ist: Ein alternativer Name. Schon die Man Page legt nahe, dass es darum geht, ein Wort in einem simplen Kommando zu ersetzen.

Das könnte bedeuten, ein Tool über einen komplett anderen, alternativen Aufruf zu starten, also etwa „search“ statt „find“. Oder schlicht abzukürzen, etwa „f“ statt „find“. In der Praxis läuft es meist eher darauf hinaus, Tools standardmäßig mit bestimmten Optionen zu starten beziehungsweise explizite Starter für derlei Optionen zu erstellen, etwa:

ll = 'ls -al'
ls = 'ls -F --color=auto –show-control-chars'

Aber ebenso ist Realität: In den Alias-Definitionen landen schnell auch Pipes und Befehlsketten. Meist beginnt es mit kurzen Pipes, die wieder und wieder genutzt werden, beispielsweise das Durchsuchen der History:

history | grep

Und da bietet sich durchaus ein Alias „hisgrep“ oder dergleichen an, um etwa via …

hisgrep sed

… die genutzten sed-Befehle der Session aufzulisten. Als simple Befehlskette könnten sich ssh-Verbindungen anbieten, die gleich einen Passworthinweis mit sich bringen:

sshcubi='echo MeinHinweis && ssh me@192.168.178.100'

Auch für derlei Kleinigkeiten sind Aliase gut geeignet, die standardmäßig nur in interaktiven Subshells zur Verfügung stehen. Und schon da beginnt die Limitierung von Aliasen. Zwar lassen sie sich durchaus via Bash-Option expandieren und dann auch in nicht interaktiven Subshells nutzen. Der Einsatz in Skripten ist möglich, doch sinnvoll ist das eher nicht.

Aliase stehen schließlich nur lokal zur Verfügung und können auch temporär verändert werden. So ließe sich etwa ein in der Bash-Startupdatei „.bashrc“ hinterlegter Alias für die aktuelle Shell einfach temporär umdefinieren, ohne später etwas rückgängig machen zu müssen. Aliase liegen auch im Speicher der Shell, neue Subshells sind zum Ausführen also nicht nötig.

Kritisch wird es spätestens dann, wenn positionelle Parameter übergeben werden sollen – das geht mit Aliasen nicht. Aber fernab davon, was gehen mag und was nicht: gedacht sind Aliase für simple Wortersetzungen.

Um es mal Gnu.org sagen zu lassen: „For almost every purpose, shell functions are preferred over aliases.“ In diesem Sinne muss man das Thema vielleicht gar nicht erschöpfend ausloten und kann gleich zur Funktion übergehen.

Funktion: Eine Funktion

Abermals verrät der Name schon alles: Eine Function-Definition liefert eine einzelne Funktion. Auch Funktionen liegen im Speicher der Shell, sind aber per export-Anweisung in allen Subshells abrufbar, also auch in Skripten. Und natürlich werden auch Funktionen in der Regel über die „.bashrc“ geladen, sei es direkt oder über eine darin inkludierte separate Sammlung von Funktionen.

Trotz aller Ähnlichkeiten dürften Aliase wesentlich verbreiteter sein – sei es. weil sie genügen oder weil sich bei manch einem im Laufe der Jahre eine stattliche, an Funktionen erinnernde Sammlung aufgebaut hat. Dabei liefern Funktion selbst bei ganz einfachen Aufgaben einen deutlichen Mehrwert.

Noch einmal zu obigen SSH-Logins: Fixe Logins für einzelne Nutzer sind gut und schön, aber flexibel sind sie nicht. In der Praxis meldet man sich aber doch immer wieder auf Rechnern im eigenen Netzwerk mit unterschiedlichen Nutzernamen an – was bleibt in der Regel immer gleich? Die Subnetzmaske und das @, man kann es also auch ersetzen:

sl () { ssh $1@192.168.178.$2 ; }

Fortan genügt die Angabe von Nutzername und letzter Stelle der IP-Adresse, um ein SSH-Login durchzuführen:

sl me 100

Ganz generell sind Functions programmatischer als Aliase, sie erlauben eben wesentlich komplexere Aufgaben, Schleifen, Abfragen und so weiter – und in der regulären Schreibweise sehen sie für jeden mit Programmiererfahrung auch deutlich vertrauter aus. Hier mit zusätzlichem Export für Subshells/Skripte:

testing ()
{
   for i in {1..10}; do
      echo Durchlauf $i
      Sleep 1
   done
}
export -f testing

Und letztlich haben Funktionen auch eine Art Superkraft gegenüber den noch mächtigeren Skripten: Wie gesagt, sie werden ohne eigene Subshell ausgeführt – und können daher auch die Umgebung der aktuellen Shell ändern, also beispielsweise Umgebungsvariablen wie das Root-Verzeichnis.

Jetzt Newsletter abonnieren

Täglich die wichtigsten Infos zu Softwareentwicklung und DevOps

Mit Klick auf „Newsletter abonnieren“ erkläre ich mich mit der Verarbeitung und Nutzung meiner Daten gemäß Einwilligungserklärung (bitte aufklappen für Details) einverstanden und akzeptiere die Nutzungsbedingungen. Weitere Informationen finde ich in unserer Datenschutzerklärung.

Aufklappen für Details zu Ihrer Einwilligung

Ein „Problem“ haben aber auch Funktionen: Sie stehen zwar in Subshells zur Verfügung, aber eben doch nur der einen Shell, der Bash.

Skript: Teilbare Funktion(en)

Bash-Skripte kommen ins Spiel, wenn mindestens einer der folgenden Punkte relevant ist: Es sollen viele einzelne Funktionen abgearbeitet werden, es soll mit anderen Nutzern/Shells/Interpretern teilbar sein, Speicher soll nur bei Bedarf zugeteilt werden.

Skripte werden bei Aufruf in einer eigenen Subshell gestartet – und zwar mit dem über den Shebang angegebenen Interpreter. Alternativ kann das Skript auch über den Interpreter direkt gestartet werden:

bash meinskript
sh meinskript
zsh meinskript

Was selbstredend nicht heißt, dass Skripte nicht auch in der aktuellen Shell ausgeführt werden können, einfach per source-Kommando. Und hier nochmal kurz zum oben angesprochenen Export von Funktionen: Wenn in „meinskript“ die beiden in der .bashrc definierten Funktionen „meinefunktion1“ und „meinefunktion2“ aufgerufen werden und nur „meinefunktion1“ exportiert wurde, wird bei dem Aufruf …

sh meinskript

… auch nur die erste Funktion ausgeführt, da die zweite der sh-Subshell nicht zur Verfügung steht. Hingegen würde ein …

source meinskript

… sehr wohl beide Funktionen aufrufen, da schließlich keine Subshell involviert ist.

Wann also was?

Nun lässt sich trefflich darüber streiten, wann genau welches Werkzeug eingesetzt wird, wie weit man Funktionen und vor allem Aliase ausreizen kann und wie sie sich sogar vollends verzahnen ließen. Aber Skripte, die exportierte Funktionen aufrufen, die expandierte Aliase aufrufen … keine gute Idee. Man kann sich aber durchaus auf den Standpunkt stellen: Wenn es funktioniert, ist es auch okay.

Ohne einen dermaßen festen, vermutlich durch Erfahrung geprägten Standpunkt fährt man eigentlich gut damit, die Tools so einzusetzen, wie es essenziell gedacht ist. Und das heißt:

  • Aliase als Abkürzungen und alternative Aufrufe für simple Kommandos,
  • Funktionen für abgegrenzte Aufgaben, die nur innerhalb einer Shell für einen User relevant sind und
  • Skripte für alles, was komplexer ist und/oder von dritten Nutzern/Interpretern ausgeführt werden soll.

Abseits davon könnte man Funktionen eigentlich immer dann zu eigenständigen Skripten erheben, wenn sie allein für sich genommen eine sinnvolle Aufgabe erledigen – selbst, wenn sie nur daheim auf dem Zweitrechner genutzt werden sollen.

Und ja, wenn man ganz unvoreingenommen in das Thema gegangen ist, klingt das einfach nur naheliegend. Die wohl wichtigste Erkenntnis: Aliase sollte man auf ein Minimum reduzieren, Funktionen sind wesentlich mächtiger und auch in der Schreibweise eleganter.

Soweit so theoretisch – ganz praktisch sind persönliche Präferenzen und Workflows relevant, insofern nochmal: Was funktioniert, ist okay. Ein Beispiel aus der Praxis gefällig? Folgender „Alias“, und man beachte die Anführungszeichen, ist hier seit Jahren im Einsatz, funktioniert tadellos:

alias ml_version='
   tput setaf 1 && echo Systeminfo: && tput sgr0 &&
   lsb_release -idrc &&
   tput setaf 1 && echo Kernel:&& tput sgr0 &&
   uname -r &&
   tput setaf 1 && echo Devices: && tput sgr0 &&
   lsblk -o NAME,SIZE,MOUNTPOINT &&
   tput setaf 1 && echo Speicherplatz: && tput sgr0 &&
   df -h --output=source,size,used,avail,target –exclude-type=tmpfs'

Dieser „Alias“ liefert fix ein paar hübsch formatierte Systeminformationen auf Debian, Ubuntu und deren Abkömmlingen. Um diesen Alias auf fremden Systemen als Skript nutzen zu können, liegt der Code auch auf einem Webserver und lässt sich wunderbar per …

curl cli.help/version | sh

… nutzen. Damit läuft ein und derselbe Code mal als Alias, mal als Skript – das ist nicht unbedingt im Sinne des Erfinders und ganz sicher nicht hübsch. Aber es funktioniert.

Doch ganz nebenbei: Auch wenn hier immer von Bash-Skripten die Rede war, sind Skripte natürlich nicht auf Bash als Interpreter angewiesen – aber wer etwa Python beherrscht, schlägt sich vermutlich sowieso nicht mit allzu vielen Bash-Funktionen und -Skripten, geschweige denn überkonstruierten Aliasen herum.

(ID:47485803)