리눅스 명령행 인자: 명령어 옵션과 따옴표, 옵션 끝 표시, $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))
doneWir 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/wwwFü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 sitetotal 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.htmlDanach 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 samesameDie 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 sitels: 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.txtalpha
betaBei der langen Option hängt man den Wert mit einem Gleichheitszeichen an: [--lines=2].
head --lines=2 a.txtalpha
betaAlle 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 -ntotal 4
-rw-r--r-- 1 0 0 10 Oct 28 16:00 -nArgumente hinter -- werden nicht als Optionen gelesen, auch wenn sie mit einem Bindestrich beginnen. [ls -- -n] gab nur den Dateinamen -n aus.
ls -- -n-nInnerhalb 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 fileMan 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.
| Parameter | Enthaltener Wert | C-Funktion main |
|---|---|---|
| $0 | Name des ausgeführten Skripts | argv[0] |
| $1 ~ $9 | Erstes bis neuntes Argument | argv[1] ~ argv[9] |
| ${10} | Ab dem zehnten Argument in geschweiften Klammern | argv[10] |
| $# | Anzahl der Argumente, $0 nicht mitgezählt | argc - 1 |
| "$@" | Alle Argumente, jedes einzeln | argv[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" dwith "$@"
[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.txtbefore shift: $1 = -v, $# = 3
after shift: $1 = a.txt, $# = 2Ab 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.
🔢 FAQ & empfohlene Inhalte
Platzhalter
[Shell-Sonderzeichen] Linux-Platzhalter (Metazeichen)
Ein Beitrag mit Beispielen dazu, wie man Dateinamen mit Platzhalterzeichen wie * und ? sowie mit Zeichenklassen auswählt.
Mehrere Befehle
[Linux] 5 Arten, Befehle zu verketten (Semikolon, Pipe, Ampersand..)
Ein Beitrag zu fünf Arten, mehrere Befehle in einer Zeile mit Semikolon, Pipe, &&, || und & auszuführen.
Zeichenketten ausgeben
echo-Befehl: From Expansion und Quoting
Ein Beitrag dazu, wie man mit echo Zeichenketten und Variablenwerte ausgibt, und zu seinen Optionen.
ℹ️ 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.