
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 ls
comando 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.