Question Méthode propre pour écrire des chaînes complexes de plusieurs lignes dans une variable


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

Ma question est donc la suivante: quelle est la meilleure façon de s'y prendre si j'ai une longue chaîne que je veux être lisible par l'homme dans mon script bash?

Idéalement je veux:

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

Est-ce que cela peut ê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

94
2017-10-08 10:54


origine


Je suis prêt à parier que vous allez simplement vider ces données dans un flux. Pourquoi le stocker dans une variable quand vous pouvez rendre les choses plus complexes et utiliser des flux? - Zenexer
voir ça aussi: Chaîne multiligne avec espace supplémentaire (indentation préservée) - Yibo Yang


Réponses:


Cela mettra votre texte dans votre variable sans avoir besoin d'échapper aux guillemets. Il traitera également les guillemets non équilibrés (apostrophes, c.-à-d. '). Mettre des guillemets autour de la sentinelle (EOF) empêche le texte de se développer. le -d'' provoque la lecture de plusieurs lignes (ignorer les nouvelles lignes). read est un Bash intégré de sorte qu'il ne nécessite 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

123
2017-10-08 12:37



+1 pour éviter cat. - James Sneeringer
cat est une commande externe. Ne pas l'utiliser enregistre cela. De plus, certains ont la philosophie que si vous utilisez un chat avec moins de deux arguments "Ur doin 'it false" (ce qui est distinct de "l'utilisation inutile de cat"). - Dennis Williamson
et jamais jamais indenter deuxième EOF .... (table multiple à la frange en cause) - IljaBek
J'ai essayé d'utiliser la déclaration ci-dessus en set -e. Il semble read renvoie toujours non nul. Vous pouvez épaissir ce comportement en utilisant ! read -d ....... - krissi
Et si vous utilisez cette multi-ligne String variable pour écrire dans un fichier, mettez la variable autour de "QUOTES" comme echo "${String}" > /tmp/multiline_file.txt ou echo "${String}" | tee /tmp/multiline_file.txt. Cela m'a pris plus d'une heure pour le trouver. - Aditya


Vous avez été presque là. Soit vous utilisez chat pour l'assemblage de votre chaîne ou vous citez la chaîne entière (dans ce cas, vous devez échapper aux 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}"

25
2017-10-08 11:14



Malheureusement, l'apostrophe dans "Raphael's" empêche le premier de fonctionner. - Dennis Williamson
Les deux missions fonctionnent pour moi par la suite. La citation simple dans VAR1 ne devrait pas poser de problème (du moins pas pour bash). Peut-être avez-vous été induit en erreur par la coloration syntaxique? - joschi
Cela fonctionne dans un script, mais pas à l'invite de Bash. Désolé de ne pas être plus clair. - Dennis Williamson
Il est préférable de citer EOF comme 'EOF' ou "EOF", sinon les variables shell seront analysées. - Stanislav German-Evtushenko


#!/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


9
2017-09-05 15:54



+1 cette solution autorise la substitution de variable comme $ {foo} - Offirmo
Upside: sh-compatible. Inconvénient: les backticks sont déconseillés / déconseillés en bash. Maintenant, si je devais choisir entre sh et bash ... - Zenexer
depuis quand les backticks sont-ils déconseillés / déconseillés? juste curieux - Alexander Mills


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

J'aime utiliser des variables et spécial <<- qui laisse tomber 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

Attention: il n'y a pas 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>
Quelques explications:
  • mapfile lu en entier ici document dans un tableau.
  • la syntaxe "${Pattern[*]}" jette ce tableau dans une chaîne.
  • j'utilise IFS=";" Parce qu'il n'y a pas ; dans les chaînes requises
  • La syntaxe while IFS=";" read file ... prévenir IFS être modifié pour le reste du script. En cela, seulement read utilisez le modifié IFS.
  • pas de fourchette.

4
2017-07-22 13:45



Notez que mapfile nécessite Bash 4 ou supérieur. Et la syntaxe "${Pattern[*]}" jette le tableau dans une chaîne entre guillemets (comme indiqué dans l'exemple de code). - Dennis Williamson
Oui, bash 4 était très Nouveau quand cette question a été posée. - F. Hauri


Il y a trop de cas dans de nombreuses autres réponses.

Pour être absolument sûr qu'il n'y a pas de problèmes d'espaces, de tabulations, d'IFS, etc., une meilleure approche consiste à utiliser la construction "heredoc", mais à coder le contenu de heredoc à l'aide de uuencode comme expliqué ici:

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


2
2018-05-17 09:10