Dividir o arquivo de texto em vários quando o padrão aparecer, com a linha de comando no linux

2

Eu quero dividir um arquivo de texto em vários. Um novo arquivo toda vez que o padrão aparecer. Exemplo: O padrão será PAT

Conteúdo original do arquivo:

PAT --example html http://askubuntu.com/page01
ABC
DEF

PAT --example html http://askubuntu.com/page02
GHI
JKL

PAT --example html http://askubuntu.com/page03
MNO
PQR

(e assim por diante)

O arquivo original é chamado original.txt Eu gostaria de obter arquivos assim:

$ cat page01.txt
ABC
DEF
$ cat page02.txt
GHI
JKL
$ cat page03.txt
MNO
PQR

(e assim por diante)

Idealmente, com comandos como grep, awk ... A renomeação dos arquivos é secundária, mas seria uma vantagem para ajudar a classificá-los. Agradecemos antecipadamente.

    
por tom_len 01.10.2015 / 01:57

3 respostas

5

Você pode usar awk com algum redirecionamento:

awk -F/ '/^PAT/{close(file);file = $NF; next} /./{print >> file}' foo

O resultado:

$ head page0*
==> page01 <==
ABC
DEF    

==> page02 <==
GHI
JKL    

==> page03 <==
MNO
PQR

Essencialmente, para cada linha que começa com PAT , estou salvando o último campo (por meio de um separador de campo / ) da variável file e imprimindo todas as linhas não vazias ( /./ corresponde linhas com pelo menos um caractere) para o nome contido em file .

Observe que é importante fechar o arquivo anterior em cada loop para evitar um erro "makes too many open files" quando há "muito" arquivo criado.

    
por muru 01.10.2015 / 02:04
3

Como o @muru me venceu na solução awk , aqui está uma abordagem Perl (mas use o @ Muru, é mais simples e eficiente):

perl -00ne 's#PAT.*/(.*)\n##; open($F,">",".txt"); s/\n\s*(\n|$)//g; 
            print $F "$_\n"' original.txt 

O -00 torna perl tratar os parágrafos como linhas: uma "linha" (um "registro") é agora um parágrafo, definido por uma linha vazia. s#PAT.*/(.*)\n## removerá a linha que começa com PAT do registro e os parênteses capturam a última palavra depois de / como . Em seguida, abrimos .txt para gravação ( open($F,">",".txt") ) com o arquivo manipular $F . A próxima etapa, s/\n\s*\n//g; remove linhas em branco e, finalmente, o registro atual é impresso no manipulador de arquivo $F com print $F "$_\n" .

Para usar tudo depois do // como nome, tente:

perl -00ne 's#PAT.*//(.*)\n##; $k=; $k=~s#[./]##g;open($F,">","$k.txt"); 
              s/\n\s*(\n|$)//g; print $F "$_\n"' original.txt 

No seu exemplo, isso resultaria nos seguintes arquivos:

askubuntucompage01.txt
askubuntucompage02.txt
askubuntucompage03.txt
    
por terdon 01.10.2015 / 02:25
0

Veja também o csplit (1):

csplit --suppress-correspondido --prefix page --suffix-format% 02d.txt original.txt '/ ^ PAT /' '{*}'

    
por Greg 01.10.2015 / 11:08