web-dev-qa-db-fra.com

Utilisation de variables dans un bash heredoc

J'essaie d'interpoler des variables à l'intérieur d'un bash heredoc:

var=$1
Sudo tee "/path/to/outfile" > /dev/null << "EOF"
Some text that contains my $var
EOF

Cela ne fonctionne pas comme je le pensais ($var est traité littéralement, non développé).

J'ai besoin d'utiliser Sudo tee _ car la création du fichier nécessite Sudo. Faire quelque chose comme:

Sudo cat > /path/to/outfile <<EOT
my text...
EOT

Ça ne marche pas, parce que >outfile ouvre le fichier dans le shell actuel, qui n’utilise pas Sudo.

171
Jon

En réponse à votre première question, il n'y a pas de substitution de paramètre car vous avez mis le délimiteur entre guillemets - le manuel de bash dit :

Le format de here-documents est:

      <<[-]Word
              here-document
      delimiter

Aucun développement de paramètre, substitution de commande, développement arithmétique ou développement de chemin d'accès n'est effectué sur Word . Si des caractères dans Word sont cités, le délimiteur est le résultat de suppression de devis sous Word, et les lignes dans le document here-document ne sont pas développées. Si le mot n'est pas entre guillemets, toutes les lignes du document here sont soumises à l'expansion des paramètres, à la substitution de commandes et à l'expansion arithmétique. [...]

Si vous modifiez votre premier exemple pour utiliser <<EOF au lieu de << "EOF" vous constaterez que cela fonctionne.

Dans votre deuxième exemple, le shell appelle Sudo uniquement avec le paramètre cat, et la redirection s’applique à la sortie de Sudo cat en tant qu'utilisateur d'origine. Cela fonctionnera si vous essayez:

Sudo sh -c "cat > /path/to/outfile" <<EOT
my text...
EOT
229
Mark Longair

N'utilisez pas de guillemets avec <<EOF:

var=$1
Sudo tee "/path/to/outfile" > /dev/null <<EOF
Some text that contains my $var
EOF

Le développement de variable est le comportement par défaut dans here-docs. Vous désactivez ce comportement en citant le libellé (avec des guillemets simples ou doubles).

88
mob

En corollaire tardif des réponses précédentes, vous vous retrouvez probablement dans des situations où vous souhaitez un peu mais pas tous variables à interpoler. Vous pouvez résoudre ce problème en utilisant des barres obliques inverses pour échapper aux signes dollar et aux antécédents; ou vous pouvez mettre le texte statique dans une variable.

Name='Rich Ba$tard'
dough='$$$dollars$$$'
cat <<____HERE
$Name, you can win a lot of $dough this week!
Notice that \`backticks' need escaping if you want
literal text, not `pwd`, just like in variables like
\$HOME (current value: $HOME)
____HERE

Démo: https://ideone.com/rMF2XA

Notez que l’un des mécanismes de citation - \____HERE ou "____HERE" ou '____HERE' - désactive toute interpolation de variable et transforme le document here en un morceau de texte littéral.

Une tâche courante consiste à combiner des variables locales avec un script qui doit être évalué par un autre shell, langage de programmation ou hôte distant.

local=$(uname)
ssh -t remote <<:
    echo "$local is the value from the Host which ran the ssh command"
    # Prevent here doc from expanding locally; remote won't see backslash
    remote=\$(uname)
    # Same here
    echo "\$remote is the value from the Host we ssh:ed to"
:
14
tripleee