Usando sed em shell script com variáveis ​​multilinhas

Usando sed em shell script com variáveis ​​multilinhas

Eu uso scripts de shell para configurar diferentes tipos de VMs. Freqüentemente, esses scripts incluem variáveis ​​multilinhas que precisam ser inseridas em arquivos de configuração em determinadas posições usando sed.

Se eu criá-los assim, está tudo bem:

VAR="Config Line1\nConfig Line2\nConfig Line 3"
sed -i "/MatchingPattern/ a $VAR" somefile

Isso não torna o script muito legível, especialmente porque os blocos de texto podem ser bastante longos.

Se eu escrevê-los assim:

VAR="Config Line1
Config Line2
Config Line 3"
sed -i "/MatchingPattern/ a $VAR" somefile

Recebo um erro ao executar o script: sed: -e expression #1, char 31: unknown command:C'`

Existe uma maneira de usar sedcom variáveis ​​declaradas assim?

Responder1

A sintaxe padrão do acomando é:

sed -e 'a\
first line\
  second line\
last line'

BSD (pelo menos FreeBSD e OS/X) sedremove os espaços em branco iniciais, eprecisa do -epara solucionar um bug. GNU sedpermite mover a primeira linha para logo após, a\desde que não esteja vazia.

Então, você precisaria pré-processar a entrada:

VAR='content with
multiple lines
  some with lead blanks
or even backslash\'

preprocessed_VAR=$(printf '%s\n' "$VAR" |
  sed 's/\\/&&/g;s/^[[:blank:]]/\\&/;s/$/\\/')

sed -i -e "/MatchingPattern/a\\
${preprocessed_VAR%?}" somefile

(substitua -ipor -i ''no FreeBSD ou OS/X).

No GNU/Linux e com o shell GNU ( bash) ou zsh, você pode fazer:

sed -i '/MatchingPattern/r /dev/stdin' <<< "$VAR"

Isso funciona porque bashimplementa zshhere-strings com arquivos temporários excluídos e /dev/stdin no Linux é implementado como um link simbólico para o arquivo (o que significa que ele pode ser aberto várias vezes e, a cada vez, é aberto no início).

Aqui você também pode usar o GNU awk:

(export VAR
gawk -i /usr/share/awk/inplace.awk '{print}; /MatchingPattern/{print ENVIRON["VAR"]}' somefile)

Não use-i inplaceas gawktenta carregar primeiro a inplaceextensão (como inplaceou inplace.awk) do diretório de trabalho atual, onde alguém poderia ter plantado malware. O caminho da inplaceextensão fornecida gawkpode variar de acordo com o sistema, consulte a saída degawk 'BEGIN{print ENVIRON["AWKPATH"]}'

Ou perl(de onde isso -ivem):

(export VAR
perl -pi -e '$_ .= "$ENV{VAR}\n" if /MatchingPattern/' somefile)

Responder2

O erro ocorre porque o sedcomando de acréscimo aprecisa de uma barra invertida após o real a:

Com GNU sed:

$ sed "/pattern/a\\$VAR" file.in >file.out

BSD sed, até onde eu sei, só é capaz de inserir uma única linha em um arquivo com o acomando, a menos que as novas linhas sejam escapadas corretamente.

Resposta intimamente relacionada sobre como resolver isso com BSD sed:http://unix.stackexchange.com/a/60322

informação relacionada