Cuando no se citan, $*y $@son lo mismo. No debe usar ninguno de estos, ya que pueden romperse inesperadamente tan pronto como tenga argumentos que contengan espacios o comodines.
"$*"se expande a una sola palabra "$1c$2c...". Por clo general, es un espacio, pero en realidad es el primer personaje de IFS, por lo que puede ser cualquier cosa que elija.
El único buen uso que he encontrado es:
unir argumentos con coma (versión simple)
join1() {
typeset IFS=,
echo "$*"
}
join1 a b c # => a,b,c
unir argumentos con el delimitador especificado (mejor versión)
join2() {
typeset IFS=$1 # typeset makes a local variable in ksh (see footnote)
shift
echo "$*"
}
join2 + a b c # => a+b+c
"$@" se expande para separar palabras: "$1" "$2" ...
Esto es casi siempre lo que quieres. Expande cada parámetro posicional a una palabra separada, lo que lo hace perfecto para tomar argumentos de línea de comando o función y luego pasarlos a otro comando o función. Y debido a que se expande usando comillas dobles, significa que las cosas no se rompen si, por ejemplo, "$1"contiene un espacio o un asterisco ( *).
Escribamos un script llamado svimque se ejecute vimcon sudo. Haremos tres versiones para ilustrar la diferencia.
svim1
#!/bin/sh
sudo vim $*
svim2
#!/bin/sh
sudo vim "$*"
svim3
#!/bin/sh
sudo vim "$@"
Todos estarán bien para casos simples, por ejemplo, un solo nombre de archivo que no contenga espacios:
svim1 foo.txt # == sudo vim foo.txt
svim2 foo.txt # == sudo vim "foo.txt"
svim2 foo.txt # == sudo vim "foo.txt"
Pero solo $*y "$@"funciona correctamente si tienes múltiples argumentos.
svim1 foo.txt bar.txt # == sudo vim foo.txt bar.txt
svim2 foo.txt bar.txt # == sudo vim "foo.txt bar.txt" # one file name!
svim3 foo.txt bar.txt # == sudo vim "foo.txt" "bar.txt"
Y solo "$*"y "$@"funciona correctamente si tiene argumentos que contienen espacios.
svim1 "shopping list.txt" # == sudo vim shopping list.txt # two file names!
svim2 "shopping list.txt" # == sudo vim "shopping list.txt"
svim3 "shopping list.txt" # == sudo vim "shopping list.txt"
Entonces solo "$@"funcionará correctamente todo el tiempo.
typesetes cómo hacer una variable local en ksh( bashy ashusar localen su lugar). Significa IFSque se restaurará a su valor anterior cuando la función regrese. Esto es importante, porque los comandos que ejecute después podrían no funcionar correctamente si IFSestá configurado en algo no estándar.
$*. Siempre lo consideré completamente inútil ... unirme con un delimitador es un buen caso de uso.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 degrepmás que el decvs), invocarcvssmalgunos argumentos se comporta como llamarcvs -nq updatecon estos argumentos."$@"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/shno 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/shes seguro, por lo que solo#!/bin/shse ven afectados los#!/usr/bin/env shguiones , 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 laIFSvariable. Si el valor deIFSes 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 yIFStiene 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,bazyfoo, a continuación:fuente
"$@"hecho se expandió a una lista que consta de la cadena vacía: unix.stackexchange.com/questions/68484/…Aquí hay un script simple para demostrar la diferencia entre
$*y$@:Salida:
En la sintaxis de matriz, no hay diferencia cuando se usa
$*o$@. Solo tiene sentido cuando los usa con comillas dobles"$*"y"$@".fuente
IFS="^${IFS}"embargo, ¿puedes explicar el uso de ?IFS.IFS="^xxxxx"lo haría? El${IFS}sufijo final me hizo pensar que estaba haciendo algo más complicado, como recuperar de alguna manera automáticamente el IFS original al final (por ejemplo: el primer carácter se desplazó automáticamente o algo así).El código que proporcionó dará el mismo resultado. Para entenderlo mejor, intente esto:
La salida ahora debería ser diferente. Esto es lo que obtengo:
Esto funcionó para mí
bash. Que yo sepa, ksh no debería diferir mucho. Esencialmente, las citas$*tratarán todo como una palabra, y las citas$@tratarán la lista como palabras separadas, como se puede ver en el ejemplo anterior.Como ejemplo de uso de la
IFSvariable con$*, considere estoObtengo esto como resultado:
Además, acabo de confirmar que funciona igual
ksh. Ambosbashykshprobados aquí estaban bajo OSX pero no puedo ver cómo eso importaría mucho.fuente
unset IFSal final para restablecerlo al original, pero no funcionó para mí sin ningún problema y al hacerloecho $IFSobtuve el resultado estándar que obtengo. La configuración de losIFScorchetes introduce un nuevo alcance, por lo que, a menos que lo exporte, no afectará el exteriorIFS.echo $IFSno prueba nada, porque el shell ve el,, pero luego divide palabras usandoIFS! Tratarecho "$IFS".IFSdebería resolver eso.IFStenga un valor personalizado diferente antes de llamar a la función. Pero sí, la mayoría de las veces el IFS inquietante funcionará.La diferencia es importante al escribir scripts que deberían usar los parámetros posicionales de la manera correcta ...
Imagine la siguiente llamada:
Aquí solo hay 4 parámetros:
En mi caso,
myuseraddes solo un contenedoruseraddque acepta los mismos parámetros, pero agrega una cuota para el usuario:Observe la llamada a
useradd "$@", con$@cita. Esto respetará los parámetros y los enviará tal como estánuseradd. Si tuviera que poner entre comillas$@(o usar$*también sin comillas), useradd vería 5 parámetros, ya que el tercer parámetro que contenía un espacio se dividiría en dos:(ya la inversa, si se va a utilizar
"$*", useradd sería sólo ven un parámetro:-m -c Carlos Campderrós ccampderros)En resumen, si necesita trabajar con parámetros que respeten parámetros de varias palabras, use
"$@".fuente
// hombre bash . es ksh, afair, comportamiento similar.
fuente
Hablando de diferencias entre
zshybash:Con comillas alrededor
$@y$*,zshy sebashcomportan igual, y supongo que el resultado es bastante estándar entre todos los shells:Sin comillas, los resultados son los mismos para
$*y$@, pero diferentes enbashy enzsh. En este casozshmuestra un comportamiento extraño:(Zsh generalmente no divide datos textuales usando IFS, a menos que se solicite explícitamente, pero observe que aquí el argumento vacío falta inesperadamente en la lista).
fuente
$@no es especial a este respecto: se$xexpande como máximo a una palabra, pero las variables vacías se expanden a nada (no es una palabra vacía). Pruebaprint -l a $foo bconfoovacío o indefinido.Una de las respuestas dice
$*(que considero un "splat") rara vez es útil.Busco google con
G() { IFS='+' ; w3m "https://encrypted.google.com/search?q=$*" ; }Dado que las URL a menudo se dividen con un
+, pero mi teclado hace que seamás fácil de alcanzar que+,$*+$IFSsiento que vale la pena.fuente