Como inserir linhas com números de X a Y em outro arquivo após a linha Z?

7

Eu criei dois arquivos:

echo -e "1\n2\n3\n4\n5" > 123.txt
echo -e "a\nb\nc\nd\ne" > abc.txt

Eu quero pegar o arquivo 123.txt com o seguinte conteúdo:

1
2
3
b
c
d
4
5

Em outras palavras, insira as linhas com números de 2 a 4 do arquivo abc.txt no arquivo 123.txt após a terceira linha.

Eu revi as muitas perguntas semelhantes aqui, mas não encontrei uma resposta adequada. No entanto, eu tenho as linhas:

sed -n '2,4p' abc.txt

e coloque algum texto no arquivo após a terceira linha:

sed -i '3a\mytext' 123.txt

Como fazer isso usando o comando anterior stdout ou / e um comando sed / awk single?

    
por Apostle 08.07.2014 / 17:57

4 respostas

6

Se o seu sistema possui a versão GNU de sed , você pode usar o comando r da extensão GNU:

r filename
    As a GNU extension, this command accepts two addresses.

    Queue the contents of filename to be read and inserted into the
    output stream at the end of the current cycle, or when the next input 
    line is read. Note that if filename cannot be read, it is treated as 
    if it were an empty file, without any error indication.

    As a GNU sed extension, the special value /dev/stdin is supported for 
    the file name, which reads the contents of the standard input. 

Por exemplo,

$ sed '3r /dev/stdin' 123.txt < <(sed -n '2,4p' abc.txt)
1
2
3
b
c
d
4
5
    
por 08.07.2014 / 18:14
3

Usando awk e sed :

$ awk 'FNR==3{print;system("sed -n '2,4p' abc.txt");next};1' 123.txt 
1
2
3
b
c
d
4
5
    
por 08.07.2014 / 18:41
2

Com sed , você pode usar o comando r para inserir um arquivo inteiro. Para inserir uma parte de um arquivo, extraia essa parte e canalize-a como entrada para sed . Você pode usar sed para fazer a extração também.

sed -n '2,4p' abc.txt | sed -i '3r /dev/stdin' 123.txt

Com awk , você pode ler um arquivo e alternar para outro arquivo no meio.

awk <123.txt >123.txt.new '
    1                                    # print the input line
    NR==3 {                              # after line 3 of 123.txt, …
        while (getline < "abc.txt") {
            ++inner_NR;
            if (inner_NR >= 2) print;    # start printing at line 2 from abc.txt
            if (inner_NR == 4) break;    # stop after line 4
        }
    }
' &&
mv 123.txt.new 123.txt

Você também pode usar head e tail para extrair as partes dos arquivos que deseja combinar.

head -n 3 <123.txt >123.txt.new &&
<abc.txt tail -n +2 | head -n 3 >>123.txt.new &&
tail -n +4 123.txt >>123.txt.new &&
mv 123.txt.new 123.txt

Você pode combinar a abordagem head + tail com sed . Para arquivos grandes, é provável que seja o mais rápido.

<abc.txt tail -n +2 | head -n 3 | sed -i '3r /dev/stdin' 123.txt

Observe que todas essas abordagens gravam em um arquivo temporário que é movido para 123.txt (até mesmo as abordagens que usam sed -i , porque é isso que o sed -i faz sob o capô).

    
por 09.07.2014 / 02:23
2

Edição no local usando ed e sed (no prompt do bash):

ed -s 123.txt<<<$'3r !sed -n "2,4p" abc.txt\nw'
    
por 08.07.2014 / 19:07