Pertanyaan Cara bersih untuk menulis string multi-garis kompleks ke variabel


Saya perlu menulis beberapa xml yang rumit ke variabel di dalam skrip bash. Xml harus dapat dibaca di dalam skrip bash karena ini adalah tempat fragmen xml akan hidup, itu tidak dibaca dari file atau sumber lain.

Jadi pertanyaan saya adalah ini jika saya memiliki string panjang yang saya ingin menjadi manusia yang dapat dibaca di dalam script bash saya apa cara terbaik untuk melakukannya?

Idealnya saya mau:

  • untuk tidak harus melarikan diri dari salah satu karakter
  • memilikinya membelah beberapa baris membuatnya dapat dibaca manusia
  • pertahankan indentasi itu

Bisakah ini dilakukan dengan EOF atau sesuatu, bisakah seseorang memberi saya contoh?

misalnya

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




Saya berani bertaruh bahwa Anda hanya akan membuang data itu ke dalam aliran lagi. Mengapa menyimpannya dalam variabel ketika Anda dapat membuat hal-hal lebih rumit dan menggunakan aliran? - Zenexer
lihat ini juga: Multi-garis string dengan ruang ekstra (indentasi diawetkan) - Yibo Yang


Jawaban:


Ini akan menempatkan teks Anda ke dalam variabel Anda tanpa perlu menghindari tanda kutip. Ini juga akan menangani kutipan yang tidak seimbang (apostrophes, yaitu '). Menempatkan tanda kutip di sekitar sentinel (EOF) mencegah teks agar tidak mengalami perluasan parameter. Itu -d'' menyebabkannya membaca banyak baris (abaikan baris baru). read adalah Bash built-in sehingga tidak perlu memanggil perintah eksternal seperti 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 untuk menghindari cat. - James Sneeringer
cat adalah perintah eksternal. Tidak menggunakannya menghemat melakukan itu. Plus, beberapa memiliki filosofi bahwa jika Anda menggunakan kucing dengan kurang dari dua argumen "Ur doin 'salah" (yang berbeda dari "penggunaan tidak berguna dari cat"). - Dennis Williamson
dan jangan pernah indent EFF kedua .... (multiple table to head bangs terlibat) - IljaBek
Saya mencoba menggunakan pernyataan di atas sementara set -e. Kelihatannya read selalu mengembalikan bukan nol. Anda dapat mengentalkan perilaku ini dengan menggunakan ! read -d ....... - krissi
Dan jika Anda menggunakan multi-garis ini String variabel untuk menulis ke file, menempatkan variabel di sekitar "QUOTES" seperti echo "${String}" > /tmp/multiline_file.txt atau echo "${String}" | tee /tmp/multiline_file.txt. Membawa saya lebih dari satu jam untuk menemukan itu. - Aditya


Anda sudah hampir sampai. Entah Anda gunakan kucing untuk perakitan string Anda atau Anda mengutip seluruh string (dalam hal ini Anda harus menghindari tanda kutip di dalam string Anda):

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



Sayangnya, tanda kutip di "Raphael's" membuat yang pertama tidak berfungsi. - Dennis Williamson
Kedua tugas itu akhirnya berhasil bagi saya. Kutipan tunggal dalam VAR1 seharusnya tidak menjadi masalah (setidaknya bukan untuk bash). Mungkin Anda telah disesatkan oleh penyorotan sintaks? - joschi
Ia bekerja dalam skrip, tetapi tidak pada prompt Bash. Maaf karena tidak jelas. - Dennis Williamson
Lebih baik mengutip EOF sebagai 'EOF' atau "EOF", jika tidak, variabel shell akan diuraikan. - 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}"

Ini harus bekerja dengan baik dalam lingkungan shell Bourne


9
2017-09-05 15:54



Beri +1 solusi ini memungkinkan substitusi variabel seperti $ {foo} - Offirmo
Upside: sh-kompatibel. Downside: backticks tidak lagi digunakan / dihalangi dalam bash. Sekarang jika saya harus memilih antara sh dan bash ... - Zenexer
sejak kapan backticks tidak lagi digunakan / putus asa? hanya penasaran - Alexander Mills


Namun cara lain untuk melakukan hal yang sama ...

Saya suka menggunakan variabel dan khusus <<- siapa yang menjatuhkan tabulasi di awal setiap baris untuk mengizinkan lekukan skrip:

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

peringatan: tidak ada ruang kosong sebelum eof tapi hanya tabulasi.

<?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>
Beberapa penjelasan:
  • mapfile baca seluruhnya di sini dokumen dalam sebuah array.
  • syntaxe "${Pattern[*]}" jangan letakkan array ini ke dalam string.
  • saya menggunakan IFS=";" karena tidak ada ; dalam string yang dibutuhkan
  • Sintaksisnya while IFS=";" read file ... mencegah IFS dimodifikasi untuk sisa naskah. Hanya ini saja read jangan gunakan yang dimodifikasi IFS.
  • tidak ada garpu.

4
2017-07-22 13:45



Perhatikan itu mapfile membutuhkan Bash 4 atau lebih tinggi. Dan sintaksnya "${Pattern[*]}" melemparkan array ke dalam string ketika dalam tanda kutip (seperti yang ditunjukkan pada kode contoh). - Dennis Williamson
Ya, bash 4 sangat baru ketika pertanyaan ini diajukan. - F. Hauri


Terlalu banyak kasus sudut di banyak jawaban lainnya.

Untuk benar-benar yakin tidak ada masalah dengan spasi, tab, IFS, dll., Pendekatan yang lebih baik adalah menggunakan konstruksi "heredoc", tetapi menyandikan konten heredoc menggunakan uuencode seperti yang dijelaskan di sini:

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


2
2018-05-17 09:10