¿Qué significa $ @ en un script de shell?

Respuestas:

243

$@son todos los parámetros pasados ​​al script.

Por ejemplo, si llamas, ./someScript.sh foo barentonces $@será igual a foo bar.

Si lo haces:

./someScript.sh foo bar

y luego dentro de la someScript.shreferencia:

umbrella_corp_options "$@"

esto se pasará umbrella_corp_optionscon cada parámetro individual encerrado entre comillas dobles, lo que permite tomar parámetros con espacio en blanco de la persona que llama y pasarlos.

Har
fuente
1
¿Qué contendría $ @ si lo hiciera someScript.sh foo bar "boo far"?
trusktr
77
$ @ es especial si se escribe entre comillas dobles. Luego dará como resultado una lista de valores citados, en su caso, trusktr, en los tres argumentos "foo", "bar" y "boo far".
Alfe
44
Aunque en general es el caso, $@no no necesariamente provienen de parametros pasados al script ... por ejemplo; set a b "x   y"; printf '(%s)' "$@"salidas(a)(b)(x   y)
Peter.O
Me gusta más la respuesta de Alfe porque da la diferencia principal entre $@y$*
donleyp
106

$@es casi lo mismo que $*ambos significa "todos los argumentos de la línea de comandos". A menudo se usan para simplemente pasar todos los argumentos a otro programa (formando así un contenedor alrededor de ese otro programa).

La diferencia entre las dos sintaxis se muestra cuando tiene un argumento con espacios (p. Ej.) Y $@entre comillas dobles:

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.

Ejemplo: llamar

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

resultará en:

"$@": 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
fuente
2
No son lo mismo, y la página de manual es clara sobre los efectos secundarios de $ * usando IFS, que no es necesariamente espacio. (Si fueran lo mismo, no habría ningún punto, aparte de la compatibilidad quizás, en ofrecer ambos.)
jørgensen
66
No, ellos no son. Y lo dije dos líneas a continuación: "La diferencia entre los dos ..." Para obtener oraciones cortas y aumentar la legibilidad, el lector tiene que leer más de una oración antes de emitir un veredicto: - /
Alfe
2
Alfe, la inserción de Christoffer de esa sola palabra "casi" marcó una gran diferencia, sin sacrificar ninguna terquedad o legibilidad. De hecho, voté por esta respuesta (en oposición a la aceptada) exactamente debido a ese sutil énfasis de la diferencia ... ¡antes de darme cuenta de que estaba casi en contra de su voluntad! ;)
Sz.
Creo que esa palabra marcó una gran diferencia para las personas que emiten un veredicto justo después de leer la primera oración ;-) y nunca fue en contra de mi voluntad. Realmente me gustaría escribir también para estas personas.
Alfe
Muy poco claro wrappedProgram "$*"-> separated by single spaces.pero en tu segundo ejemplo no están separados por espacios individuales.
Felix Dombek
36

Estos son los argumentos de la línea de comando donde:

$@= almacena todos los argumentos en una lista de cadenas
$*= almacena todos los argumentos como una sola cadena
$#= almacena el número de argumentos

Sameer Duwal
fuente
(La inexactitud mencionada anteriormente por @iruvar fue corregida.)
Mateen Ulhaq
13

El uso de un $@medio puro en la mayoría de los casos "lastima al programador lo más que puede", porque en la mayoría de los casos conduce a problemas con la separación de palabras y con espacios y otros caracteres en los argumentos.

En (adivinado) el 99% de todos los casos, se requiere encerrarlo en ": "$@"es lo que se puede usar para iterar confiablemente sobre los argumentos.

for a in "$@"; do something_with "$a"; done
glglgl
fuente
44
Su línea se puede escribir como: para a; hacer algo_con "$ a"; hecho ;-)
Alfe
1
@Alfe lo sé; solo que lo he olvidado. Piense en ello como for a in start_token "$@" end_token; do something_with "$a"; done:-)
glglgl
9

Del manual:

@ @

Se expande a los parámetros posicionales, comenzando desde uno. Cuando la expansión se produce entre comillas dobles, cada parámetro se expande a una palabra separada. Es decir, "$ @" es equivalente a "$ 1" "$ 2" .... Si la expansión entre comillas dobles ocurre dentro de una palabra, la expansión del primer parámetro se une con la parte inicial de la palabra original, y el La expansión del último parámetro se une con la última parte de la palabra original. Cuando no hay parámetros posicionales, "$ @" y $ @ se expanden a nada (es decir, se eliminan).

Christoffer Hammarström
fuente
1

Sentido.

En resumen, se $@expande a los argumentos posicionales pasados ​​del llamador a una función o un script . Su significado depende del contexto : dentro de una función, se expande a los argumentos pasados ​​a dicha función. Si se usa en un script (no dentro del alcance de una función), se expande a los argumentos pasados ​​a dicho script.

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

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

Palabra dividida.

Ahora, otro tema que es de suma importancia cuando se comprende cómo se $@comporta en el shell es la división de palabras . El shell divide los tokens en función del contenido de la IFSvariable. Su valor predeterminado es \t\n; es decir, espacios en blanco, tabulación y nueva línea.

Expandir "$@"le da una copia prístina de los argumentos pasados. Sin embargo, expandirse $@no siempre será así. Más específicamente, si los argumentos contienen caracteres de IFS, se dividirán.


La mayoría de las veces lo que querrá usar es "$@", no $@.

Luis Lavaire
fuente