Como usar uma variável de ambiente dentro de uma string entre aspas no Bash

91

Tentei várias formas do seguinte em um script bash:

#!/bin/bash
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Mas não consigo obter a sintaxe para expandir corretamente a COLUMNSvariável de ambiente.

Tentei várias formas do seguinte:

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W $COLUMNS'

e

svn diff $@ --diff-cmd /usr/bin/diff -x '-y -w -p -W ${COLUMNS}'

e

eval svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Sugestões?

Jamie
fonte
então, o que esses exemplos produzem no seu caso? E o que você quer que eles produzam?
o comando fora do script está funcionando?
DFA
Você já tentousvn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W ""$COLUMNS"
Qian Chen
BTW, usar sem $@aspas torna-o exatamente o mesmo que $*- o que significa que se divide "foo bar"em dois argumentos separados, fooe bar. Se você deseja preservar a lista de argumentos original exatamente como foi fornecida a você, você deseja "$@".
Charles Duffy,

Respostas:

16

Se não tiver certeza, você pode usar a solicitação 'cols' no terminal e esquecer COLUMNS:

COLS=$(tput cols)
TheBonsai
fonte
Por alguma razão, esta é a única solução que consegui trabalhar nesta página (em 11 / maio 10:38 ET). Obrigado
Jamie
397

Apenas uma nota / resumo rápido para quem veio aqui através do Google em busca da resposta à pergunta geral feita no título (como eu estava). Qualquer um dos itens a seguir deve funcionar para obter acesso às variáveis ​​do shell entre aspas:

echo "$VARIABLE"
echo "${VARIABLE}"

O uso de aspas simples é o principal problema. De acordo com o Manual de Referência Bash :

Colocar caracteres entre aspas simples ( ') preserva o valor literal de cada caractere entre aspas. Uma aspa simples não pode ocorrer entre aspas simples, mesmo quando precedida por uma barra invertida. [...] personagens que encerram em aspas duplas ( ") preserva o valor literal de todos os caracteres entre as aspas, com exceção de $, `, \, e, quando a expansão história está habilitado, !. Os caracteres $e `retêm seu significado especial entre aspas duplas (consulte Expansões do Shell). A barra invertida mantém o seu significado especial apenas quando seguido por um dos seguintes caracteres: $, `, ",\, ou nova linha. Entre aspas duplas, as barras invertidas seguidas por um desses caracteres são removidas. As barras invertidas que precedem os caracteres sem um significado especial não são modificadas. Uma aspa dupla pode ser colocada entre aspas duplas, precedendo-a com uma barra invertida. Se ativada, a expansão do histórico será executada, a menos que um !símbolo que aparece entre aspas duplas seja escapado por uma barra invertida. A barra invertida que precede o !não é removida. Os parâmetros especiais *e @têm um significado especial quando entre aspas duplas (ver Shell Parâmetro de Expansão).

No caso específico da pergunta, $ COLUMNS é uma variável especial que possui propriedades não padronizadas (veja a resposta de lhunath acima).

RecursivamenteIrônico
fonte
20
No caso de aspas simples, talvez esta solução alternativa ajude: 'before'"$variable"'after'(conforme declarado nesta resposta: stackoverflow.com/a/13802438/2254346 )
MakisH
Ótima resposta! Eu tive o mesmo problema de referir minha variável env entre aspas simples. Depois que mudei minha aspa simples para aspas duplas, minha variável env foi sendo expandida conforme o esperado.
Binita Bharati
14

Observe que COLUMNSé:

  1. NÃO uma variável de ambiente. É um parâmetro bash comum definido pelo próprio bash.
  2. Definido automaticamente ao receber um SIGWINCHsinal.

Esse segundo ponto geralmente significa que sua COLUMNSvariável só será definida em seu shell interativo , não em um script bash.

Se o seu script stdinestá conectado ao seu terminal, você pode procurar manualmente a largura do seu terminal perguntando ao seu terminal:

tput cols

E para usar isso em seu comando SVN:

svn diff "$@" --diff-cmd /usr/bin/diff -x "-y -w -p -W $(tput cols)"

(Nota: você deve citar "$@" e ficar longe de eval;-))

lhunath
fonte
Obrigado pela informação; saber o que está acontecendo traz uma sensação de catarse ao problema.
Jamie
2

O seguinte script funciona para mim para vários valores de $COLUMNS. Gostaria de saber se você não está definindo COLUMNSantes desta chamada?

#!/bin/bash
COLUMNS=30
svn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W $COLUMNS"

Você pode ecoar $COLUMNSdentro do seu script para ver se ele está configurado corretamente?

Alex B
fonte
Boo, hiss re: unquoted $@- que divide um único parâmetro "two words"em dois parâmetros separados, twoe words. Deve ser "$@"para passar a lista de argumentos exatamente como foi fornecida.
Charles Duffy,
0

Você está fazendo certo, então acho que algo mais está errado (não exportar COLUNAS?).

Um truque para depurar esses casos é fazer um comando especializado (um encerramento para caras da linguagem de programação). Crie um script de shell chamado diff-colunas fazendo:

exec /usr/bin/diff -x -y -w -p -W "$COLUMNS" "$@"

e apenas use

svn diff "$@" --diff-cmd  diff-columns

Desta forma, seu código é mais limpo para ler e mais modular (abordagem de cima para baixo), e você pode testar o código das colunas diff completamente separadamente (abordagem de baixo para cima).

Colas Nahaboo
fonte
A linha de comando é analisada antes que o processo seja bifurcado, portanto, não exportar COLUMNS não pode ser o problema.
Peter van der Heijden
1
Ele diz que seu código é parte de um script bash, portanto, pode ser o problema.
Colas Nahaboo