Substituir um marcador em um arquivo de texto com novo texto arbitrário

4

Eu tenho um arquivo que contém algum texto e - em uma única linha - um marcador que indica onde o novo conteúdo deve ser adicionado

foo
bar
%SUBSTITUTE%
foo

O substituto da linha de linha deve ser substituído por uma nova string de múltiplas linhas de caracteres text="some text" (note que eu não sei a string que pode, por exemplo, ser o resultado da leitura de um arquivo text= cat "file" ''). O resultado da substituição deve ser lido

foo
bar
some text
%SUBSTITUTE%
foo

Eu tinha uma versão de trabalho baseada em perl que parou de funcionar (aparentemente devido à alteração na versão perl). Agora estou tentando utilitários padrão como tr e sed para substituir a linha. Eu estou tendo alguns problemas com isso, porque a seqüência a ser colada pode conter caracteres arbitrários, incluindo barras invertidas, etc. Eu não quero escapar destes antes de colar.

Existe uma maneira segura de fazer isso que funciona com ferramentas padrão? As outras questões que encontro para o problema são soluções particulares onde o texto a ser colado é conhecido.

    
por highsciguy 15.11.2014 / 13:28

4 respostas

4

Se você tem a versão GNU do sed, você deve ser capaz de usar o comando r para ler e inserir novo conteúdo de um arquivo, depois excluir a linha do marcador, por exemplo.

sed '/%SUBSTITUTE%/{
r path/to/newcontent
d
}' file

Se você quiser manter o marcador %SUBSTITUTE% após a inserção, isso é complicado, porque o que você fizer, a extensão GNU r enfileirará o conteúdo do arquivo até o fim do ciclo de padrões atual (retê-lo antes seria apenas uma questão de remover o comando d ). Provavelmente, a maneira mais simples é anexá-lo ao arquivo newcontent : você poderia fazer isso na hora, como

sed '/%SUBSTITUTE%/{
r /dev/stdin
d
}' file < <(sed '$a %SUBSTITUTE%' path/to/newcontent)

Tomando uma abordagem completamente diferente, você pode dividir o primeiro arquivo em %SUBSTITUTE% e depois cat no novo conteúdo

csplit -s file '/%SUBSTITUTE%/'
cat xx00 newcontent xx01

Você também pode fazer um loop bash read sobre as linhas do primeiro arquivo, e catar o novo arquivo de conteúdo quando você combina com a string do marcador - no entanto eu tive meus dedos estourados por sugerir loops de leitura para processamento de texto este fórum. Infelizmente, nenhum dos dois fornece uma solução no local.

    
por 15.11.2014 / 13:45
3

Aqui está outra maneira de usar ed .
Insira todo o conteúdo de FILE antes do marcador (ou seja, antes da linha contendo %SUBSTITUTE% ):

ed -s originalfile <<< $'/%SUBSTITUTE%/- r FILE\nw\nq'

onde:% /%SUBSTITUTE%/ : define o endereço na primeira linha correspondendo %SUBSTITUTE%
- ou -1 : compensações endereçam uma linha antes de r FILE : Reads FILE to after the addressed line.
w : escreve para originalfile (substitua por ,p apenas para imprimir o conteúdo em vez de escrever)
q : sai do editor

A substituição de FILE por !echo "$TEXT" inserirá o conteúdo de $TEXT antes do marcador:

export TEXT
ed -s originalfile <<'IN'
/%SUBSTITUTE%/-1 r !echo "$TEXT"
w
q
IN
    
por 19.02.2015 / 01:59
2

Eu encontrei a seguinte solução com base em awk :

text='cat "filepaste"'
export text;
<"$file" awk '
    BEGIN {REPLACE=ENVIRON["text"] "\n%SUBSTITUTE%" }
    {gsub(/^%SUBSTITUTE%$/, REPLACE); print}
'

Aqui, "filepaste" contém o conteúdo para substituir %SUBSTITUTE% . Uma vantagem é que essa string pode ser usada com ferramentas de shell diferentes sem a necessidade de salvá-la em um arquivo. A leitura da awk variable REPLACE da variável de ambiente evita a expansão de caracteres de escape em text .

    
por 15.11.2014 / 15:06
0

Desde que você teve uma solução Perl, aqui está outra. Estou usando rep.txt para armazenar a substituição:

$ perl -pe '$re='cat rep.txt'; chomp($re); s/%SUBSTITUTE%\n/$re/' file.txt
foo
bar
multi
  line
string
foo

Isso lê cada linha do arquivo de destino ( file.txt ), depois aplica o script dado por -e a ele e imprime ( -p ).

    
por 15.11.2014 / 17:43