Zugriff auf Bash-Befehlszeilenargumente $ @ vs $ *

326

In vielen SO-Fragen und Bash-Tutorials sehe ich, dass ich auf Befehlszeilenargumente in Bash-Skripten auf zwei Arten zugreifen kann:

$ ~ >cat testargs.sh 
#!/bin/bash

echo "you passed me" $*
echo "you passed me" $@

Was in ... resultiert:

$ ~> bash testargs.sh arg1 arg2
you passed me arg1 arg2
you passed me arg1 arg2

Was ist der Unterschied zwischen $*und $@?
Wann sollte man das erstere verwenden und wann soll man das letztere verwenden?

Oz123
quelle
Schauen Sie sich diese Antwort an: stackoverflow.com/a/842325/671366
Codierung
Die statische Analyse in IntelliJ wird echo "something $@"als Fehler behandelt
Alex Cohn

Antworten:

436

Der Unterschied tritt auf, wenn die speziellen Parameter angegeben werden. Lassen Sie mich die Unterschiede veranschaulichen:

$ set -- "arg  1" "arg  2" "arg  3"

$ for word in $*; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in $@; do echo "$word"; done
arg
1
arg
2
arg
3

$ for word in "$*"; do echo "$word"; done
arg  1 arg  2 arg  3

$ for word in "$@"; do echo "$word"; done
arg  1
arg  2
arg  3

Ein weiteres Beispiel für die Wichtigkeit des Zitierens: Beachten Sie, dass zwischen "arg" und der Zahl zwei Leerzeichen stehen, aber wenn ich $ word nicht zitiere:

$ for word in "$@"; do echo $word; done
arg 1
arg 2
arg 3

und in bash "$@"ist die "Standard" -Liste, über die iteriert werden soll:

$ for word; do echo "$word"; done
arg  1
arg  2
arg  3
Glenn Jackman
quelle
65
+1 Ich habe immer gedacht, dass dieses Konzept am besten anhand eines einfachen Beispiels demonstriert werden kann, in dem das Bash-Handbuch vollständig fehlt.
Chepner
5
Gibt es einen möglichen Anwendungsfall, wenn $*oder "$*"möglicherweise erforderlich, und der Zweck kann nicht von $@oder "$@"erfüllt werden?
Anishsane
5
Welche Version eignet sich besser für ein "Wrapper" -Skript, bei dem die Skriptparameter zu Parametern für einen neuen Befehl werden müssen?
Segfault
7
@Segfault, in diesem Fall immer "$@"mit den Anführungszeichen wählen .
Glenn Jackman
2
Diese Antwort enthält nützliche Beispiele, wäre aber besser, wenn sie auch den Mechanismus dahinter erläutern würde. Warum funktioniert das so?
Lii
254

Eine schöne handliche Übersichtstabelle aus dem Bash Hackers Wiki :

$ * versus $ @ table

Dabei steht cin der dritten Zeile das erste Zeichen des $IFSinternen Feldtrenners, einer Shell-Variablen.

Wenn die Argumente in einer Skriptvariablen gespeichert werden sollen und die Argumente Leerzeichen enthalten sollen, empfehle ich von ganzem Herzen, einen "$*"Trick$IFS anzuwenden, bei dem das interne Feldtrennzeichen auf tab gesetzt ist .

Serge Stroobandt
quelle
42
... wo "c" das erste Zeichen von $ IFS ist
Glenn Jackman
39
... und $IFSsteht für "Internal Field Separator".
Serge Stroobandt
Hier ist ein Beispiel , das Eingaben in Anführungszeichen enthält. Die Eingabe ist auch wichtig!
Serge Stroobandt
Angenommen, ich möchte ein Wrapper-Skript erstellen, das nur die Funktionalität des umschlossenen Befehls nachahmt. Welche Syntax sollte ich verwenden, um die Argumente vom Wrapper-Skript an den inneren Befehl zu übergeben?
Marinos An
44

$ *

Erweitert auf die Positionsparameter, beginnend mit eins. Wenn die Erweiterung in doppelten Anführungszeichen erfolgt, wird sie zu einem einzelnen Wort erweitert, wobei der Wert jedes Parameters durch das erste Zeichen der IFS-Spezialvariablen getrennt ist. Das heißt, "$ *" entspricht "$ 1c $ 2c ...", wobei c das erste Zeichen des Werts der IFS-Variablen ist. Wenn IFS nicht gesetzt ist, werden die Parameter durch Leerzeichen getrennt. Wenn IFS null ist, werden die Parameter ohne dazwischenliegende Trennzeichen verbunden.

$ @

Erweitert auf die Positionsparameter, beginnend mit eins. Wenn die Erweiterung in doppelten Anführungszeichen erfolgt, wird jeder Parameter zu einem separaten Wort erweitert. Das heißt, "$ @" entspricht "$ 1" "$ 2" ... Wenn die Erweiterung in doppelten Anführungszeichen innerhalb eines Wortes auftritt, wird die Erweiterung des ersten Parameters mit dem Anfangsteil des ursprünglichen Wortes und der Erweiterung verbunden des letzten Parameters wird mit dem letzten Teil des ursprünglichen Wortes verbunden. Wenn keine Positionsparameter vorhanden sind, werden "$ @" und $ @ zu nichts erweitert (dh sie werden entfernt).

Quelle: Bash Man

Muffo
quelle
15

$ @ ist dasselbe wie $ *, aber jeder Parameter ist eine Zeichenfolge in Anführungszeichen, dh die Parameter werden ohne Interpretation oder Erweiterung intakt weitergegeben. Dies bedeutet unter anderem, dass jeder Parameter in der Argumentliste als separates Wort betrachtet wird.

Natürlich sollte "$ @" in Anführungszeichen gesetzt werden.

http://tldp.org/LDP/abs/html/internalvariables.html#ARGLIST

rkosegi
quelle
1

In diesem Beispiel können wir den Unterschied zwischen "at" und "asterix" hervorheben, während wir sie verwenden. Ich habe zwei Arrays als "Obst" und "Gemüse" deklariert.

fruits=(apple pear plumm peach melon)            
vegetables=(carrot tomato cucumber potatoe onion)

printf "Fruits:\t%s\n" "${fruits[*]}"            
printf "Fruits:\t%s\n" "${fruits[@]}"            
echo + --------------------------------------------- +      
printf "Vegetables:\t%s\n" "${vegetables[*]}"    
printf "Vegetables:\t%s\n" "${vegetables[@]}"    

Siehe folgendes Ergebnis im obigen Code:

Fruits: apple pear plumm peach melon
Fruits: apple
Fruits: pear
Fruits: plumm
Fruits: peach
Fruits: melon
+ --------------------------------------------- +
Vegetables: carrot tomato cucumber potatoe onion
Vegetables: carrot
Vegetables: tomato
Vegetables: cucumber
Vegetables: potatoe
Vegetables: onion
stefansson
quelle
6
Wissenschaftlich gesehen sind Tomaten Früchte.
Randy
1
Du hast recht! "In der Botanik ist eine Frucht die samenhaltige Struktur in Blütenpflanzen (auch als Angiospermen bekannt), die nach der Blüte aus dem Eierstock gebildet werden." en.wikipedia.org/wiki/Fruit
stefansson
@ Randy: Wissenschaftlich gesehen sind alle Früchte Gemüse (es ist ein Synonym für "Pflanze").
Cris Luengo
@CrisLuengo Häresie! :)
Randy