리눅스 명령행 인자: 명령어 옵션과 따옴표, 옵션 끝 표시, $1, $# 받기

TestumgebungRHEL-FamilieAlmaLinux 9.8bash 5.1root-Konto
Shell$1$#--

Linux-Kommandozeilenargumente (command-line argument) sind Werte, die man einem Programm übergibt, indem man sie durch Leerzeichen getrennt hinter den Befehlsnamen schreibt. Wir haben auf einem AlmaLinux-9-Server einem Testskript, das die empfangenen Argumente unverändert ausgibt, Optionen, Anführungszeichen, Platzhalter und -- übergeben: Das Aufteilen der Argumente übernahm die Shell, das Lesen der Optionen jeder Befehl selbst.

Die Ausgabe unten ist genau das, was mit bash 5.1 unter dem root-Konto eines AlmaLinux-9.8-Servers herauskam. Die Testskripte und Beispieldateien wurden in einem eigenen Arbeitsordner angelegt, und der Pfad /home/user/www ist ein Beispielwert.

1️⃣ Was sind Linux-Kommandozeilenargumente?

Schreibt man auf der Kommandozeile etwa [Befehl Arg1 Arg2], teilt die Shell die Wörter an den Leerzeichen auf. Das erste Wort wird zum Programm, das ausgeführt wird, und die übrigen Wörter werden der Reihe nach als dessen Argumente übergeben.

Um die übergebenen Argumente sichtbar zu machen, haben wir im Arbeitsordner args.sh angelegt. $0 enthält den Namen, mit dem es aufgerufen wurde, $# die Anzahl der Argumente und ab $1 die Argumente der Reihe nach. Die eckigen Klammern zeigen, wo jedes Argument anfängt und endet.

#!/bin/bash
echo "\$0 = $0"
echo "\$# = $#"
i=1
for a in "$@"; do
  echo "\$$i = [$a]"
  i=$((i+1))
done

Wir haben dem Skript Ausführungsrechte gegeben und es mit drei Wörtern aufgerufen: a, b und c.

./args.sh a b c
$0 = ./args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]

Die drei Wörter landeten in $1, $2 und $3, und $# war 3. Ruft man das Skript auf, indem man seinen Namen hinter bash schreibt, enthält $0 genau den geschriebenen Namen, args.sh.

bash args.sh a b c
$0 = args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]

Nur $0 wurde zu args.sh; die drei Argumente und ihre Anzahl blieben wie zuvor.

2️⃣ Kommandozeilenargumente und Befehlsoptionen

Linux-Befehle schreibt man meist in der Reihenfolge [Befehl -Option Argument]. Optionen ändern, wie der Befehl arbeitet, und Argumente legen die Dateien, Pfade oder Werte fest, mit denen er arbeitet.

ls -l /home/user/www

Für die Shell ist auch -l nur ein Argument. Übergibt man dieselben Wörter an args.sh, landet -l in $1 und der Pfad in $2.

./args.sh -l /home/user/www
$0 = ./args.sh
$# = 2
$1 = [-l]
$2 = [/home/user/www]

-l als Option zu lesen ist Sache von ls. Deshalb bedeutet derselbe Buchstabe in jedem Befehl etwas anderes: -n bei head legt die Zahl der ausgegebenen Zeilen fest, -n bei ls zeigt Besitzer als Nummer statt als Namen.

Manche Optionen nehmen das unmittelbar folgende Wort als eigenen Wert. Beim Befehl find nimmt -type das f und -name das "*.txt" als Wert; ein solcher Wert, der zu einer Option gehört, heißt Optionsargument.

find . -type f -name "*.txt"

Der Punkt . am Anfang dieses Befehls ist ein Argument, das zu keiner Option gehört, und legt den Ordner fest, in dem die Suche beginnt.

3️⃣ Schreibweisen von Linux-Befehlsoptionen

Kurze Optionen beginnen mit einem Bindestrich, bestehen aus einem Buchstaben und lassen sich zusammenschreiben. Zuerst haben wir den Ordner site im Arbeitsordner mit [ls -l -a] ausgegeben.

