Bir değişkene karmaşık çok satırlı dize yazmanın temiz yolu


109

Bir bash betiğinin içindeki bir değişkene bazı karmaşık xml'ler yazmam gerekiyor. Xml parçasının yaşadığı yer olan xml bash betiğinin içinde okunabilir olmalı, başka bir dosyadan veya kaynaktan okunmuyor.

Öyleyse sorum şu: bash betiğimde insan tarafından okunabilir olmak istediğim uzun bir dizgime sahipsem, bunun için en iyi yol nedir?

İdeal olarak istiyorum:

  • herhangi bir karakterden kaçmak zorunda kalmamak
  • insan tarafından okunabilir hale getirmek için birçok çizgiyi geçmesini sağlamak
  • girintisini koru

Bu EOF veya başka bir şeyle yapılabilir mi, birisi bana bir örnek verebilir mi?

Örneğin

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

İddiaya girerim ki, bu verileri tekrar bir akışa atacaksın. İşleri daha karmaşık hale getirip akışları kullanabiliyorken neden değişkende saklıyorsunuz?
Zenexer

Yanıtlar:


140

Bu, metninizi tırnak işaretlerinden kaçmanıza gerek kalmadan değişkeninize yerleştirir. Ayrıca, dengesiz tırnaklara da bakacaktır (kesme işaretleri, yani '). Nöbetçi tırnaklarına (EOF) tırnak işaretleri koymak metnin parametre genişlemesini gerçekleştirmesini önler. -d''Nedenleri birden çok çizgiler (yeni satırlar görmezden) okumak için. readbir Bash yerleşik olduğundan, harici bir komut çağırmayı gerektirmez 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
Önlemek için +1 cat.
James Sneeringer

4
catharici bir komuttur. Kullanmamak, bunu yapmaktan tasarruf sağlar. Ayrıca, bazılarında ikiden daha az argüman olan kedi kullanıyorsanız "Ur bunu yanlış yapıyorsunuz" (“yararsız kullanım” dan farklı) felsefesi vardır cat.
Dennis Williamson,

9
ve hiçbir zaman ikinci
EOF'yi girintisiz bırakma

9
Ben ise yukarıdaki ifadeyi kullanmaya çalıştım set -e. Her readzaman sıfır olmayan bir şekilde görünüyor . Bu davranışı kullanarak! read -d .......
krissi

11
Ve Stringbir dosyaya yazmak için bu çok satırlı değişkeni kullanıyorsanız , değişkeni "QUOTES" echo "${String}" > /tmp/multiline_file.txtveya benzeri gibi koyun echo "${String}" | tee /tmp/multiline_file.txt. Bunu bulmam bir saatten fazla sürdü.
Aditya,

28

Neredeyse oradaydın. Dizenin montajı için cat kullanırsınız ya da bütün dizeyi alıntılarsınız (bu durumda dizginizin içindeki tırnaklardan kaçmanız gerekir):

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

Ne yazık ki, "Raphael's" deki kesme işareti ilki çalışmaz hale getirir.
Dennis Williamson,

Her iki ödev de sonunda benim için çalışıyor. VAR1'deki tek alıntı bir sorun olmamalıdır (en azından bash için değil). Belki de sözdizimi vurgusu tarafından yanlış yönlendirildiniz?
joschi

1
Bir komut dosyasında çalışır, ancak Bash komut isteminde değil. Daha net olmadığım için üzgünüm.
Dennis Williamson,

1
EOF'yi 'EOF'veya olarak alıntı yapmak daha iyidir "EOF", aksi takdirde kabuk değişkenleri ayrıştırılır.
Stanislav Alman-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}"

Bourne kabuğu ortamında iyi sonuç vermeli


1
+1 bu çözüm, $ {foo} gibi değişken değişimlerine izin verir
Offirmo

Upside: sh uyumlu. Dezavantajı: backticks bash içinde kullanımdan kaldırılmıştır / önerilmemektedir. Şimdi sh ve bash arasında seçim yapmak zorunda
kalsaydım

2
ne zamandan beri backticks kullanımdan kaldırılıyor / cesareti kırılıyor? sadece meraklıyım
Alexander Mills,

6

Aynısını yapmanın başka bir yolu ...

Değişkenleri ve özel <<-olarak komut satırını girmek için her satırın başında sekme bırakan kullanıcıları kullanmayı seviyorum :

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

Uyarı : Önceden boş alan yoktur, eofsadece tablolama yapılır .

<?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>
Bazı açıklamalar:
  • mapfile burada tüm belgeyi bir dizide okudu .
  • Sözdizimi "${Pattern[*]}"bu diziyi bir dizgeye çevirir .
  • Kullanıyorum IFS=";"çünkü ;gerekli dizgiler yok
  • Sözdizimi , betiğin geri kalanında değiştirilmeyi while IFS=";" read file ...önler IFS. Bu, sadece readdeğiştirilmiş kullanın IFS.
  • çatal yok.

mapfileBash 4 veya üstü bir sürüm gerektirdiğini unutmayın . Sözdizimi , tırnaklar halinde (örnek kodda gösterildiği gibi) "${Pattern[*]}"dizeyi bir dizgeye aktarır .
Dennis Williamson,

Evet, bash 4 derece oldu yeni bu soru sorulduğunda.
F. Hauri,

2

Diğer cevapların çoğunda çok fazla köşe durumu var.

Boşluk, sekme, IFS vb. Sorun olmadığından kesinlikle emin olmak için, "heredoc" yapısını kullanmak daha iyi bir yaklaşımdır, ancak aşağıda uuencodeaçıklandığı şekilde kullanarak heredoc içeriğini kodlamaktır :

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.