Script Bash para receber e repassar parâmetros citados

98

Estou tentando obter parâmetros citados de um script bash para serem recebidos com segurança por um script aninhado. Alguma ideia?

test.sh

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

myecho.sh

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

Amostra:

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

Resultado:

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

Resultado desejado

aaa bbb "ccc ddd"
aaa
bbb
ccc ddd
chilltemp
fonte
2
Eu estava prestes a fazer essa pergunta! Bom momento.
Scottie T de

Respostas:

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

Observe que a construção "$ @" não é específica do bash e deve funcionar com qualquer shell POSIX (pelo menos funciona com traço). Observe também que, dada a saída desejada, você não precisa do nível extra de citação. IE, basta chamar o script acima como:

./test.sh 1 2 "3 4"
pixelbeat
fonte
5
"$ @" funciona com qualquer shell Bourne ou derivado de shell Bourne (de 1978 em diante), incluindo Korn e Bash. Provavelmente 95% das vezes, usar "$ @" está correto e $ * errado.
Jonathan Leffler
Agradável! Mas, conhece alguém se existe alguma maneira de armazená- lo "como está" em uma variável? Original $@não está disponível dentro de uma função (porque é sobrescrito por argumentos de função). Eu tentei foovar="$@"e foovar=$@+ "$foovar"na função e nenhuma funcionou: - /
bitifet
143

Você deseja usar "$ @" (dólar entre aspas) para passar parâmetros para um subscrito. Igual a ....

ls-color.sh:

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


Quanto ao porquê ...

Na página de manual do Bash :

$*- Expande-se para os parâmetros posicionais, a partir de um. Quando a expansão ocorre entre aspas duplas, ela se expande para uma única palavra com o valor de cada parâmetro separado pelo primeiro caractere da variável especial IFS. Ou seja, "$*"é equivalente a "$1c$2c...", onde c é o primeiro caractere do valor da variável IFS. Se IFS não estiver definido, os parâmetros serão separados por espaços. Se IFS for nulo, os parâmetros serão unidos sem separadores intermediários.

$@- Expande-se para os parâmetros posicionais, a partir de um. Quando a expansão ocorre entre aspas duplas, cada parâmetro se expande para uma palavra separada. Ou seja, "$@"é equivalente a "$1" "$2" ...Se a expansão entre aspas ocorrer dentro de uma palavra, a expansão do primeiro parâmetro é juntada com a parte inicial da palavra original, e a expansão do último parâmetro é juntada com a última parte do original palavra. Quando não há parâmetros posicionais "$@"e se $@expandem para nada (ou seja, eles são removidos).


Configurando alguns scripts de demonstração ...

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 é uma transformação de identidade para repassar args para um subshell (~ 99% do tempo, isso é o que você pretendia fazer):

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

"$*"- a estrela de um dólar entre aspas esmaga os argumentos em uma única string (~ 1% do tempo em que você realmente deseja esse comportamento, por exemplo, em um condicional if [[ -z "$*" ]]; then ...:):

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

$*/ $@- sem aspas, ambas as formas retiram um nível de aspas e interpretam os espaços das strings subjacentes, mas ignoram os caracteres de aspas (quase sempre, isso é um erro):

./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

Se você quiser se divertir, pode usar "$ @" para aninhar as coisas tão profundamente quanto desejar, empurrando e removendo elementos da pilha de args se quiser.

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
fonte
1
Obrigada pelo esclarecimento. Apenas usei "$ *" para o alias grep.
darkless
Você salva meu dia!
xyz