Frage Saubere Möglichkeit, komplexe mehrzeilige Strings in eine Variable zu schreiben


Ich muss einige komplexe XML in eine Variable in einem Bash-Skript schreiben. Das XML muss innerhalb des Bash-Skripts lesbar sein, da das XML-Fragment dort lebt und nicht von einer anderen Datei oder Quelle gelesen wird.

Also meine Frage ist das, wenn ich eine lange Zeichenfolge habe, die ich in meinem Bash-Skript lesen möchte, was ist der beste Weg, um darüber zu gehen?

Idealerweise möchte ich:

  • um keinem der Charaktere entkommen zu müssen
  • es muss mehrere Zeilen durchbrechen, um es lesbar zu machen
  • behalte den Einzug

Kann dies mit EOF oder so gemacht werden, könnte mir jemand ein Beispiel geben?

z.B.

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


Ursprung


Ich wette, dass Sie diese Daten nur noch einmal in einen Stream ablegen werden. Warum sollten Sie es in einer Variablen speichern, wenn Sie Dinge komplexer machen und Streams verwenden könnten? - Zenexer
sieh das auch: Mehrzeilige Zeichenfolge mit zusätzlichem Leerzeichen (beibehaltene Einrückung) - Yibo Yang


Antworten:


Dadurch wird Ihr Text in Ihre Variable eingefügt, ohne dass die Anführungszeichen entfernt werden müssen. Es behandelt auch unausgewogene Anführungszeichen (Apostrophe, d. H. '). Das Angeben von Anführungszeichen um den Sentinel (EOF) verhindert, dass der Text eine Parametererweiterung erfährt. Das -d'' bewirkt, dass es mehrere Zeilen liest (Zeilenumbrüche ignorieren). read ist eine integrierte Bash, so dass es nicht erforderlich ist, einen externen Befehl wie z 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 zum Vermeiden cat. - James Sneeringer
cat ist ein externer Befehl. Wenn Sie es nicht verwenden, sparen Sie das. Außerdem haben einige die Philosophie, dass, wenn Sie Katze mit weniger als zwei Argumenten verwenden "Ur doin 'es falsch" (was unterscheidet sich von "nutzlosen Gebrauch von cat"). - Dennis Williamson
und niemals einen zweiten EOF einrücken (mehrere Tabellen mit Head Pony) - IljaBek
Ich habe versucht, die obige Aussage während zu verwenden set -e. Es scheint read gibt immer ungleich Null zurück. Sie können dieses Verhalten durch Verwendung von ! read -d ....... - krissi
Und wenn Sie diese Mehrfachleitung verwenden String Variable, um in eine Datei zu schreiben, legen Sie die Variable um "QUOTES" wie echo "${String}" > /tmp/multiline_file.txt oder echo "${String}" | tee /tmp/multiline_file.txt. Ich brauchte mehr als eine Stunde, um das zu finden. - Aditya


Du warst fast da. Entweder du benutzt Katze für die Assemblierung Ihrer Zeichenfolge oder Sie geben die ganze Zeichenfolge an (in diesem Fall müssten Sie die Anführungszeichen in der Zeichenfolge entfernen):

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



Leider macht der Apostroph in "Raphaels" den ersten nicht funktioniert. - Dennis Williamson
Beide Aufgaben funktionieren für mich irgendwann. Das einfache Zitat in VAR1 sollte kein Problem sein (zumindest nicht für Bash). Vielleicht wurdest du durch die Syntaxhervorhebung irregeführt? - joschi
Es funktioniert in einem Skript, aber nicht in einer Bash-Eingabeaufforderung. Tut mir leid, dass ich nicht klarer bin. - Dennis Williamson
Es ist besser, EOF als zu zitieren 'EOF' oder "EOF"Andernfalls werden Shell-Variablen analysiert. - 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}"

Dies sollte innerhalb der Bourne-Shell-Umgebung funktionieren


9
2017-09-05 15:54



+1 diese Lösung erlaubt variable Substitution wie $ {foo} - Offirmo
Upside: sh-kompatibel. Nachteil: Backticks sind in bash veraltet / entmutigt. Wenn ich jetzt zwischen sh und bash wählen müsste ... - Zenexer
seit wann sind Backticks veraltet / entmutigt? nur neugierig - Alexander Mills


Noch eine andere Möglichkeit, das Gleiche zu tun ...

Ich verwende gerne Variablen und spezielle <<- wer fallen lassen Tabellierung am Anfang jeder Zeile, um das Einrücken des Skripts zu erlauben:

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

Warnung: es gibt kein Leerstelle Vor eof aber nur Tabellierung.

<?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>
Einige Erklärungen:
  • Mapfile vollständig gelesen hier Dokument in einem Array.
  • die Syntax "${Pattern[*]}" Wirf dieses Array in eine Zeichenkette.
  • ich benutze IFS=";" weil es kein ... gibt ; in erforderlichen Zeichenfolgen
  • Die Syntax while IFS=";" read file ... verhindern IFS für den Rest des Skripts geändert werden. Nur in diesem read benutze das modifizierte IFS.
  • keine Gabel.

4
2017-07-22 13:45



Beachten Sie, dass mapfile benötigt Bash 4 oder höher. Und die Syntax "${Pattern[*]}" wandelt das Array in eine Zeichenfolge um wenn in Anführungszeichen (wie im Beispielcode gezeigt). - Dennis Williamson
Ja, Bash 4 war sehr Neu wenn diese Frage gestellt wurde. - F. Hauri


Es gibt zu viele Eckfälle in vielen der anderen Antworten.

Um absolut sicher zu sein, dass es keine Probleme mit Leerzeichen, Tabulatoren, IFS usw. gibt, ist es besser, das "heredoc" -Konstrukt zu verwenden, aber den Inhalt des heredocs zu verwenden uuencode wie hier erklärt:

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


2
2018-05-17 09:10