Respuesta corta: uso"$@"
(tenga en cuenta las comillas dobles). Las otras formas son muy raramente útiles.
"$@"
Es una sintaxis bastante extraña. Se reemplaza por todos los parámetros posicionales, como campos separados. Si no hay parámetros posicionales ( $#
es 0), se "$@"
expande a nada (no es una cadena vacía, sino una lista con 0 elementos), si hay un parámetro posicional, entonces "$@"
es equivalente a "$1"
, si hay dos parámetros posicionales, entonces "$@"
es equivalente a "$1" "$2"
etc.
"$@"
le permite pasar los argumentos de un script o función a otro comando. Es muy útil para los contenedores que hacen cosas como establecer variables de entorno, preparar archivos de datos, etc. antes de llamar a un comando con los mismos argumentos y opciones con los que se llamó al contenedor.
Por ejemplo, la siguiente función filtra la salida de cvs -nq update
. Además del filtrado de salida y el estado de retorno (que es el de grep
más que el de cvs
), invocar cvssm
algunos argumentos se comporta como llamar cvs -nq update
con estos argumentos.
cvssm () { cvs -nq update "$@" | egrep -v '^[?A]'; }
"$@"
se expande a la lista de parámetros posicionales. En los shells que admiten matrices, hay una sintaxis similar para expandir a la lista de elementos de la matriz: "${array[@]}"
(las llaves son obligatorias excepto en zsh). Una vez más, las comillas dobles son algo engañosas: protegen contra la división de campos y la generación de patrones de los elementos de la matriz, pero cada elemento de la matriz termina en su propio campo.
Algunas conchas antiguas tenían lo que podría decirse que era un error: cuando no había argumentos posicionales, se "$@"
expandían a un solo campo que contenía una cadena vacía, en lugar de a ningún campo. Esto condujo a la solución${1+"$@"}
(que se hizo famosa a través de la documentación de Perl ). Solo se ven afectadas las versiones anteriores del shell Bourne real y la implementación de OSF1, ninguno de sus reemplazos modernos compatibles (ash, ksh, bash, ...) se ven afectados. /bin/sh
no se ve afectado en ningún sistema que se lanzó en el siglo XXI que conozca (a menos que cuente la versión de mantenimiento Tru64, e incluso allí /usr/xpg4/bin/sh
es seguro, por lo que solo #!/bin/sh
se ven afectados los #!/usr/bin/env sh
guiones , no los guiones, siempre que su RUTA esté configurada para el cumplimiento POSIX) . En resumen, esta es una anécdota histórica de la que no debe preocuparse.
"$*"
siempre se expande a una palabra. Esta palabra contiene los parámetros posicionales, concatenados con un espacio intermedio. (Más generalmente, el separador es el primer carácter del valor de la IFS
variable. Si el valor de IFS
es la cadena vacía, el separador es la cadena vacía). Si no hay parámetros posicionales, entonces "$*"
es la cadena vacía, si hay dos parámetros posicionales y IFS
tiene su valor predeterminado, entonces "$*"
es equivalente a "$1 $2"
, etc.
$@
y las $*
comillas externas son equivalentes. Se expanden a la lista de parámetros posicionales, como campos separados, como "$@"
; pero cada campo resultante se divide en campos separados que se tratan como patrones comodín de nombre de archivo, como es habitual con expansiones de variables sin comillas.
Por ejemplo, si el directorio actual contiene tres archivos bar
, baz
y foo
, a continuación:
set -- # no positional parameters
for x in "$@"; do echo "$x"; done # prints nothing
for x in "$*"; do echo "$x"; done # prints 1 empty line
for x in $*; do echo "$x"; done # prints nothing
set -- "b* c*" "qux"
echo "$@" # prints `b* c* qux`
echo "$*" # prints `b* c* qux`
echo $* # prints `bar baz c* qux`
for x in "$@"; do echo "$x"; done # prints 2 lines: `b* c*` and `qux`
for x in "$*"; do echo "$x"; done # prints 1 lines: `b* c* qux`
for x in $*; do echo "$x"; done # prints 4 lines: `bar`, `baz`, `c*` and `qux`