Vraag Schone manier om complexe meerregelige reeks naar een variabele te schrijven


Ik moet een aantal complexe XML naar een variabele binnen een bash-script schrijven. De XML moet leesbaar zijn in het bash-script, omdat dit het punt is waar het xml-fragment zal leven, het wordt niet gelezen vanuit een ander bestand of bron.

Dus mijn vraag is dit als ik een lange reeks heb die ik leesbaar wil maken in mijn bash-script, wat is de beste manier om dit aan te pakken?

Idealiter wil ik:

  • om geen van de personages te hoeven missen
  • laat het breken over meerdere lijnen waardoor het menselijk leesbaar is
  • behoud zijn inspringing

Kan dit worden gedaan met EOF of zoiets, zou iemand mij een voorbeeld kunnen geven?

bijv.

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


oorsprong


Ik durf te wedden dat je die gegevens gewoon weer in een stream dumpt. Waarom zou je het in een variabele opslaan als je dingen ingewikkelder zou kunnen maken en stromen zou kunnen gebruiken? - Zenexer
zie dit ook: Meerregelige reeks met extra ruimte (behouden inspringing) - Yibo Yang


antwoorden:


Hiermee wordt uw tekst in uw variabele geplaatst zonder dat u aan de aanhalingstekens hoeft te ontsnappen. Het zal ook onevenwichtige aanhalingstekens behandelen (apostrofen, d.w.z. '). Door citaten rond de sentinel (EOF) te plaatsen, wordt voorkomen dat de tekst parameteruitbreiding ondergaat. De -d'' zorgt ervoor dat het meerdere regels leest (negeer nieuwe regels). read is een Bash-ingebouwd, zodat het niet nodig is om een ​​extern commando zoals 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 om te vermijden cat. - James Sneeringer
cat is een extern commando. Niet gebruiken bespaart dat. Plus, sommigen hebben de filosofie dat als je kat met minder dan twee argumenten gebruikt "Ur doin 'it wrong" (wat anders is dan "nutteloos gebruik van cat"). - Dennis Williamson
en nooit een tweede EOF inspringen .... (meerdere tafels om het hoofd te knallen) - IljaBek
Ik heb geprobeerd om de bovenstaande verklaring te gebruiken terwijl set -e. Het lijkt read retourneert altijd niet-nul. Je kunt dit gedrag verdiepen door te gebruiken ! read -d ....... - krissi
En als u deze multi-lijn gebruikt String variabele om naar een bestand te schrijven, plaats de variabele rond "QUOTES" zoals echo "${String}" > /tmp/multiline_file.txt of echo "${String}" | tee /tmp/multiline_file.txt. Het kostte me meer dan een uur om dat te vinden. - Aditya


Je bent er bijna geweest. Ofwel gebruik je kat voor de assemblage van je snaar of je citeert de hele snaar (in dat geval zou je aan de aanhalingstekens in je snaar moeten ontsnappen):

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



Helaas, de apostrof in "Raphael's" maakt de eerste niet werken. - Dennis Williamson
Beide opdrachten werken uiteindelijk voor mij. Het enkele citaat in VAR1 zou geen probleem mogen zijn (althans niet voor bash). Misschien bent u misleid door de syntax highlighting? - joschi
Het werkt in een script, maar niet bij een Bash-prompt. Sorry dat ik niet duidelijker ben. - Dennis Williamson
Het is beter om EOF te citeren als 'EOF' of "EOF", anders worden shell-variabelen geparseerd. - 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}"

Dit zou goed moeten werken in de omgeving van de Bourne shell


9
2017-09-05 15:54



+1 deze oplossing staat een variabele vervanging toe zoals $ {foo} - Offirmo
Ondersteboven: sh-compatibel. Nadeel: backticks zijn gedeprecieerd / ontmoedigd bij bash. Als ik moest kiezen tussen sh en bash ... - Zenexer
sinds wanneer zijn backticks verouderd / ontmoedigd? gewoon nieuwsgierig - Alexander Mills


Nog een andere manier om hetzelfde te doen ...

Ik gebruik graag variabelen en speciaal <<- wie vallen tabel aan het begin van elke regel om inspringen van scripts toe te staan:

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

waarschuwing: er is geen lege ruimte voor eof maar alleen tabel.

<?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>
Enkele verklaringen:
  • mapbestand volledig lezen hier document in een array.
  • de syntaxis "${Pattern[*]}" cast deze array in een string.
  • ik gebruik IFS=";" omdat er geen is ; in vereiste reeksen
  • De syntaxis while IFS=";" read file ... voorkomen IFS worden aangepast voor de rest van het script. Alleen hierin read gebruik de gewijzigde IFS.
  • geen vork.

4
2017-07-22 13:45



Let daar op mapfile vereist Bash 4 of hoger. En de syntaxis "${Pattern[*]}" zet de array in een tekenreeks wanneer tussen aanhalingstekens (zoals getoond in de voorbeeldcode). - Dennis Williamson
Ja, bash 4 was erg nieuwe toen deze vraag werd gesteld. - F. Hauri


Er zijn teveel hoekgevallen in veel van de andere antwoorden.

Om er absoluut zeker van te zijn dat er geen problemen zijn met spaties, tabbladen, IFS enz., Is het beter om het "heredoc" -construct te gebruiken, maar de inhoud van de heredoc te coderen met behulp van uuencode zoals hier uitgelegd:

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


2
2018-05-17 09:10