web-dev-qa-db-fra.com

Manière propre d'écrire une chaîne multiligne complexe dans une variable

J'ai besoin d'écrire du xml complexe dans une variable à l'intérieur d'un script bash. Le xml doit être lisible à l'intérieur du script bash car c'est là que le fragment xml va vivre, il n'est pas lu à partir d'un autre fichier ou source.

Donc, ma question est la suivante: si j'ai une longue chaîne que je veux être lisible par l'homme dans mon script bash, quelle est la meilleure façon de procéder?

Idéalement, je veux:

  • ne pas avoir à échapper à l'un des personnages
  • le faire traverser plusieurs lignes le rendant lisible par l'homme
  • garder son indentation

Cela peut-il être fait avec EOF ou quelque chose, quelqu'un pourrait-il me donner un exemple?

par exemple.

String = <<EOF
 <?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
EOF
112
ChrisInCambo

Cela mettra votre texte dans votre variable sans avoir besoin d'échapper aux guillemets. Il traitera également les citations non équilibrées (apostrophes, c'est-à-dire '). Mettre des guillemets autour de la sentinelle (EOF) empêche le texte de subir une expansion des paramètres. Le -d'' le fait lire plusieurs lignes (ignorer les nouvelles lignes). read est un Bash intégré, il ne nécessite donc pas d'appeler une commande externe telle que cat.

IFS='' read -r -d '' String <<"EOF"
<?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
EOF

Vous y êtes presque arrivé. Soit vous utilisez cat pour l'assemblage de votre chaîne, soit vous citez la chaîne entière (auquel cas vous devrez échapper les guillemets à l'intérieur de votre chaîne):

#!/bin/sh
VAR1=$(cat <<EOF
<?xml version="1.0" encoding='UTF-8'?>
<painting>
  <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's "Foligno" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>
EOF
)

VAR2="<?xml version=\"1.0\" encoding='UTF-8'?>
<painting>
  <img src=\"madonna.jpg\" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's \"Foligno\" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>"

echo "${VAR1}"
echo "${VAR2}"
27
joschi
#!/bin/sh

VAR1=`cat <<EOF
<?xml version="1.0" encoding='UTF-8'?>
<painting>
  <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
  <caption>This is Raphael's "Foligno" Madonna, painted in
  <date>1511</date>-<date>1512</date>.</caption>
</painting>
EOF
`
echo "VAR1: ${VAR1}"

Cela devrait fonctionner correctement dans l'environnement Bourne Shell

14
schweiz

Encore une autre façon de faire de même ...

J'aime utiliser des variables et des <<- Spéciaux qui suppriment la tabulation au début de chaque ligne pour permettre l'indentation du script:

#!/bin/bash

mapfile Pattern <<-eof
        <?xml version="1.0" encoding='UTF-8'?>
        <painting>
          <img src="%s" alt='%s'/>
          <caption>%s, painted in
          <date>%s</date>-<date>%s</date>.</caption>
        </painting>
        eof

while IFS=";" read file alt caption start end ;do
    printf "${Pattern[*]}" "$file" "$alt" "$caption" "$start" "$end"
  done <<-eof
        madonna.jpg;Foligno Madonna, by Raphael;This is Raphael's "Foligno" Madonna;1511;1512
        eof

avertissement: il n'y a pas d'espace vide avant eof mais seulement tabulation .

<?xml version="1.0" encoding='UTF-8'?>
 <painting>
   <img src="madonna.jpg" alt='Foligno Madonna, by Raphael'/>
   <caption>This is Raphael's "Foligno" Madonna, painted in
   <date>1511</date>-<date>1512</date>.</caption>
 </painting>
  • mapfile lit le document entier ici dans un tableau.
  • la syntaxe "${Pattern[*]}" transforme ce tableau en chaîne.
  • J'utilise IFS=";" Car il n'y a pas de ; Dans les chaînes obligatoires
  • La syntaxe while IFS=";" read file ... Empêche la modification de IFS pour le reste du script. En cela, seul read utilise le IFS modifié.
  • pas de fourchette.
6
F. Hauri

Il y a trop de cas de coin dans la plupart des autres réponses.

Pour être absolument sûr qu'il n'y a aucun problème avec les espaces, les tabulations, les IFS, etc., une meilleure approche consiste à utiliser la construction "heredoc", mais à coder le contenu de l'hérédoc en utilisant uuencode comme expliqué ici:

https://stackoverflow.com/questions/6896025/#11379627 .

2
Chris Johnson