Insere texto do arquivo inline após o padrão correspondente em outro arquivo

6

Estou tentando pegar o conteúdo de um arquivo e inseri-lo após um padrão correspondente em outro arquivo usando sed. A minha pergunta é muito semelhante a esta questão , mas desejo inserir o conteúdo de um arquivo inline em vez de em uma nova linha. Como posso fazer isso?

Usando a pergunta de exemplo mencionada, a primeira resposta faz exatamente o que eu quero; no entanto, quero que a inserção aconteça em linha:

sed '/First/r file1.txt' infile.txt 

Os dados reais que quero inserir são um arquivo JSON:

[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]
    
por turtle 09.12.2014 / 22:23

3 respostas

5

Na sua pergunta vinculada já existe uma boa awk answer, apenas modifique-a um pouco usando printf em vez de print para inserir o conteúdo sem nova linha:

awk '/First/ { printf $0; getline < "File1.txt" }1' infile.txt

Resultado:

Some Text here
FirstThis is text to be inserted into the File.
Second
Some Text here

Você pode querer adicionar espaço ou outro delimitador após "Primeiro" com printf $0 " "; ...

Se o arquivo inserido tiver muitas linhas, então:

awk '/First/{printf $0; while(getline line<"File1.txt"){print line};next}1' infile.txt

Resultado:

Some Text here
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]
Second
Some Text here
    
por 09.12.2014 / 22:37
5

Portanto, seria um pouco complicado fazer com que este trabalho portável em sed - você deve estar olhando para cut e / ou paste com algum precursor regex gerando seu script nesse contexto - e isso é porque sed sempre inserirá um \n ewline antes da saída de um r ead. Ainda assim, com GNU sed :

sed '/First/{x;s/.*/cat file/e;H;x;s/\n//}' <<\IN 
First
Second
Third
IN

Isso funciona em e xecutando cat sempre que encontrar seu endereço /First/ . Ele faz isso no espaço h old (meio - um buffer alternativo de qualquer maneira - porque eu e x muda eles realmente acontece no espaço padrão que costumava ser h old space) para preservar o conteúdo da linha correspondente a First e, em seguida, anexar a saída de cat à sua linha e remover a intervenção \n ewline.

OUTPUT:

First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]
Second
Third

Agora, se você quiser que todo o conteúdo do arquivo caiba entre duas partes de uma linha que tem que funcionar um pouco diferente, porque com o comando acima eu removo a nova linha entre o end da linha correspondente e do começo do arquivo. Ainda assim, você pode fazer isso também:

sed '/First/{s//&\n/;h
         s/.*/{ cat file; echo .; }/e;G
         s/\(.*\).\n\(.*\)\n//
}' <<\IN
Third
Second
First Second Third
Third
Second
First Second Third
IN

Isso divide a linha na correspondência com um caractere \n ewline, salva em h espaço antigo, e xecutes cat - que substitui o espaço padrão por sua saída - G ets o conteúdo de o espaço de armazenamento anexado ao nosso novo espaço de padrão após outro caractere \n ewline e, em seguida, reorganiza os delimitadores \n ewline.

Eu faço echo . para preservar qualquer caractere de ewline \n em file - mas se esse não for seu desejo (e não é muito relevante para o seu exemplo) você pode faça sem ele e remova o primeiro . antes de .\n na seguinte s/// ubstitution.

Pouco antes de reorganizar o espaço padrão, é assim:

^cat's output - any number of newlines.*.\nmatch on First\nrest of match$

OUTPUT:

Third
Second
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
] Second Third 
Third
Second
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
] Second Third
    
por 09.12.2014 / 23:33
5

Você pode usar perl (obtenha o conteúdo do arquivo e substitua pattern por pattern + file content ):

perl -pe '$text='cat insert.txt'; chomp($text); s/PAT/$&$text/' file.txt

adicione -i para editar no lugar; g para acrescentar após cada ocorrência de PAT (padrão), por exemplo:

perl -i -pe '$text='cat insert.txt'; chomp($text); s/PAT/$&$text/g' file.txt

Outra maneira, usando ed :

printf '%s\n' /PAT/s/PAT/\&\ \/ - kb ". r insert.txt" j \'b j ,p q | ed -s file.txt

para editar no local, substitua ,p por w :

 printf '%s\n' /PAT/s/PAT/\&\ \/ - kb ". r insert.txt" j \'b j w q | ed -s file.txt

Provavelmente ninguém está interessado em como isso funciona, mas de qualquer forma, printf passa uma lista de comandos para ed :

/PAT/s/PAT/&\             #   set address to first line matching PAT and
/                         #   split the line right after PAT
-                         #   set address one line before (return to the line matching PAT)
kb                        #   mark the current line
. r insert.txt            #   insert content of insert.txt after this line         
j                         #   join current line and the next
'b                        #   set  address to marked line (return to the line matching PAT)
j                         #   join current line and the next one
,p                        #   print file content
q                         #   quit editor

Ou, sem usar printf e | :

ed -s file.txt <<< $'/PAT/s/PAT/&\\n/\n-\nkb\n. r insert.txt\nj\n\'b\nj\nw\nq\n'
    
por 10.12.2014 / 10:41