Script de bash para recibir y repasar parámetros citados

98

Estoy tratando de obtener los parámetros citados de un script bash para que un script anidado los reciba de forma segura. ¿Algunas ideas?

test.sh

#!/bin/bash
echo $*
bash myecho.sh $*

myecho.sh

#!/bin/bash
 echo $1
 echo $2
 echo $3
 echo $4

Muestra:

bash test.sh aaa bbb '"ccc ddd"'

Resultado:

aaa bbb "ccc ddd"
aaa
bbb
"ccc
ddd"

Resultado deseado

aaa bbb "ccc ddd"
aaa
bbb
ccc ddd
chilltemp
fuente
2
¡Estaba a punto de hacer esa pregunta! Buen tiempo.
Scottie T

Respuestas:

70
#!/bin/bash
echo $*
bash myecho.sh "$@"

Tenga en cuenta que la construcción "$ @" no es específica de bash y debería funcionar con cualquier shell POSIX (al menos lo hace con dash). Tenga en cuenta también que, dado el resultado que desea, no necesita el nivel adicional de cotización en absoluto. IE simplemente llame al script anterior como:

./test.sh 1 2 "3 4"
pixelbeat
fuente
5
"$ @" funciona con cualquier shell Bourne o derivado de shell Bourne (desde 1978 en adelante), incluyendo Korn y Bash. Probablemente el 95% de las veces, el uso de "$ @" es correcto y $ * es incorrecto.
Jonathan Leffler
¡Agradable! Pero, ¿conoce a alguien si hay alguna forma de almacenarlo "tal cual" en una variable? El original $@no está disponible dentro de una función (porque se sobrescribe con los argumentos de la función). Intenté foovar="$@"y foovar=$@+ "$foovar"en la función y ninguno funcionó: - /
bitifet
143

Desea utilizar "$ @" (dólar cotizado en) para pasar parámetros a un subíndice. Al igual que ....

ls-color.sh:

#!/bin/bash
/bin/ls --color=auto "$@"    # passes though all CLI-args to 'ls'


Como qué.....

Desde la página del manual de Bash :

$*- Se expande a los parámetros posicionales, comenzando desde uno. Cuando la expansión ocurre entre comillas dobles, se expande a una sola palabra con el valor de cada parámetro separado por el primer carácter de la variable especial IFS. Es decir, "$*"es equivalente a "$1c$2c...", donde c es el primer carácter del valor de la variable IFS. Si IFS no está configurado, los parámetros están separados por espacios. Si IFS es nulo, los parámetros se unen sin separadores intermedios.

$@- Se expande a los parámetros posicionales, comenzando desde uno. Cuando la expansión ocurre 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 la expansión del último parámetro se une con la última parte del original. palabra. Cuando no hay parámetros posicionales, "$@"y se $@expanden a nada (es decir, se eliminan).


Configurando algunos scripts de demostración ...

echo 'echo -e "\$1=$1\n\$2=$2\n\$3=$3\n\$4=$4"' > echo-params.sh
echo './echo-params.sh $*' > dollar-star.sh
echo './echo-params.sh $@' > dollar-at.sh
echo './echo-params.sh "$*"' > quoted-dollar-star.sh
echo './echo-params.sh "$@"' > quoted-dollar-at.sh
chmod +x *.sh

"$@"- quoted-dollar-at es una transformación de identidad para volver a pasar argumentos a una subcapa (~ 99% del tiempo, esto es lo que pretendía hacer):

./quoted-dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2=            
  # $3= 'cc cc'
  # $4= "ddd ddd"

"$*"- quoted-dollar-star rompe los argumentos en una sola cadena (~ 1% del tiempo que realmente desea este comportamiento, por ejemplo, en un condicional :) if [[ -z "$*" ]]; then ...:

./quoted-dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa  'cc cc' "ddd ddd"   
  # $2=                     
  # $3=             
  # $4=

$*/ $@- sin comillas, ambas formas eliminan un nivel de comillas e interpretan los espacios de las cadenas subyacentes, pero ignoran los caracteres de comillas (casi siempre, esto es un error):

./dollar-star.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc                  
  # $3= cc'
  # $4= "ddd

./dollar-at.sh aaa '' "'cc cc'" '"ddd ddd"'
  # $1= aaa
  # $2= 'cc
  # $3= cc'
  # $4= "ddd

Si quieres divertirte un poco, puedes usar "$ @" para anidar cosas tan profundo como quieras, empujando y sacando elementos de la pila de argumentos si quieres.

function identity() {
  "$@"
}
set -x
identity identity identity identity identity echo Hello \"World\"
# + identity identity identity identity identity echo Hello '"World"'
# + identity identity identity identity echo Hello '"World"'
# + identity identity identity echo Hello '"World"'
# + identity identity echo Hello '"World"'
# + identity echo Hello '"World"'
# + echo Hello '"World"'
# Hello "World"
Dave Dopson
fuente
1
Gracias por la explicación. Solo usé "$ *" para el alias grep.
darkless
¡Me salvas el día!
xyz