Preciso citar substituições de comando ao atribuir sua saída a uma variável?

Preciso citar substituições de comando ao atribuir sua saída a uma variável?

Costumo citar substituições de comandos conforme mostrado abaixo, mesmo ao atribuir sua saída a uma variável:

var="$(command)"

Isso é realmente necessário? Quando isso quebra? A resposta aceitaaquireivindicações:

DIRNAME="$(diretório $FILE)"não vai fazer o que você querse $FILE contiver espaços em branco ou caracteres globbing [?*.

O link aponta para a ótima página do Grey Cat Wiki sobre citações, mas essa página não menciona especificamente as substituições de comandos. E ao citar ovariávelé claramente necessário, citar a substituição do comando em si não parece ser.

No entanto, a mesma postagem conclui com:

DIRNAME="$(dirname "$FILE")" é a forma recomendada. Você pode substituir DIRNAME= por um comando e um espaço sem alterar mais nada, e dirname recebe a string correta.

Que é o que sempre pensei e muitas vezes corrigi postagens aqui que não citavam isso. No entanto, a página wiki vinculada acima também afirma que:

Existem alguns casos em que as aspas duplas podem ser omitidas com segurança:

No lado direito de uma tarefa simples. Você pode escrever foo=$bar sem aspas. Isso é compatível com POSIX.

[. . . ]

Embora var=$(command)não seja realmente uma tarefa "simples", não consegui encontrar um caso em que as aspas fossem realmente necessárias:

$ var=$(echo "foo bar baz")  ## whitespace works
$  echo "$var"
foo bar baz

$ var=$(printf "foo\nbar * baz") ## so do globbing characters
$ echo "$var"
foo
bar * baz

$ var1="foo\nbar * baz"
$ var=$(printf "$var1")  ## printing a variable doesn't make any difference
$ echo "$var" 
foo
bar * baz

$ var=$(printf '%s\n' "$var1")
$ echo "$var"
foo\nbar * baz

$ var=$(printf -- '-e %s\n' "$var1") ## strings starting with - also work
$ echo "$var"
-e foo\nbar * baz

É claro que as aspas são absolutamente necessárias se a substituição do comando estiver sendo usada diretamente para coisas como command1 "$(command2)", mas esse não parece ser o caso ao atribuir a uma variável.

Então, o que estou perdendo? As cotações são sempre necessárias? Qual caso extremo citará uma substituição de comandoao atribuir seu valor de retorno a uma variávelproteger você de? Ou é sempre correto não citar uma substituição de comando se ela estiver no lado direito de uma operação de atribuição de variável?

Responder1

Você faznão precisapara citar a expressão no lado direito de uma tarefa.

O que te irrita é que a outra respostarecomendapara citar, no entanto. Mas trata-se apenas de manutenção de código.

Considere o seguintecorretoexemplo:

DIRNAME=$(dirname "$FILE")
echo "debug: dirname is $DIRNAME"
ls "$DIRNAME"

Agora, depois de um tempo usando este script, você pode pensar que a mensagem de depuração pode ser removida. Então, usando um editor, você removerá a linha de eco. Então você notará que nem precisa mais da variável DIRNAME e simplesmente move o lscomando para substituir o site esquerdo da atribuição. Agora você podeesqueça de adicionar as cotações necessáriase você acaba com issoroteiro quebrado:

ls $(dirname "$FILE")

A probabilidade de tal erro é ainda maior se o primeiro autor for um especialista em shell, mas o segundo editor for um novato.

É claro que é discutível se issorecomendação para evitar um recurso de shell portátilé realmente útil. Pessoalmente, faço isso principalmente como ele recomenda. Eu também faço isso para tarefas mais "simples" como: var="${foo}"(incluindo chaves supérfluas também).

Responder2

Como uma referência,O manual do Bash é claro sobre isso:

Uma variável pode ser atribuída por uma instrução da forma

name=[value]

Se o valor não for fornecido, a variável receberá a string nula. Todos os valores passam por expansão de til, expansão de parâmetros e variáveis, substituição de comandos, expansão aritmética e remoção de aspas (detalhado abaixo). [...]A divisão de palavras não é executada, com exceção de "$@" conforme explicado abaixo.A expansão do nome do arquivo não é executada.

Sem divisão de palavras, sem expansão de nome de arquivo, portanto, não há necessidade de aspas.


Quanto ao POSIX, seção2.9.1 Comandos Simples:

2. As palavras que não sejam atribuições ou redirecionamentos de variáveis ​​serão ampliadas. Se algum campo permanecer após sua expansão Se algum campo permanecer após sua expansão, o primeiro campo será considerado o nome do comando e os campos restantes serão os argumentos do comando.
[...]
4. Cada atribuição de variável deve ser expandida para expansão de til, expansão de parâmetro, substituição de comando, expansão aritmética e remoção de aspas antes de atribuir o valor.

Não tenho certeza se isso deve ser interpretado como significando que a divisão de campo ocorre apenas para expansões feitas na etapa 2. O passo 4 faznãomencionar a divisão de campos, embora a seção sobreDivisão de campotambém não menciona atribuições de variáveis ​​como uma exceção à produção de vários campos.

informação relacionada