Isso foi o melhor que consegui:
sed -n '/^PATTERN_START/, /^PATTERN_END/{
/^PATTERN_START/{x;s/^.*$//;x};
/^Record/{x;/^\n/{s/^\n//p;d};s/\n/ /gp};
/^PATTERN_END/{x;/^\n/{s/^\n//p;d};s/\n/ /gp;g;p};
/^Record/!H
};
/^PATTERN_START/, /^PATTERN_END/!p'
Explicação
Suponho que você esteja familiarizado com a ideia de manter espaço e espaço padrão em sed
. Nesta solução, faremos muitas manipulações no espaço padrão. Assim, o primeiro ponto é desativar a impressão automática com a opção -n
e imprimir onde for necessário.
A primeira tarefa é juntar todas as linhas que estão entre Record
lines.
Considere o seguinte arquivo:
a
b
Record 1
c
d
Record 2
e
f
Record 3
Depois de juntar linhas, queremos que seja
a
b
Record 1 c d
Record 2 e f
Record 3
Então, aqui está o plano:
- Lemos uma linha, anexamos ao espaço de espera.
- Se a linha começar com
Record
, significa que o registro anterior foi concluído e um novo registro foi iniciado. Então, imprimimos o espaço de espera, limpamos e começamos com o ponto 1 novamente.
O ponto 1 é implementado pelo código /^Record/!H
(quinta linha no comando). O que significa é "se a linha não começar com Record
, adicione uma nova linha ao espaço de espera e anexe esta linha ao espaço de espera".
O ponto 2 pode ser implementado pelo código
/ ^ Gravar / {x; s / \ n / / gp;}
onde x
substitui os espaços de padrão e de espera, s
substitui todos \n
s por
s e p
flag imprime o espaço de padrão. O uso de x
também tem a vantagem de que agora o espaço de espera contém a linha Record
atual para que possamos começar outro ciclo de pontos 1 e 2.
Mas isso tem um problema. No exemplo dado, existem duas linhas
uma
b
antes da primeira linha Record
. Não queremos substituir \n
por
nessas linhas. Como eles não começam com Record
, de acordo com o ponto 1, \n
é adicionado para manter o espaço e, em seguida, essas linhas são anexadas. Portanto, se o primeiro caractere do espaço de suspensão for \n
, isso significa que não foi encontrado Record
antes e não devemos substituir \n
por
. Isso é feito com o comando
/^\n/{s/^\n//p;d}
Assim, todo o comando se torna
/^Record/{x;/^\n/{s/^\n//p;d};s/\n/ /gp};
Agora, a segunda complicação é que queremos unir linhas, mesmo que uma linha Record
não seja terminada por uma linha Record
, mas por uma linha PATTERN_END
. Queremos fazer exatamente as mesmas coisas do ponto 2, mesmo quando a linha começa com PATTERN_END
. Então o comando se torna
/^PATTERN_END/{x;/^\n/?s/^\n//p;d};s/\n/ /gp}
Mas há um problema com isso. Como no caso de Record
lines, a linha PATTERN_END
agora acaba no espaço de espera. Mas sabemos que não haverá mais junção de linhas após PATTERN_END
line. Então, podemos imprimir isso. Então, nós trazemos a linha PATTERN_END
para o espaço padrão com g
e imprimimos com p
. Então o comando final se torna
/^PATTERN_END/{x;/^\n/?s/^\n//p;d};s/\n/ /gp;g;p}
O próximo problema é com as linhas PATTERN_START
. Na explicação acima, assumimos que no início, o espaço de espera está vazio. Mas depois de um PATTERN_END
, há algo no espaço de espera. (Esse algo é apenas PATTERN_END
line). Quando começamos um novo ciclo com PATTERN_START
, queremos limpar o espaço de espera.
Então, o que fazemos é quando encontramos PATTERN_START
, trocamos o conteúdo dos espaços hold e pattern, limpamos o espaço padrão e trocamos novamente. Isso faz com que o espaço fique limpo. Isso é exatamente o que o seguinte comando faz:
/^PATTERN_START/{x;s/^.*$//;x}
O último traço é que queremos fazer todo esse trabalho apenas entre PATTERN_START
e PATTERN_END
linhas. Outros, nós apenas os imprimimos. Isso é feito pelos comandos
/^PATTERN_START/, /^PATTERN_END/{
----above commands go here----
};
/^PATTERN_START/, /^PATTERN_END/!p
Coloque tudo isso junto e isso dá o comando final:)