Maneira limpa de escrever uma cadeia complexa de várias linhas para uma variável

96

Eu preciso escrever algum xml complexo para uma variável dentro de um script bash. O xml precisa ser legível dentro do script bash, pois é onde o fragmento xml ficará ativo, não está sendo lido de outro arquivo ou fonte.

Então, minha pergunta é: se eu tiver uma string longa que eu queira ser legível dentro do meu script, qual é a melhor maneira de fazer isso?

O ideal é que eu queira:

  • para não ter que escapar de nenhum dos caracteres
  • divida várias linhas tornando-a legível por humanos
  • mantenha o recuo

Isso pode ser feito com EOF ou algo assim, alguém poderia me dar um exemplo?

por exemplo,

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
    
por ChrisInCambo 08.10.2009 / 12:54

5 respostas

124

Isso colocará seu texto em sua variável sem precisar escapar das citações. Ele também irá manipular aspas não balanceadas (apóstrofos, ou seja, ' ). Colocar aspas ao redor da sentinela (EOF) impede que o texto passe por expansão de parâmetro. O -d'' faz com que ele leia várias linhas (ignore as novas linhas). read é um Bash integrado, por isso não é necessário chamar um comando externo, como 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
    
por 08.10.2009 / 14:37
25

Você esteve quase lá. Ou você usa cat para a montagem da sua string ou cita a string inteira (nesse caso você teria que escapar das aspas dentro da string):

#!/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}"
    
por 08.10.2009 / 13:14
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}"

Isso deve funcionar bem no ambiente do shell Bourne

    
por 05.09.2012 / 17:54
4

Ainda outra maneira de fazer o mesmo ...

Eu gosto de usar variáveis e <<- especiais que dropam tabulação no início de cada linha para permitir o recuo do 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

warning : não há espaço em branco antes de eof , mas apenas tabulação .

<?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>
Algumas explicações:
  • mapfile lê todo aqui documento em uma matriz.
  • a sintaxe "${Pattern[*]}" atribui essa matriz a uma string.
  • eu uso IFS=";" porque não há ; nas strings necessárias
  • A sintaxe while IFS=";" read file ... impede que IFS seja modificado para o restante do script. Neste, apenas read usa o IFS modificado.
  • sem garfo.
por 22.07.2013 / 15:45
2

Existem muitos casos específicos em muitas das outras respostas.

Para ter certeza absoluta de que não há problemas com espaços, guias, IFS etc., uma abordagem melhor é usar o constructo "heredoc", mas codifique o conteúdo do heredoc usando uuencode , conforme explicado aqui:

link .

    
por 17.05.2014 / 11:10