Чистый способ записи сложной многострочной строки в переменную

Мне нужно написать сложный xml для переменной внутри скрипта bash. Xml должен быть доступен для чтения внутри сценария bash, так как здесь находится фрагмент xml, он не читается из другого файла или источника.

Итак, мой вопрос заключается в том, что если у меня есть длинная строка, которую я хочу быть читаемой человеком внутри моего сценария bash, что это лучший способ сделать это?

В идеале хочу:

  • не нужно выходить из любого символа
  • попросите его разбить несколько строк, что делает его понятным для человека.
  • сохранить отступы

Можно ли это сделать с помощью EOF или что-то еще, может ли кто-нибудь дать мне пример?

например.

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
90 голосов | спросил ChrisInCambo 8 +04002009-10-08T14:54:00+04:00312009bEurope/MoscowThu, 08 Oct 2009 14:54:00 +0400 2009, 14:54:00

5 ответов


118

Это поместит ваш текст в вашу переменную без необходимости избегать цитат. Он также будет обрабатывать несбалансированные кавычки (апострофы, т. Е. '). Помещение котировок вокруг часового (EOF) предотвращает переход текста от расширения параметра. -d'' заставляет его читать несколько строк (игнорировать новые строки). read - это встроенный Bash, поэтому он не требует вызова внешней команды, такой как 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
ответил Dennis Williamson 8 +04002009-10-08T16:37:40+04:00312009bEurope/MoscowThu, 08 Oct 2009 16:37:40 +0400 2009, 16:37:40
25

Ты был почти там. Либо вы используете cat для сборки вашей строки, либо цитируете всю строку (в этом случае вам нужно было бы избежать кавычек внутри вашей строки):

#!/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}"
ответил joschi 8 +04002009-10-08T15:14:11+04:00312009bEurope/MoscowThu, 08 Oct 2009 15:14:11 +0400 2009, 15:14:11
9
#!/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

ответил schweiz 5 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowWed, 05 Sep 2012 19:54:44 +0400 2012, 19:54:44
3

Еще один способ сделать то же самое ...

Мне нравится использовать переменные и специальные <<-, которые выгружают табуляцию в начале каждой строки, чтобы разрешить отступ сценария:

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

предупреждение : нет пробела до 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>
Некоторые объяснения:
  • mapfile читает целые здесь документ в массиве.
  • синтаксис "${Pattern[*]}" делает этот массив в строку.
  • Я использую IFS=";", потому что в обязательных строках нет ;
  • Синтаксис while IFS=";" read file ... предотвратить IFS, который будет изменен для остальной части скрипта. В этом только read используйте модифицированный IFS.
  • нет вилки.
ответил F. Hauri 22 J000000Monday13 2013, 17:45:11
2

Во многих других ответах слишком много угловых случаев.

Чтобы быть абсолютно уверенными в отсутствии пробелов, вкладок, IFS и т. д., лучше использовать конструкцию «heredoc», но кодировать содержимое heredoc с помощью uuencode, как объяснено здесь:

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

ответил Chris Johnson 17 Maypm14 2014, 13:10:02

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132