Como inverter as linhas entre um padrão em outro arquivo

2

Eu tenho o seguinte no arquivo de entrada

#Start para
0 hello dq
1 world dq
2 welcomes dq
3 you dq
#Start para
0 how tq
1 are tq
2 you tq
#Start para
0 say dq
1 hello dq
2 to dq
3 the dq
4 world dq

Eu quero isso direcionado para outro arquivo como este

#Start para
3 you dq
2 welcomes dq
1 world dq
0 hello dq
#Start para
2 you tq
1 are tq
0 how tq
#Start para
4 world dq
3 the dq
2 to dq
1 hello dq
0 say dq

Como posso fazer isso usando sed ou awk ? Basicamente eu quero o parágrafo dentro do #Start para invertido. Mas a ordem dos parágrafos deve permanecer a mesma.

    
por vini 11.03.2015 / 16:35

5 respostas

5

Se o único # for o começo do bloco, então com awk você pode tentar

$ awk -F'\n' 'BEGIN{RS="#"}NR>1{print "#"$1;for(i=NF-1;i>1;i--)print $i}' file

Resultado:

#Start para
3 you dq
2 welcomes dq
1 world dq
0 hello dq
#Start para
2 you tq
1 are tq
0 how tq
#Start para
4 world dq
3 the dq
2 to dq
1 hello dq
0 say dq
    
por 11.03.2015 / 16:44
2

Para uma abordagem mais conservadora e menos enigmática ...

awk '
  /^#/ { printf "%s",out ; print ; out = "" }
  /^[0-9]/ { out = $0 RS out }
  END { printf "%s",out }
'
    
por 11.03.2015 / 17:24
2

com sed :

sed '/#Start para/{x;G;s/^\n//;p;s/.*//;x;d};G;s/\n$//;h;$!d' input.file

Para linhas que consistem em #Start para anexá-lo ao final de hold space por e x change: espaço de padrão < - > retenha espaço e, em seguida, retorne os dados de hold appendin G para padrão . (o mesmo pode ser feito por H (anexar para manter) e retornar ao padrão por g ). Se o espaço de espera estiver vazio, o espaço de padrão será iniciado com a linha vazia, de forma que seja removido pelas linhas coletadas s/^\n// e p rint. Os próximos comandos (até } ) têm como objetivo limpar os espaços de retenção e padrão e ir para a próxima linha.

Para outras linhas (que não consistem em #Start para ) appengin G mantém espaço no padrão, remove a linha vazia (se o espaço de espera estiver vazio), coloque o espaço de padrão em espera e inicie o novo loop d elete tudo se não for a última linha. Se a última linha imprime o espaço de padrão formado como padrão.

    
por 11.03.2015 / 18:32
0

Use tac . Sim, há um comando chamado tac , que faz reversão de cat

    
por 11.03.2015 / 16:47
0

Aqui está uma abordagem em três frentes:

sed 's/^#/\n#/' file | 
    perl -00lne '@A=split(/\n/); print shift(@A); print join "\n", reverse @A' | 
        grep .

Explicação

  • O comando sed adiciona uma nova linha antes de cada linha que começa com # . Isso nos permite usar o modo de parágrafo do Perl (veja abaixo).
  • As opções do Perl:

    • -00 ativa "modo de parágrafo" uma "linha" é definida por 2 \n caracteres.
    • -l : remove novas linhas à direita e adiciona \n a cada print de chamadas.
    • -n : leia um arquivo de entrada linha por linha (ou parágrafo por parágrafo neste caso).
    • -e : o script que será executado em cada linha.
  • O script Perl:

    • @A=split(/\n/); : divida esta linha (parágrafo) na matriz @A , transformando cada linha individual (linha real aqui, não parágrafo) em um elemento da matriz.
    • print shift(@A); : remova o primeiro elemento de @A (a linha do cabeçalho) e imprima-o.
    • print join "\n", reverse @A' : inverta os elementos restantes de @A , conecte-os com \n caracteres e imprima.
  • grep . : apenas um hack sujo para remover as linhas em branco adicionadas por sed . Isso imprimirá todas as linhas que contiverem pelo menos um caractere.
por 11.03.2015 / 19:22