Was bedeutet $ @ in einem Shell-Skript?

Antworten:

240

$@sind alle an das Skript übergebenen Parameter.

Wenn Sie zum Beispiel anrufen, ./someScript.sh foo barist $@dies gleich foo bar.

Wenn Sie tun:

./someScript.sh foo bar

und dann Insider- someScript.shReferenz:

umbrella_corp_options "$@"

Dies wird umbrella_corp_optionsmit jedem einzelnen Parameter in doppelten Anführungszeichen übergeben, sodass Parameter mit Leerzeichen vom Aufrufer übernommen und weitergegeben werden können.

Har
quelle
1
Was würde $ @ enthalten, wenn ich es tun würde someScript.sh foo bar "boo far"?
Trusktr
7
$ @ ist etwas Besonderes, wenn es in doppelten Anführungszeichen steht. Dann wird eine Liste der zitierten Werte angezeigt, in Ihrem Fall trusktr, in den drei Argumenten "foo", "bar" und "boo far".
Alfe
4
Obwohl dies im Allgemeinen der Fall ist, $@kommt es nicht unbedingt von Parametern, die an das Skript übergeben wurden ... z. set a b "x   y"; printf '(%s)' "$@"Ausgänge(a)(b)(x   y)
Peter.O
Ich mag Alfe's Antwort besser, weil er den Hauptunterschied zwischen $@und$*
donleyp
105

$@ist fast dasselbe wie $*, beide bedeuten "alle Befehlszeilenargumente". Sie werden häufig verwendet, um einfach alle Argumente an ein anderes Programm zu übergeben (wodurch ein Wrapper um dieses andere Programm gebildet wird).

Der Unterschied zwischen den beiden Syntaxen wird angezeigt, wenn Sie ein Argument mit Leerzeichen (z. B.) $@in doppelten Anführungszeichen setzen:

wrappedProgram "$@"
# ^^^ this is correct and will hand over all arguments in the way
#     we received them, i. e. as several arguments, each of them
#     containing all the spaces and other uglinesses they have.
wrappedProgram "$*"
# ^^^ this will hand over exactly one argument, containing all
#     original arguments, separated by single spaces.
wrappedProgram $*
# ^^^ this will join all arguments by single spaces as well and
#     will then split the string as the shell does on the command
#     line, thus it will split an argument containing spaces into
#     several arguments.

Beispiel: Anrufen

wrapper "one two    three" four five "six seven"

wird darin enden, dass:

"$@": wrappedProgram "one two    three" four five "six seven"
"$*": wrappedProgram "one two    three four five six seven"
                             ^^^^ These spaces are part of the first
                                  argument and are not changed.
$*:   wrappedProgram one two three four five six seven
Alfe
quelle
2
Sie sind nicht gleich, und in der Manpage werden die Nebenwirkungen von $ * bei Verwendung von IFS deutlich - was nicht unbedingt Platz ist. (Wenn sie gleich wären, hätte es keinen anderen Sinn als die Kompatibilität, beides anzubieten.)
jørgensen
6
Nein sind sie nicht. Und ich sagte zwei Zeilen weiter unten: "Der Unterschied zwischen den beiden ..." Um kurze Sätze zu erhalten und die Lesbarkeit zu verbessern, muss der Leser mehr als einen Satz lesen, bevor er ein Urteil
fällen kann
2
Alfe, Christoffers Einfügung dieses einen Wortes "fast" machte einen verdammt großen Unterschied, ohne die Knappheit oder Lesbarkeit zu beeinträchtigen. Tatsächlich habe ich diese Antwort (im Gegensatz zu der akzeptierten) genau aufgrund dieser subtilen Betonung des Unterschieds positiv bewertet ... - bevor ich merkte, dass es fast gegen Ihren Willen war! ;)
Gr.
Ich denke, dieses Wort hat für die Leute, die gleich nach dem Lesen des ersten Satzes ein Urteil fällen, einen verdammt großen Unterschied gemacht ;-) und es war nie gegen meinen Willen. Ich würde wirklich gerne auch für diese Leute schreiben.
Alfe
Sehr unklar. wrappedProgram "$*"-> separated by single spaces.aber in Ihrem zweiten Beispiel sind sie nicht durch einzelne Leerzeichen getrennt.
Felix Dombek
36

Dies sind die Befehlszeilenargumente, bei denen:

$@= speichert alle Argumente in einer Liste von Zeichenfolgen
$*= speichert alle Argumente als einzelne Zeichenfolge
$#= speichert die Anzahl der Argumente

Sameer Duwal
quelle
(Die oben von @iruvar erwähnte Ungenauigkeit wurde behoben.)
Mateen Ulhaq
13

Die Verwendung eines reinen $@Mittels bedeutet in den meisten Fällen "den Programmierer so schwer wie möglich zu verletzen", da dies in den meisten Fällen zu Problemen bei der Worttrennung sowie bei Leerzeichen und anderen Zeichen in Argumenten führt.

In (erratenen) 99% aller Fälle ist es erforderlich, es in Folgendes einzuschließen ": Dies "$@"kann verwendet werden, um die Argumente zuverlässig zu durchlaufen.

for a in "$@"; do something_with "$a"; done
glglgl
quelle
4
Ihre Zeile kann geschrieben werden als: für a; mach etwas_mit "$ a"; fertig ;-)
Alfe
1
@ Alfe Ich weiß, ich habe es einfach vergessen. for a in start_token "$@" end_token; do something_with "$a"; done
Betrachten
9

Aus dem Handbuch:

@

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 dem verbunden Die Erweiterung 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).

Christoffer Hammarström
quelle
1

Bedeutung.

Kurz $@gesagt , erweitert sich um die Positionsargumente, die vom Aufrufer an eine Funktion oder ein Skript übergeben werden . Seine Bedeutung ist kontextabhängig : Innerhalb einer Funktion wird es auf die Argumente erweitert, die an eine solche Funktion übergeben werden. Wenn es in einem Skript verwendet wird (nicht innerhalb des Bereichs einer Funktion), wird es auf die Argumente erweitert, die an ein solches Skript übergeben werden.

$ cat my-sh
#! /bin/sh
echo "$@"

$ ./my-sh "Hi!"
Hi!
$ put () ( echo "$@" )
$ put "Hi!"
Hi!

Wortspaltung.

Ein weiteres Thema, das für das Verständnis des Verhaltens $@in der Shell von größter Bedeutung ist, ist die Wortteilung . Die Shell teilt Token basierend auf dem Inhalt der IFSVariablen. Der Standardwert ist \t\n; dh Leerzeichen, Tabulator und Zeilenumbruch.

Durch Erweitern erhalten "$@"Sie eine makellose Kopie der übergebenen Argumente. Eine Erweiterung $@wird jedoch nicht immer möglich sein. Insbesondere wenn die Argumente Zeichen von enthalten IFS, werden sie aufgeteilt.


Meistens möchten Sie "$@"nicht verwenden $@.

Luis Lavaire
quelle