Eu tenho um script, que não faz nada útil além de executar os argumentos posicionais. (Estou ciente dos riscos de segurança e o script não faz nada útil porque é um exemplo de trabalho mínimo.)
$ cat script
> #!/usr/bin/env bash
>
> eval "${*}"
$ cat "docu ment"
> Lorem ipsum dolor sit amet
O que eu gostaria de fazer é chamar o script com ./script cat "docu ment"
, ou ./script cat docu\ ment
, mas as aspas ou o caractere de escape desaparecem e o script tentará cat docu ment
, o que não funciona. Como eu corrigiria a cotação em tal caso?
EDIT: O que eu realmente quero fazer é invocar um comando quantas vezes até retornar um código de saída bem-sucedido ou tentar n vezes. Meu script está assim:
#!/usr/bin/env bash
# Try command several times, until it reports success (exit code 0)
# or I give up (tried n times)
tryMax=10
try=1
# Do until loop in bash
while
eval "${@}"
exitcode="${?}"
[[ "${exitcode}" -ne 0 && "${try}" -lt "${tryMax}" ]]
do (( try++ ))
done
if [[ "${exitcode}" -ne 0 ]]; then
echo -n "I tried hard, but did not manage to make this work. The exit code "
echo "of the last iteration of this command was: ${exitcode}."
exit "${exitcode}"
fi
Você não precisa
eval
aqui. Você pode simplesmente usar"$@"
:"$@"
expandirá para todos os argumentos do script como "palavras" separadas - respeitando a citação original que impedia a divisão de palavras - e deixará você com o primeiro argumento como o comando aguardando para ser executado (cat
) e os argumentos restantes como argumentos paracat
(docu ment
) .Onde isso não funcionará:
"$@"
expansão.! cmd
.!
também é processado no início da manipulação de um comando, antes da expansão do parâmetro.x \; y
ou$'x\ny'
oux $'\n' y
, ou o mesmo com&&
ou||
. Todos esses são apenas argumentos regulares.LD_LIBRARY_PATH=/x foo
. Você pode colocá-los antes do nome do script, mas não do comando de argumento.>foo
,3<bar
nele. Eles podem ou não ser afixados ao script, pois o script tem sua própria saída de log.eval
qualquer maneira.( ... )
ou grupo de comandos{ ... ; }
. Eles serão tratados como comandos chamados(
e{
, não como construções sintáticas.$(...)
que precisa ser executada repetidamente . Você pode usar isso (ou qualquer outra construção de shell) para gerar os argumentos originais, mas todos eles serão strings fixas assim que o script começar a ser executado.$RANDOM
ou uma expansão aritmética$((i++))
.time
. Esta é uma palavra reservada do shell e não um comando interno, portanto, também é processada antes da expansão do parâmetro.Caso contrário, no entanto, você pode evitar
eval
completamente e provavelmente deve fazê-lo. É muito frágil para construir corretamente mesmo ignorando quaisquer possíveis problemas de segurança.