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


Мне нужно написать некоторый сложный 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

92
2017-10-08 10:54


Источник


Я готов поспорить, что вы просто собираетесь сбросить эти данные в поток снова. Зачем хранить его в переменной, если вы можете сделать вещи более сложными и использовать потоки? - Zenexer
см. также: Многострочная строка с дополнительным пространством (сохраненный отступ) - Yibo Yang


Ответы:


Это поместит ваш текст в вашу переменную без необходимости избегать цитат. Он также будет обрабатывать несбалансированные кавычки (апострофы, т. Е. '). Помещение котировок вокруг часового (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

119
2017-10-08 12:37



+1 для избежания cat, - James Sneeringer
cat является внешней командой. Не использовать его экономит. Кроме того, у некоторых есть философия, что если вы используете кошку с менее чем двумя аргументами «Ur doin», это неправильно »(что отличается от« бесполезного использования cat«). - Dennis Williamson
и никогда не отступал второй EOF .... (несколько столбиков на голову) - IljaBek
Я попытался использовать вышеприведенное утверждение, пока set -e, Кажется read всегда возвращает ненулевое значение. Вы можете толковать это поведение, используя ! read -d ....... - krissi
И если вы используете эту многострочную линию String переменная для записи в файл, поместите переменную вокруг «ЦИТАТЫ», как echo "${String}" > /tmp/multiline_file.txt или echo "${String}" | tee /tmp/multiline_file.txt, Принял меня больше часа, чтобы найти это. - Aditya


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

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



К сожалению, апостроф в «Рафаэле» делает первый из них не работает. - Dennis Williamson
Оба задания работают для меня в конечном итоге. Одинарная кавычка в VAR1 не должна быть проблемой (по крайней мере, не для bash). Может быть, вы были введены в заблуждение подсветкой синтаксиса? - joschi
Он работает в скрипте, но не в приглашении Bash. Извините за неясность. - Dennis Williamson
Лучше процитировать EOF как 'EOF' или "EOF", иначе переменные оболочки будут проанализированы. - 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}"

Это должно хорошо работать в среде оболочки Bourne


9
2017-09-05 15:54



+1 это решение допускает замену переменных как $ {foo} - Offirmo
Потенциал: sh-совместим. Недостаток: backticks устаревают / обескуражены в bash. Теперь, если мне пришлось выбирать между sh и bash ... - Zenexer
так как когда backticks устаревают / обескуражены? просто любопытно - Alexander Mills


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

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

#!/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,
  • нет вилка.

3
2017-07-22 13:45



Обратите внимание, что mapfile требует Bash 4 или выше. И синтаксис "${Pattern[*]}" переводит массив в строку когда в кавычках (как показано в примере кода). - Dennis Williamson
Да, bash 4 был очень новый когда этот вопрос был задан. - F. Hauri


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

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

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


2
2018-05-17 09:10