extrair linhas de texto de um arquivo longo

3

Eu tenho o seguinte arquivo de texto:

#unimportant comment
#possible more unimportant comments
#info1 info2 info3 ,importantname1
importanttext1
#info1 info2 info3 ,importantname2
importanttext2
#info1 info2 info3 ,importantname3
importanttext3

Eu quero dividir cada arquivo em arquivos separados. Tudo o que eu realmente preciso é extrair os URLs não comentados, preservando os comentários é opcional. Eu quero que cada arquivo seja nomeado como importantname1.txt ou o nome após a vírgula no final de cada linha de comentário anexada com .txt

so importantname1.txt teria o seguinte conteúdo:

importanttext1 

ou possivelmente

#info1 info2 info3 ,importantname1
importanttext1

para que a linha seja extraída e salva com o nome do arquivo após o comentário e anexada com .txt, neste caso, nome do arquivo importantname1.txt

É necessário fazer isso para cada conjunto de linhas no arquivo de exemplo. Preservar os comentários não é importante, mas eu preciso que ele seja roteirizado. Eu também preciso explicar um número desconhecido de linhas de comentários no cabeçalho. A linha de comentário sempre estará lá antes de cada linha importanttextX

    
por user178167 29.09.2016 / 08:39

2 respostas

2

Tente:

awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

Exemplo

Aplicado à sua entrada de amostra:

$ awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

Depois que o acima é executado, os seguintes arquivos estão no diretório:

$ ls
file  importantname1.txt  importantname2.txt  importantname3.txt

O conteúdo dos novos arquivos é:

$ cat importantname1.txt 
#info1 info2 info3 ,importantname1
importanttext1
$ cat importantname2.txt 
#info1 info2 info3 ,importantname2
importanttext2
$ cat importantname3.txt 
#info1 info2 info3 ,importantname3
importanttext3

Como funciona

O awk lê o arquivo de entrada linha a linha. Nosso script classifica essas linhas como comentários ou não-comentários. Para linhas de comentário, o nome do arquivo e o comentário são salvos. Para não comentários, um novo arquivo é criado e impresso

  • '- F,

    Isto diz ao awk para usar uma vírgula como o separador de campo na entrada. Desta forma, o nome do arquivo será sempre o último campo.

  • /^#/{f=$NF".txt";cmt=$0; next}

    Se uma linha começar com # , salvaremos o último campo, $NF , mais .txt como um nome de arquivo f . Toda a linha de comentário é salva como cmt . Em seguida, informamos ao awk para pular o restante dos comandos e pular para começar de novo na linha next .

  • printf "%s\n%s\n",cmt,$0 >f; close(f)

    Para linhas sem comentários, imprimimos o último comentário visto, cmt , e a linha atual, $0 , no nome do último arquivo f . Em seguida, fechamos o identificador de arquivo para f .

Protegendo contra nomes de arquivos incorretos

Se os campos a serem usados como nomes de arquivos contiverem / , o sistema operacional interpretará os nomes dos arquivos como diretórios de inclusão. Para evitar isso, podemos substituir todos os / por - usando gsub(/\//, "-", f) da seguinte forma:

awk -F, '/^#/{f=$NF".txt";gsub(/\//, "-", f); cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file
    
por 29.09.2016 / 08:45
0

Uma combinação de grep e csplit poderia fazer o trabalho, por a) grep ping de todas as linhas não comentadas mais as informações precedentes uma e b) dividindo a saída com base na linha de comentários info:

grep -v -B1 '^#' file | csplit -z - '/^#/' '{*}'

Ou seja. não -v extrai linhas que têm um # no início ^# , mas uma linha que precede essas linhas -B1 . Em seguida, divida a entrada canalizada de entrada - em cada # no início de uma linha, ignore os arquivos vazios -z e faça isso sempre que possível {*} .

A renomeação teria que ser uma etapa separada ( csplit autonomeia o outpit como xx00, xx01 ... - altere pre e sufixo com as opções -f e -b , respectivamente)

#/bin/bash
for f in xx* ; do
   mv "$f" "$( sed -n '2p' "$f" )".txt
done
    
por 29.09.2016 / 11:36