Modo pulito per scrivere una stringa multi-linea complessa in una variabile


109

Ho bisogno di scrivere alcuni xml complessi in una variabile all'interno di uno script bash. L'xml deve essere leggibile all'interno dello script bash poiché è qui che vivrà il frammento xml, che non viene letto da un altro file o sorgente.

Quindi la mia domanda è questa se ho una lunga stringa che voglio essere leggibile dall'uomo nel mio script bash, qual è il modo migliore per farlo?

Idealmente voglio:

  • per non dover sfuggire a nessuno dei personaggi
  • farlo rompere su più righe rendendolo leggibile dall'uomo
  • mantieni il rientro

Questo può essere fatto con EOF o qualcosa del genere, qualcuno potrebbe darmi un esempio?

per esempio

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

Sono disposto a scommettere che scaricherai di nuovo quei dati in uno stream. Perché archiviarlo in una variabile quando potresti rendere le cose più complesse e utilizzare i flussi?
Zenexer,

Risposte:


140

Questo inserirà il tuo testo nella tua variabile senza dover sfuggire alle virgolette. Gestirà anche virgolette non bilanciate (apostrofi, ad es '.). Mettere le virgolette attorno alla sentinella (EOF) impedisce al testo di subire l'espansione dei parametri. Lo -d''fa leggere più righe (ignora le nuove righe). readè un Bash integrato quindi non richiede la chiamata di un comando esterno come 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

17
+1 per evitare cat.
James Sneeringer,

4
catè un comando esterno. Non usarlo si risparmia. Inoltre, alcuni hanno la filosofia secondo cui se stai usando cat con meno di due argomenti "Ur doin 'it wrong" (che è distinto da "uso inutile di cat").
Dennis Williamson,

9
e non indentare mai il secondo EOF .... (più colpi da tavolo a testa coinvolti)
IljaBek,

9
Ho provato a usare la frase sopra mentre set -e. Sembra readsempre restituito diverso da zero. Puoi addensare questo comportamento usando! read -d .......
krissi l'

11
E se stai usando questa Stringvariabile multilinea per scrivere su un file, metti la variabile attorno a "QUOTE" come echo "${String}" > /tmp/multiline_file.txto echo "${String}" | tee /tmp/multiline_file.txt. Mi ci è voluto più di un'ora per trovarlo.
Aditya,

28

Ci sei stato quasi. O usi cat per l'assemblaggio della stringa o citi l'intera stringa (nel qual caso dovresti sfuggire alle virgolette all'interno della stringa):

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

Sfortunatamente, l'apostrofo di "Raffaello" non fa funzionare il primo.
Dennis Williamson,

Entrambi i compiti alla fine funzionano per me. La virgoletta singola in VAR1 non dovrebbe essere un problema (almeno non per bash). Forse sei stato ingannato dall'evidenziazione della sintassi?
joschi,

1
Funziona in uno script, ma non al prompt di Bash. Scusa per non essere più chiaro.
Dennis Williamson,

1
È meglio citare EOF come 'EOF'o "EOF", altrimenti verranno analizzate le variabili di shell.
Stanislav German-Evtushenko,

13
#!/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}"

Questo dovrebbe funzionare bene all'interno dell'ambiente shell Bourne


1
+1 questa soluzione consente la sostituzione variabile come $ {foo}
Offirmo il

Upside: sh-compatibile. Unico inconveniente: i backtick sono deprecati / scoraggiati in bash. Ora, se dovessi scegliere tra sh e bash ...
Zenexer,

2
da quando i backtick sono deprecati / scoraggiati? solo curioso
Alexander Mills,

6

Ancora un altro modo di fare lo stesso ...

Mi piace usare variabili e speciali <<-che rilasciano tabulazioni all'inizio di ogni riga per consentire il rientro dello 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

attenzione : non c'è spazio prima eofma solo tabulazione .

<?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>
Alcune spiegazioni:
  • mapfile leggi l'intero documento qui in un array.
  • la sintassi "${Pattern[*]}"esegue il cast di questo array in una stringa.
  • Uso IFS=";"perché non sono presenti ;stringhe obbligatorie
  • La sintassi while IFS=";" read file ...impedisce IFSdi essere modificata per il resto dello script. In questo, readusa solo il modificato IFS.
  • senza forchetta.

Nota che mapfilerichiede Bash 4 o successivo. E la sintassi "${Pattern[*]}"inserisce l'array in una stringa tra virgolette (come mostrato nel codice di esempio).
Dennis Williamson,

Sì, bash 4 era molto nuovo quando è stata posta questa domanda.
F. Hauri,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.