ls -l -a site
total 8
drwxr-xr-x 3 root root  52 Oct 28 16:00 .
drwxr-xr-x 3 root root 137 Oct 29 01:20 ..
-rw-r--r-- 1 root root  17 Oct 28 16:00 .htaccess
drwxr-xr-x 2 root root  23 Oct 28 16:00 css
-rw-r--r-- 1 root root  14 Oct 28 16:00 index.html

Danach haben wir das mit diff mit der Ausgabe von [ls -la] verglichen, das beide Buchstaben zusammenschreibt.

diff <(ls -l -a site) <(ls -la site) && echo same
same

Die beiden Ausgaben unterschieden sich in keinem einzigen Zeichen. Lange Optionen beginnen mit zwei Bindestrichen und werden als Wort geschrieben; --all bei ls ist dieselbe Option wie -a, daher lieferte auch [ls -l --all site] dasselbe Ergebnis.

Lange Optionen werden auch angenommen, wenn man nur den Anfang schreibt, solange er eindeutig ist. --al passte auf zwei Optionen, --all und --almost-all, deshalb gab ls keine Liste aus und endete mit dem Exit-Code 2.

ls --al site
ls: option '--al' is ambiguous; possibilities: '--all' '--almost-all'
Try 'ls --help' for more information.

Optionen mit einem Wert lassen sich auf mehrere Arten schreiben. Gibt man mit head die ersten zwei Zeilen von a.txt aus, kann man bei der kurzen Option den Wert direkt anhängen: [-n2].

head -n2 a.txt
alpha
beta

Bei der langen Option hängt man den Wert mit einem Gleichheitszeichen an: [--lines=2].

head --lines=2 a.txt
alpha
beta

Alle vier Formen, auch die mit Leerzeichen getrennten [-n 2] und [--lines 2], gaben die zwei Zeilen alpha und beta aus.

ls, head und cat lesen ihre Optionen mit der Funktion getopt_long der C-Bibliothek. Ein Blick mit strings in die drei Programmdateien zeigte, dass alle diesen Funktionsnamen enthalten.

Um dieselben Regeln in der Shell zu prüfen, nutzt man den Befehl getopt aus util-linux. Hinter -o stehen die kurzen Optionen, hinter -l die langen; ein Doppelpunkt hinter einem Buchstaben bedeutet, dass die Option einen Wert erwartet.

getopt -o lan: -l all,lines: -- -la -n 2 --all a.txt
 -l -a -n '2' --all -- 'a.txt'

Das zusammengeschriebene -la wurde in -l und -a aufgeteilt, und -n 2 wurde zu -n mit dem Wert 2 zusammengefasst. a.txt, das keine Option ist, wurde ans Ende hinter -- verschoben.

4️⃣ Argumente in Anführungszeichen und Platzhalter

Ein Dateiname mit Leerzeichen muss in Anführungszeichen stehen, damit er als ein einziges Argument übergeben wird.

./args.sh "my file.txt" report.txt
$0 = ./args.sh
$# = 2
$1 = [my file.txt]
$2 = [report.txt]

Ohne Anführungszeichen wurden my und file.txt getrennt, und $# wurde 3. Übergibt man das so an ls oder cat, suchen sie nach zwei Dateien namens my und file.txt.

./args.sh my file.txt report.txt
$0 = ./args.sh
$# = 3
$1 = [my]
$2 = [file.txt]
$3 = [report.txt]

Platzhalter ersetzt die Shell durch Dateinamen, bevor das Programm sie erhält. Als wir im Arbeitsordner *.txt übergaben, kamen die vier Dateien mit der Endung .txt nach Namen sortiert an.

./args.sh *.txt
$0 = ./args.sh
$# = 4
$1 = [a.txt]
$2 = [b.txt]
$3 = [my file.txt]
$4 = [report.txt]

