Como posso executar uma variável bash como um comando exatamente sem cotação adicional?

Como posso executar uma variável bash como um comando exatamente sem cotação adicional?

Estou tentando fazer um script que precisa salvar um comando para ser executado como uma string. A string em questão precisa conter aspas e, ao tentar executá-la, o bash adiciona caracteres de aspas adicionais, o que em alguns casos faz com que o comando não seja executado conforme o esperado.

Aqui está um exemplo de script. O comando exampleexecutado neste script de exemplo obviamente não faz nada e simplesmente dirá command not found, no entanto, você ainda pode executar o script e ver do que estou falando porque adicionei -xà #!/bin/bashlinha para que o comando exato que está sendo executado seja impresso .

Exemplo:

#!/bin/bash -x

#command typed explicitly
example -options "-i filename"

#command stored in string first
commandstring='example -options "-i filename"'
echo "running command: ${commandstring}"
${commandstring}

A saída da execução deste script para mim é (ignorando os dois erros de "comando não encontrado"):

+ example -options '-i filename'
+ commandstring='example -options "-i filename"'
+ echo 'running command: example -options "-i filename"'
running command: example -options "-i filename"
+ example -options '"-i' 'filename"'

Então você pode ver que a primeira linha é executada conforme o esperado, fornecendo o parâmetro de linha de comando:

-i filename

No entanto, embora o echocomando imprima a string de uma forma que também seria executada perfeitamente, quando a string é colocada na linha de comando ela muda e o parâmetro que está sendo passado torna-se

'"-i' 'nome do arquivo"'

que contém caracteres de aspas adicionais, e isso está causando falha no comando real que estou usando em meu script real.

Existe alguma maneira de evitar isso?

Responder1

Se você estiver usando bash, a maneira mais fácil de salvar exatamente um comando é colocá-lo em um array. Se o comando que você deseja executar for:

example -options "-i filename"

você pode salvá-lo em uma variável de array com:

commandline=(example -options "-i filename")

Então, você pode executar o comando salvo exatamente como está, expandindo @ a matriz entre aspas duplas:

"${commandline[@]}"

A principal coisa a saber aqui é que o shell trata os caracteres de aspas ( "'\) de maneira diferente quando digitados diretamente na linha de comando e quando os encontra dentro de uma expansão de variável como em seu ${commandstring}. Na linha de comando, os caracteres de aspas têm uma função especial de aspas. Dentro de uma expansão de parâmetro, eles são apenas caracteres normais não especiais. Portanto, "-i filename"é uma única palavra quando digitada na linha de comando que é analisada como -i filename, mas os mesmos caracteres em uma variável se expandem para as palavras "-ie filename".


BashFAQ 50cobre este tópico com muito mais detalhes.

informação relacionada