ordem inversa dos parágrafos no arquivo

8

Eu tenho um arquivo contendo texto em parágrafos (linhas com texto separado por uma ou mais linhas vazias). Eu gostaria de reverter a ordem dos parágrafos (ou seja, o último parágrafo será o primeiro, ...), de preferência usando sed.

Eu estou procurando um comando sed que faria para um arquivo de parágrafos, o que tac faria para um arquivo de linhas.

    
por Martin Vegter 16.02.2014 / 12:45

6 respostas

6

Usar sed não é tão direto quanto mencionado por Joseph R. . No entanto, você poderia dizer:

sed '/./{H;d;};x;s/\n/={NL}=/g' inputfile | \
sed -e 's/^={NL}=//' -e '1!G;h;$!d' | \
sed G | sed 's/={NL}=/\'$'\n/g'

Dada uma entrada de amostra:

Para 1 line 1
Para 1 line 2
Para 1 line 3

Para 2 line 1
Para 2 line 2
Para 2 line 3

Para 3 line 1
Para 3 line 2
Para 3 line 3

isso produziria:

Para 3 line 1
Para 3 line 2
Para 3 line 3

Para 2 line 1
Para 2 line 2
Para 2 line 3

Para 1 line 1
Para 1 line 2
Para 1 line 3

Vale ressaltar que esta solução (assim como a alternativa do Perl) requer uma linha em branco no final do arquivo de entrada para funcionar como esperado.

    
por 16.02.2014 / 13:27
6

Esta solução usa tac e perl para ler um parágrafo por vez. Não é necessário ler todo o arquivo na memória.

tac file | perl -00 -lpe '$_ = join "\n", reverse split /\n/'

Inverta todas as linhas do arquivo, depois, para cada parágrafo invertido, inverta as linhas.

    
por 16.02.2014 / 14:39
3

Pode haver uma maneira de fazer isso com sed , mas duvido que seja simples. Aqui está como eu faria em Perl:

perl -n00e 'push @paragraphs,$_; END{print for reverse @paragraphs}' your_file

Isso funciona porque definir o separador de registro de entrada como o caractere nulo ( -00 ) informa ao Perl para operar no modo de parágrafo. A definição de Perl de um parágrafo 1 corresponde exatamente à sua definição.

1 Procure no cabeçalho Other values for $/

    
por 16.02.2014 / 13:13
1

Se os seus parágrafos estão sempre separados por uma única linha vazia:

sed '/^$/s/^/\x02/' infile | tr \n$'
Para 1 line 1
Para 1 line 2

Para 2 line 1


Para 3 line 1
Para 3 line 2

Para 4 line 1
Para 4 line 2



Para 5 line 1
2' $'
paste -d $'
Para 5 line 1

Para 4 line 1
Para 4 line 2


Para 3 line 1
Para 3 line 2

Para 2 line 1