Das in Anführungszeichen gesetzte "*.txt" ersetzte die Shell nicht, es wurde Zeichen für Zeichen zu einem einzigen Argument. Bei Optionen wie -name von find, bei denen das Programm das Muster selbst vergleicht, übergibt man es so in Anführungszeichen.

./args.sh "*.txt"
$0 = ./args.sh
$# = 1
$1 = [*.txt]

Auch leere Anführungszeichen werden als ein leeres Argument übergeben. Bei [./args.sh '' b] war $# gleich 2 und $1 leer.

5️⃣ Ende der Befehlsoptionen (--)

Ein Argument, das mit einem Bindestrich beginnt, etwa eine Datei namens -n, liest der Befehl als Option. Als wir [ls -n] im Ordner dash ausführten, der nur diese eine Datei enthält, nahm ls -n nicht als Dateinamen, sondern als Option für numerische Ausgabe und listete den Ordner auf.

ls -n
total 4
-rw-r--r-- 1 0 0 10 Oct 28 16:00 -n

Argumente hinter -- werden nicht als Optionen gelesen, auch wenn sie mit einem Bindestrich beginnen. [ls -- -n] gab nur den Dateinamen -n aus.

ls -- -n
-n

Innerhalb eines Befehls werden dieselben Zeichen vor und hinter -- unterschiedlich gelesen. Als wir cat zweimal -n übergaben, wurde das erste -n als Option für Zeilennummern und das -n hinter -- als Dateiname gelesen, sodass der Dateiinhalt mit Zeilennummern erschien.

cat -n -- -n
     1	dash file

Man kann auch einen Pfad davorsetzen und ./-n schreiben; dann beginnt das Argument nicht mit einem Bindestrich und wird als dieselbe Datei -n gelesen.

Auch dass -- als Ende der Optionen gilt, ist eine Regel auf Seiten des Befehls. Übergibt man es an args.sh, das keine Optionen liest, landet auch -- unverändert in $1.

./args.sh -- -a
$0 = ./args.sh
$# = 2
$1 = [--]
$2 = [-a]

Die POSIX Utility Conventions legen fest, dass das erste --, das kein Optionsargument ist, als Ende der Optionen gilt. Deshalb schreibt man bei Befehlen, die diesen Konventionen folgen, Dateinamen, die mit - beginnen, hinter --.

6️⃣ Kommandozeilenargumente im Shell-Skript empfangen

Ein Shell-Skript liest die empfangenen Argumente über Positionsparameter und Spezialparameter. Auch main(int argc, char *argv[]) in einem C-Programm erhält dieselben Argumente; nebeneinandergestellt sieht das so aus.

ParameterEnthaltener WertC-Funktion main
$0Name des ausgeführten Skriptsargv[0]
$1 ~ $9Erstes bis neuntes Argumentargv[1] ~ argv[9]
${10}Ab dem zehnten Argument in geschweiften Klammernargv[10]
$#Anzahl der Argumente, $0 nicht mitgezähltargc - 1
"$@"Alle Argumente, jedes einzelnargv[1] bis zum Ende
"$*"Alle Argumente, mit Leerzeichen zu einem verbunden—

Ein Python-Programm erhält dieselben Argumente als Liste sys.argv. Als wir mit [python3 -c] drei Argumente übergaben, landete das in Anführungszeichen gesetzte my file.txt in einem einzigen Listeneintrag, und im ersten Eintrag stand -c.

python3 -c 'import sys; print(sys.argv)' a "my file.txt" -l
['-c', 'a', 'my file.txt', '-l']

"$@" und "$*" liefern in doppelten Anführungszeichen unterschiedliche Ergebnisse. Um den Unterschied zu sehen, haben wir star.sh angelegt, das beide Formen nacheinander ausgibt.

#!/bin/bash
echo 'with "$@"'
printf '  [%s]\n' "$@"
echo 'with "$*"'
printf '  [%s]\n' "$*"

Wir haben star.sh mit drei Argumenten aufgerufen: a, "b c" und d.

./star.sh a "b c" d
with "$@"
  [a]
  [b c]
  [d]
