Comment utiliser des variables entre guillemets simples

11

J'ai une application qui prend comme attributs d'entrée des guillemets doubles intégrés dans des guillemets simples. Prenez par exemple cette bonne commande:

command -p 'cluster="cl1"'

Afin de l'automatiser, j'ai créé un fichier bash en utilisant $CLUSTERcomme variable. Comment devrait être ma commande? En d'autres termes, que dois-je mettre à la place de cl1?

Veuillez noter que si j'ai modifié la commande ci-dessus, elle ne sera pas acceptée. Par exemple: command -p "cluster=cl1"n'est pas accepté

Mohamad-Jaafar NEHME
la source
2
CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"
mikeserv
Une autre possibilité (si vous préférez stocker clisans guillemets dans la CLUSTERvariable):CLUSTER='cl1'; command -p 'cluster="'"$CLUSTER"'"'
jimmij
Enfin, j'ai trouvé la bonne réponse. Merci @jimmij.
Mohamad-Jaafar NEHME

Réponses:

8

Il semble que votre commande définisse peut-être des variables d'environnement basées sur des arguments donnés sur la ligne de commande. Il se peut que vous puissiez faire:

CLUSTER=cl1; cluster=$CLUSTER command

... et lui a défini son environnement lors de l'invocation.

Sinon, les guillemets shell délimitent généralement les arguments ou échappent à d'autres caractères shell spéciaux de l'interprétation shell. Vous pouvez contenir (et donc échapper) différents types de citations shell dans d'autres types en fonction de différentes règles:

  • "''''" - une chaîne entre guillemets peut contenir n'importe quel nombre de guillemets.
  • "\""- une \barre oblique inversée peut échapper à un "guillemet "doux dans une chaîne entre guillemets.
    • Dans ce contexte, une \\barre oblique inversée s'échappe également, le \$jeton d'expansion et les \nlignes électroniques comme indiqué ci-dessous, mais est autrement traité littéralement.
  • "${expand} and then some"- une chaîne entre guillemets peut contenir une $expansion interprétée du shell .
  • '"\'- une 'chaîne entre guillemets peut contenir tout caractère autre qu'un 'guillemet.
  • \- une barre oblique inverse sans guillemets échappe à tout caractère suivant pour une interprétation littérale - même une autre barre oblique inverse - à l'exception d'une ligne \nélectronique.
    • Dans un \\ncas de ligne électronique, la \barre oblique inverse et la ligne \nélectronique sont complètement supprimées de la commande interprétée résultante.
  • ${parameter+expand "$parameter"}- les guillemets résultant d'une expansion du shell ne servent presque jamais de marqueurs de délimitation à l'exception de quelques cas particuliers. Je ne m'aventurerai pas à les décrire davantage ici.

Je trouve étrange que toute application interprète des guillemets dans ses arguments de ligne de commande. Une telle pratique n'a pas beaucoup de sens en ce que - pour les coquilles, au moins - le but principal d'une citation est généralement de délimiter un argument. À l'invocation, cependant, les arguments sont toujours déjà délimités par des \0NULcaractères et une citation ne peut donc pas être très utile.

Même un shell ne prend généralement la peine d'interpréter les guillemets dans l'un de ses arguments d'invocation que lorsqu'il est appelé avec un -ccommutateur - ce qui indique que son premier opérande est en fait un script shell qu'il doit exécuter lors de l'invocation. C'est un cas d' entrée évaluée deux fois .

Cela dit, vous pouvez faire un certain nombre de choses pour passer des guillemets littéraux via des arguments sur la ligne de commande. Par exemple:

CLUSTER='"cl1"'; command -p "cluster=$CLUSTER"

Comme je l'ai noté dans un commentaire auparavant, vous pouvez contenir les "guillemets dans une extension qui est elle-même "citée.

CLUSTER=cl1; command -p "cluster=\"$CLUSTER\""

Vous pouvez échapper à "avec une \barre oblique inverse dans la "chaîne entre guillemets.

CLUSTER=cl1; command -p cluster='"'"$CLUSTER"'"'

Vous pouvez alterner et concaténer les styles de devis pour arriver au résultat final souhaité comme le note @jimmij ci-dessus .

CLUSTER=cl1; ( set -f; IFS=; command -p cluster=\"$CLUSTER\" )

Vous pouvez désactiver à la fois la génération et la $IFSdivision des noms de fichiers - évitant ainsi la nécessité de citer le $expansiontout - et donc uniquement les guillemets. C'est probablement exagéré.

Enfin, il existe un autre type de shell-quote qui pourrait être utilisé. Comme je l'ai noté précédemment, la sh -c "$scriptlet"forme d'invocation du shell est souvent utilisée pour fournir un script de shell sur la ligne de commande. Lorsque cela $scriptletse complique - comme lorsque les guillemets doivent contenir d'autres guillemets - il peut souvent être avantageux d'utiliser un document ici et à la sh -splace - où le shell est spécifiquement chargé d'attribuer tous les opérandes suivants aux paramètres de position comme il le ferait dans un -ccas et pourtant de prendre également son script stdin.

Si votre commande doit interpréter les guillemets de cette manière, je considérerais qu'il vaut mieux qu'elle puisse le faire dans une entrée de fichier. Par exemple:

CLUSTER=cl1
command --stdin <<-SCRIPT
    cluster="$CLUSTER"
SCRIPT

Si vous ne citez pas le délimiteur d'un, <<here-documentalors tout son contenu est traité presque exactement comme il l'a été entre "guillemets - sauf que les "guillemets eux-mêmes ne sont pas traités spécialement. Et donc si nous exécutons ce qui précède à la catplace:

CLUSTER=cl1
cat <<-SCRIPT
        cluster="$CLUSTER"
SCRIPT

... ça imprime ...

cluster="cl1"
mikeserv
la source
1

Comme l'a écrit mikeserv :

 CLUSTER='"cl1"'; command -p "cluster=$CLUSTER" 

« Guillemets » chaque littéral qui contient des espaces / métacaractères et chaque extension: "$var", "$(command "$var")", "${array[@]}", "a & b". Utilisez 'single quotes'pour le code ou littéral $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. Voir
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words

Gilles Quenot
la source
Tu as raison, merci. Mais qu'en est-il de l'automatisation? Supposons que je veuille lire CLUSTER? Je serai de nouveau coincé avec le même problème: variable à l'intérieur de guillemets simples
Mohamad-Jaafar NEHME
@Moi - l'automatisation n'est pas un gros problème, bien que vous deviez aseptiser la variable des "caractères - seuls le premier et le dernier devraient être suffisants. Le vrai problème ici est que votre application interprète les citations dans un argument. L'interprétation d'une citation dans un argument n'est presque jamais une bonne idée car une citation ne doit être qu'un moyen de délimiter un argument - et à l'invocation, cette délimitation est gérée par \0NULs dans tous les cas. Il existe probablement un meilleur moyen de transmettre les informations que vous souhaitez à l'application? Comme un command --'script=/path/to/some/file'ou quelque chose?
mikeserv