Para 1 line 1
Para 1 line 2
4' <(sed '/^$/s/^/\x02/' infile | tr \n$'
paste -d $'\n' <(sed '/^$/s/^/\x02/' infile | tr \n$'
sed '/^$/s/^/\x02/' infile | tr \n$'
Para 1 line 1
Para 1 line 2

Para 2 line 1


Para 3 line 1
Para 3 line 2

Para 4 line 1
Para 4 line 2



Para 5 line 1
2' $'
paste -d $'
Para 5 line 1

Para 4 line 1
Para 4 line 2


Para 3 line 1
Para 3 line 2

Para 2 line 1



Para 1 line 1
Para 1 line 2
4' <(sed '/^$/s/^/\x02/' infile | tr \n$'
paste -d $'\n' <(sed '/^$/s/^/\x02/' infile | tr \n$'%pre%2' $'%pre%3'\n | \
sed -e '/^\x03$/d;s/^\x03//;s/\x03$//;1!G;h;$!d;$a\') \
<(sed -E '/^$/!d;//{:a;N;/^(\n){1,}$/ba;s/\n/\x02/g;s/(.*)\x02.*//}' infile) | \
tr $'%pre%3%pre%2' \n\n
2' $'%pre%3'\n | \ sed -e '/^\x03$/d;s/^\x03//;s/\x03$//;1!G;h;$!d;$a\') \ <(sed -E '/^$/!d;//{:a;N;/^(\n){1,}$/ba;s/\n/\x02/g;s/(.*)\x02.*//}' infile) \ | sed '$!s/\x04/\n/;$s/\x04$//' | tr $'%pre%3%pre%2' \n\n
3'\n | \ sed 's/^\x03//;1s/\x03$//;1!G;h;$!d;$a\' | tr $'%pre%3' \n
2' $'%pre%3'\n | \ sed -e '/^\x03$/d;s/^\x03//;s/\x03$//;1!G;h;$!d;$a\') \ <(sed -E '/^$/!d;//{:a;N;/^(\n){1,}$/ba;s/\n/\x02/g;s/(.*)\x02.*//}' infile) | \ tr $'%pre%3%pre%2' \n\n
2' $'%pre%3'\n | \ sed -e '/^\x03$/d;s/^\x03//;s/\x03$//;1!G;h;$!d;$a\') \ <(sed -E '/^$/!d;//{:a;N;/^(\n){1,}$/ba;s/\n/\x02/g;s/(.*)\x02.*//}' infile) \ | sed '$!s/\x04/\n/;$s/\x04$//' | tr $'%pre%3%pre%2' \n\n
3'\n | \ sed 's/^\x03//;1s/\x03$//;1!G;h;$!d;$a\' | tr $'%pre%3' \n

É muito fácil ver como funciona se você dividir em pedaços e executar sed '/^$/s/^/\x02/' infile then sed '/^$/s/^/\x02/' infile | tr \n$'paste2' $'sed3'\n e assim por diante ...

Se seus parágrafos estiverem separados por uma ou mais linhas vazias, por exemplo,

%pre%

e você quer inverter a ordem dos parágrafos, mas preservar a ordem dos "blocos vazios", você poderia ler o arquivo duas vezes:
1º: transformar os parágrafos em linhas simples (removendo blocos vazios no meio) e invertê-los. 2º: transformar os blocos vazios em linhas simples, "indexar" o número de linhas vazias em cada bloco (e remover linhas não vazias)
então \x02 os resultados e processa a saída para restaurar novas linhas:

%pre%

quais saídas:

%pre%

Se você não se importa com uma linha extra na saída, pode soltar o último \x03 :

%pre%

Eles assumem que a primeira e a última linha não estão vazias (e não há \x04 , %code% ou %code% na entrada).

    
por 29.10.2015 / 20:26
1

Você pode fazer isso com uma única instância de sed ; nenhum cano necessário. Como sed apenas faz uma passagem pelo documento e como a parte do arquivo necessária como o início da saída está no fim do arquivo, será necessário mantendo todo o arquivo na memória dentro de sed (no espaço de espera) - assim, ele pode não escalar bem. Mas responde exatamente à pergunta:

:getpara
   ${
      s/$/\
/
      G
      s/\n\n$//
      q
   }
   N
   /\n$/!bgetpara
G
h
$!d
s/\n\n$//
q

Se não houver nenhuma nova linha à direita, isso ainda funciona bem. Se houver uma nova linha à direita, ela será suprimida na saída (ou seja, não haverá uma nova linha principal na saída). Se houver (por exemplo) 5 novas linhas à direita na entrada, haverá 4 novas linhas na saída.

Os intervalos entre os parágrafos são preservados.

O espaço em branco em uma linha vazia não é tratado como uma quebra de parágrafo, mas isso é um recurso, não um bug. :)

Você também pode fazer isso como o one-liner menos legível:

sed ':k;${;s/\(\(\n\).*\)$//;G;s/\n\n$//;q;};N;/\n$/!bk;G;h;$!d;s/\n\n$//;q' inputfile

Embora isso funcione apenas com o GNU sed . (Note o uso complicado de backreferences para executar s/$/\n/ . Sem isso, não seria um one-liner literal, pois conteria uma barra invertida-newline.)

    
por 29.10.2015 / 21:08
0
gem install facets

ruby -r facets/string \
     -e 'puts $stdin.read.strip.shatter(/\n\n+/).reverse.join("")' < file

Isso deve preservar seu espaçamento entre parágrafos (embora seja mais legível do que sed :)) Embora apóie-se para obter uma resposta incrível.

    
por 17.02.2014 / 10:36