with "$*"
  [a b c d]

"$@" übergab die drei Argumente einzeln, "$*" verband sie mit Leerzeichen und übergab sie als eines.

Wer die empfangenen Argumente unverändert an einen anderen Befehl weitergibt, nutzt deshalb "$@".

shift verwirft $1 und rückt die übrigen Argumente um eine Stelle nach vorn. Man nutzt es in Skripten, die zuerst eine Option lesen und den Rest als Dateiliste behandeln.

Wir haben shift.sh angelegt, das $1 und $# vor und nach shift ausgibt.

#!/bin/bash
echo "before shift: \$1 = $1, \$# = $#"
shift
echo "after shift:  \$1 = $1, \$# = $#"

Wir haben shift.sh mit drei Argumenten aufgerufen: -v, a.txt und b.txt.

./shift.sh -v a.txt b.txt
before shift: $1 = -v, $# = 3
after shift:  $1 = a.txt, $# = 2

Ab dem zehnten Argument setzt man die Zahl in geschweifte Klammern, etwa ${10}. Wir haben ten.sh angelegt, das $10 und ${10} nebeneinander ausgibt.

#!/bin/bash
echo "\$10 = $10"
echo "\${10} = ${10}"

Wir haben ten.sh 11 Argumente übergeben, a bis k.

./ten.sh a b c d e f g h i j k
$10 = a0
${10} = j

$10 ergab a0, also $1 mit angehängter 0, während ${10} das zehnte Argument j ergab.

🔲 Simulator für Kommandozeilenargumente

Im Simulator unten kannst du args.sh Anführungszeichen, Platzhalter und -- übergeben und auch selbst Befehle eingeben, um zu sehen, wie ls und getopt Optionen lesen und wie star.sh und shift.sh Argumente empfangen.

Simulator für Kommandozeilenargumentebash 5.1
[root@server work]#
Ein virtueller AlmaLinux-Server, der nur in deinem Browser läuft; args.sh gibt die empfangenen Argumente mit Nummern aus, und mit ↑↓ holst du frühere Befehle zurück.

🔢 FAQ & empfohlene Inhalte

Die Obergrenze für die Gesamtlänge von Argumenten und Umgebungsvariablen prüft man mit [getconf ARG_MAX]; auf dem AlmaLinux-9.8-Server waren es 2097152 Byte. Wird sie überschritten, startet das Programm nicht, und es erscheint der Fehler [Argument list too long]. Bei sehr vielen Dateien übergibt man sie nicht auf einmal per Platzhalter, sondern verteilt sie mit -exec von find oder mit xargs.

Ein Argument (argument) ist der Wert, den man beim Ausführen eines Befehls tatsächlich übergibt, ein Parameter (parameter) ist der Name, unter dem die empfangende Seite diesen Wert erhält. Im Shell-Skript nehmen Positionsparameter wie $1 und $2 die übergebenen Argumente auf.

Das in bash eingebaute getopts liest kurze Optionen wie -v eine nach der anderen. Lange Optionen liest es nicht; sollen auch lange Optionen wie --verbose angenommen werden, ordnet man die Argumente zuerst mit dem oben genutzten Befehl getopt.

ℹ️ Affiliate-Hinweis
Die Inhalte dieser Website enthalten Affiliate-Links. Kauft ein Besucher über einen dieser Links ein Produkt oder eine Dienstleistung, erhält die Website vom Verkäufer eine Provision. Der Betrag, den der Käufer zahlt(bei Aktionsrabatten sinkt er ↓), steigt dadurch nicht. Angegebene Preise, Rabatte und Lagerbestände entsprechen dem Stand bei Erstellung und können abweichen; prüfe sie daher vor dem Kauf beim Verkäufer. Produkte werden nach eigenen Kriterien ausgewählt und bewertet, und Provisionen beeinflussen weder die Reihenfolge noch den Inhalt der Bewertungen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Beweisen Sie, dass Sie ein Mensch sind: 1   +   4   =