Comment utiliser une variable d'environnement dans une chaîne entre guillemets dans Bash

91

J'ai essayé différentes formes de ce qui suit dans un script bash:

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

Mais je ne peux pas obtenir la syntaxe pour développer correctement la COLUMNSvariable d'environnement.

J'ai essayé différentes formes de ce qui suit:

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

et

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

et

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

Suggestions?

Jamie
la source
alors que produisent ces exemples dans votre cas? Et que voulez-vous qu'ils produisent?
la commande en dehors du script fonctionne?
dfa
Avez-vous essayésvn diff $@ --diff-cmd /usr/bin/diff -x "-y -w -p -W ""$COLUMNS"
Qian Chen
BTW, l'utilisation d'un $@guillemet le rend exactement identique à $*- c'est-à-dire qu'il se décompose "foo bar"en deux arguments distincts, fooet bar. Si vous souhaitez conserver la liste d'arguments d'origine telle qu'elle vous a été fournie, vous le souhaitez "$@".
Charles Duffy

Réponses:

16

En cas de doute, vous pouvez utiliser la requête 'cols' sur le terminal et oublier COLUMNS:

COLS=$(tput cols)
TheBonsai
la source
Pour une raison quelconque, c'est la seule solution que j'ai pu obtenir sur cette page (à partir du 11 / mai 10h38 HE). Merci
Jamie
398

Juste une petite note / résumé pour tous ceux qui sont venus ici via Google à la recherche de la réponse à la question générale posée dans le titre (comme je l'étais). L'un des éléments suivants devrait fonctionner pour accéder aux variables shell entre guillemets:

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

L'utilisation de guillemets simples est le principal problème. Selon le manuel de référence Bash :

Mettre les caractères entre guillemets simples ( ') préserve la valeur littérale de chaque caractère entre les guillemets. Un guillemet simple peut ne pas apparaître entre guillemets simples, même s'il est précédé d'une barre oblique inverse. [...] caractères Enserrage guillemets doubles ( ") préserve la valeur littérale de tous les caractères dans les citations, à l'exception de $, `, \et, lorsque l' expansion de l' histoire est activée, !. Les caractères $et `conservent leur signification spéciale entre guillemets (voir Expansions Shell). La barre oblique inverse conserve sa signification que lorsqu'il est suivi d'un des caractères suivants: $, `, ",\, ou nouvelle ligne. Entre guillemets doubles, les barres obliques inverses suivies de l'un de ces caractères sont supprimées. Les barres obliques inverses précédant les caractères sans signification particulière ne sont pas modifiées. Un guillemet double peut être placé entre guillemets doubles en le précédant d'une barre oblique inverse. Si cette option est activée, le développement de l'historique sera effectué à moins que les !guillemets doubles ne soient échappés à l'aide d'une barre oblique inverse. La barre oblique inverse précédant le !n'est pas supprimée. Les paramètres spéciaux *et @ont une signification particulière lorsqu'ils sont entre guillemets (voir Extension des paramètres du shell).

Dans le cas spécifique posé dans la question, $ COLUMNS est une variable spéciale qui a des propriétés non standard (voir la réponse de lhunath ci-dessus).

RécursivementIronique
la source
20
Dans le cas des guillemets simples, cette solution de contournement peut peut-être aider: 'before'"$variable"'after'(comme indiqué dans cette réponse: stackoverflow.com/a/13802438/2254346 )
MakisH
Très bonne réponse! J'ai eu le même problème de référencer ma variable env entre guillemets simples. Une fois que j'ai changé mon guillemet simple en guillemets doubles, ma variable env a été développée comme prévu.
Binita Bharati
14

Notez que COLUMNSc'est:

  1. PAS une variable d'environnement. C'est un paramètre bash ordinaire qui est défini par bash lui-même.
  2. Réglé automatiquement à la réception d'un SIGWINCHsignal.

Ce deuxième point signifie généralement que votre COLUMNSvariable ne sera définie que dans votre shell interactif , pas dans un script bash.

Si votre script stdinest connecté à votre terminal, vous pouvez rechercher manuellement la largeur de votre terminal en demandant à votre terminal:

tput cols

Et pour l'utiliser dans votre commande SVN:

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

(Remarque: vous devez citer "$@" et rester à l'écart eval;-))

lhunath
la source
Merci pour l'information; savoir ce qui se passe apporte un sentiment de catharsis à la question.
Jamie
2

Le script suivant fonctionne pour moi pour plusieurs valeurs de $COLUMNS. Je me demande si vous ne réglez pas COLUMNSavant cet appel?

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

Pouvez-vous faire écho à l' $COLUMNSintérieur de votre script pour voir s'il est défini correctement?

Alex B
la source
Boo, sifflement re: sans guillemets $@- qui divise un seul paramètre "two words"en deux paramètres distincts, twoet words. "$@"Cela devrait être de passer la liste d'arguments exactement telle qu'elle a été donnée.
Charles Duffy
0

Vous le faites correctement, donc je suppose que quelque chose d'autre est en faute (pas d'exporter des COLONNES?).

Une astuce pour déboguer ces cas est de faire une commande spécialisée (une fermeture pour les gars du langage de programmation). Créez un script shell nommé diff-columns en faisant:

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

et juste utiliser

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

De cette façon, votre code est plus propre à lire et plus modulaire (approche descendante), et vous pouvez tester le code des colonnes différentiellement séparément (approche ascendante).

Colas Nahaboo
la source
La ligne de commande est analysée avant que le processus ne soit forké, donc ne pas exporter COLUMNS ne peut pas être le problème.
Peter van der Heijden
1
Il dit que son code fait partie d'un script bash, donc ça peut être le problème.
Colas Nahaboo