No meu ambiente Bash, uso variáveis contendo espaços e essas variáveis na substituição de comandos. Infelizmente não consigo encontrar a resposta no SE.
Qual é a maneira correta de citar minhas variáveis? E como devo fazer isso se estes estiverem aninhados?
DIRNAME=$(dirname "$FILE")
ou cito fora da substituição?
DIRNAME="$(dirname $FILE)"
ou ambos?
DIRNAME="$(dirname "$FILE")"
ou eu uso back-ticks?
DIRNAME=`dirname "$FILE"`
Qual é a maneira certa de fazer isso? E como posso verificar facilmente se as aspas estão definidas corretamente?
bash
shell
quoting
command-substitution
PrimoCocaína
fonte
fonte
Respostas:
Em ordem do pior para o melhor:
DIRNAME="$(dirname $FILE)"
não fará o que você deseja se$FILE
contiver caracteres em branco ou em branco\[?*
.DIRNAME=`dirname "$FILE"`
é tecnicamente correto, mas os backticks não são recomendados para expansão de comandos devido à complexidade extra ao aninhar-los.DIRNAME=$(dirname "$FILE")
está correto, mas apenas porque esta é uma tarefa . Se você usar a substituição de comando em qualquer outro contexto, comoexport DIRNAME=$(dirname "$FILE")
oudu $(dirname "$FILE")
, a falta de aspas causará problemas se o resultado da expansão contiver espaços em branco ou caracteres brilhantes.DIRNAME="$(dirname "$FILE")"
é a maneira recomendada. Você pode substituirDIRNAME=
por um comando e um espaço sem alterar mais nada edirname
recebe a sequência correta.Para melhorar ainda mais:
DIRNAME="$(dirname -- "$FILE")"
funciona se$FILE
começa com um traço.DIRNAME="$(dirname -- "$FILE"; printf x)" && DIRNAME="${DIRNAME%?x}"
funciona mesmo que$FILE
termine com uma nova linha, pois$()
retira novas linhas no final da saída edirname
gera uma nova linha após o resultado. Sheeshdirname
, por que você tem que ser diferente?Você pode aninhar expansões de comando quantas vezes quiser. Com
$()
você sempre criar um novo contexto citando, para que possa fazer coisas como esta:Você não quer tentar isso com backticks.
fonte
$()
você sempre cria um novo contexto de cotação", assim é como fora das aspas externas. Não há mais nada, até onde eu sei.Você sempre pode mostrar os efeitos da cotação variável com
printf
.Divisão de palavras feita em
var1
:var1
citado, portanto, nenhuma divisão de palavras:Palavra dividida por
var1
dentro$()
, equivalente aecho "hello" "world"
:Não há divisão de palavras
var1
, não há problema em não citar o$()
:Palavra dividida
var1
novamente:Citando as duas, a maneira mais fácil de ter certeza.
Problema de globbing
Não citar uma variável também pode levar à expansão global de seu conteúdo:
Observe que isso acontece depois que a variável é expandida apenas. Não é necessário citar um globo durante a atribuição:
Use
set -f
para desativar esse comportamento:E
set +f
para reativá-lo:fonte
var1='hello * world'
para ilustrar também o problema de globbing.Além da resposta aceita:
Embora eu geralmente concorde com a resposta da @ l0b0 aqui, suspeito que a colocação de backticks vazios na lista "pior para o melhor" seja pelo menos parcialmente um resultado da suposição que
$(...)
está disponível em todos os lugares. Percebo que a pergunta especifica o Bash, mas há muitas vezes em que o Bash significa/bin/sh
, o que nem sempre pode ser realmente o shell Bourne Again completo.Em particular, o shell Bourne comum não saberá o que fazer
$(...)
, portanto, scripts que afirmam ser compatíveis com ele (por exemplo, através de uma#!/bin/sh
linha shebang) provavelmente se comportarão mal se forem realmente executados pelo "real"/bin/sh
- isto é interesse especial quando, digamos, produzir scripts init ou empacotar pré e pós scripts, e conseguir um em um local surpreendente durante a instalação de um sistema básico.Se algo disso parece algo que você planeja fazer com essa variável, o aninhamento é provavelmente menos uma preocupação do que ter o script realmente, previsivelmente, executado. Quando se trata de um caso bastante simples e a portabilidade é uma preocupação, mesmo que eu espere que o script geralmente seja executado em sistemas onde
/bin/sh
está o Bash, geralmente costumo usar backticks por esse motivo, com várias atribuições em vez de aninhar.Dito tudo isso, a onipresença de shells que implementam
$(...)
(Bash, Dash, et al.) Nos deixa em um bom local para ficar com a sintaxe POSIX mais bonita, mais fácil de aninhar e mais recentemente preferida na maioria dos casos, por todas as razões que @ l0b0 menciona.Além: isso também apareceu ocasionalmente no StackOverflow -
fonte