Eu tenho um script de wrapper que faz algum trabalho e depois passa os parâmetros originais para outra ferramenta:
#!/bin/bash
# ...
other_tool -a -b "$@"
Isso funciona bem, a menos que a "outra ferramenta" seja executada em um subshell:
#!/bin/bash
# ...
bash -c "other_tool -a -b $@"
Se eu chamar meu script wrapper assim:
wrapper.sh -x "blah blup"
então, apenas o primeiro argumento original (-x) é entregue para "other_tool". Na realidade, não crio um subshell, mas passo os argumentos originais para um shell em um telefone Android, o que não deve fazer diferença:
#!/bin/bash
# ...
adb sh -c "other_tool -a -b $@"
Nenhuma das soluções funciona bem. Apenas passe x / \ \ "b \" / aaaaa / \ 'xxx \ yyyy \' / zz \ "offf \" como parâmetro e eles falharão.
Aqui está um invólucro simples que lida com todos os casos. Observe como ele escapa cada argumento duas vezes.
fonte
Mude
$@
para$*
. Fiz um pequeno teste local e funciona no meu caso.Salvar como
test.sh
e torná-lo executável forneceHá uma diferença sutil entre
$*
e$@
, como você pode ver. Veja, por exemplo, http://ss64.com/bash/syntax-parameters.htmlPara a pergunta de acompanhamento nos comentários: você precisa escapar, por exemplo, espaço em branco "duas vezes" para passar uma string com um separador como argumento combinado, por exemplo, com
test.sh
modificado para umwc
wrapper:Isso funciona:
mas:
fonte
wrapper.sh -x "blah blup"
então o subshell recebe três parâmetros (-x, blá, BLUP) em vez de dois (-x "blup blah")"Blah\ blup"
. Experimente e veja se funciona.Está falhando porque você está coagindo uma matriz (os parâmetros posicionais) em uma string.
"$@"
é mágico porque fornece cada parâmetro separado como uma seqüência de caracteres corretamente citada. Adicionar texto adicional quebra a mágica:"blah $@"
é apenas uma única string.Isso pode aproximá-lo:
Obviamente, qualquer parâmetro que contenha uma aspas simples causará problemas.
fonte
Ok, mais explicações:
fonte
Tentei muitas soluções diferentes, um bom recurso, incluindo informações básicas e alternativas, é, por exemplo, o BashFAQ / 096 no Wiki de Greg (também conhecido como GreyCat) . No total, achei os dois seguintes os mais legíveis (dos que estão em funcionamento):
Desde o Bash 4.4 (até onde pude ver no NEWS ), é possível usar a expansão de parâmetros
@Q
como esta:Observe que eu uso
$*
aqui em vez de,$@
porque você deseja"other_tool -a -b ${*@Q}"
ser uma única sequência em vez de uma sequência por argumento passado.Se você quiser fazer o mesmo com uma variável do array bash , precisará da sintaxe
${ARRAY[*]@Q}
(entre aspas).Se você não tem o Bash 4.4 ou posterior disponível ou não tem certeza, esta é minha solução preferida:
Observe que aqui você precisa usar em
"$@"
vez de$@
ou"$*"
ou$*
porque não deseja dividir palavras nos argumentos, portanto, as variantes sem citação não podem ser usadas, e você deseja que o número de argumentos seja preservado, portanto"$*"
não pode ser usado, pois todos os argumentos para uma única sequência. A função retorna todos os argumentos em uma única sequência.Se você não se importa com o espaço adicional na frente do primeiro argumento, pode alterar a
printf
sequência de formatação para" %q"
e remover aseparator
variável. Ou você pode usar o verso da resposta de Gordon Davissons .Essas soluções funcionam com todos os casos que eu pude apresentar, especialmente:
escapeBashArgs
→ nadaescapeBashArgs "" ""
→'' ''
escapeBashArgs " " " "
→' ' ' '
ou\ \ \ \ \
( o último espaço é consumido por este renderizador de sites )escapeBashArgs "a b" c\ d "arg with newline"
→'a b' 'c d' $'arg with\nnewline'
oua\ \ \ \ \ \ b c\ d $'arg with\nnewline'
( a nova linha está entrewith
enewline
, em outras posições, é devido ao agrupamento de linhas neste site )escapeBashArgs '$"'\''({:})'
→'$"'\''({:})'
ou\$\"\'\(\{:\}\)
escapeBashArgs x/\ \ \"b\"/aaaaa/\'xxx\ yyyy\'/zz\"offf\"
→'x/ "b"/aaaaa/'\''xxx yyyy'\''/zz"offf"'
oux/\ \ \"b\"/aaaaa/\'xxx\ yyyy\'/zz\"offf\"
(Testado com o lançamento do GNU bash 5.0.3 (1).)
fonte
fonte