Como posso extrair linhas de texto de um arquivo?
Pergunta
Eu tenho um diretório cheio de arquivos e eu preciso puxar os cabeçalhos e rodapés fora deles. Eles são todos comprimento variável para usar a cabeça ou cauda não está indo para o trabalho. Cada arquivo tem uma linha que eu posso procurar, mas eu não quero incluir a linha nos resultados.
É geralmente
*** Start (more text here)
e termina com
*** Finish (more text here)
Eu quero que os nomes de arquivo para permanecer o mesmo, então eu preciso para substituir os originais, ou escreva para um diretório diferente e eu vou substituí-los eu mesmo.
Oh sim, é em um servidor Linux é claro, então eu tenho Perl, sed, awk, grep, etc.
Solução
Tente o flop aleta! ".." operador.
# flip-flop.pl
use strict;
use warnings;
my $start = qr/^\*\*\* Start/;
my $finish = qr/^\*\*\* Finish/;
while ( <> ) {
if ( /$start/ .. /$finish/ ) {
next if /$start/ or /$finish/;
print $_;
}
}
U pode usar o interruptor perl -i para atualizar o arquivo (s) como assim .....
$ perl -i'copy_*' flip-flop.pl data.txt
... que muda data.txt mas faz uma cópia de antemão como "copy_data.txt".
Outras dicas
coreutils GNU são seu amigo ...
csplit inputfile %^\*\*\* Start%1 /^\*\*\* Finish/ %% {*}
Isso produz o arquivo desejado como xx00
. Você pode alterar esse comportamento através do --prefix
opções, --suffix
e --digits
, mas veja a manual para si mesmo. Desde csplit
é projetado para produzir uma série de arquivos, não é possível produzir um arquivo sem sufixo, assim você terá que fazer o substituir manualmente ou através de um script:
csplit $1 %^\*\*\* Start%1 /^\*\*\* Finish/ %% {*}
mv -f xx00 $1
Adicionar loops de como você deseja.
Para obter o cabeçalho :
cat yourFileHere | awk '{if (d > 0) print $0} /.*Start.*/ {d = 1}'
Para obter o rodapé :
cat yourFileHere | awk '/.*Finish.*/ {d = 1} {if (d < 1) print $0}'
Para obter o arquivo de cabeçalho para rodapé como você quer:
cat yourFileHere | awk '/.*Start.*/ {d = 1; next} /.*Finish.*/ {d = 0; next} {if (d > 0) print $0}'
Há mais de uma maneira, com o comando csplit, você deve tentar algo como:
csplit yourFileHere /Start/ /Finish/
E examinar arquivos chamados 'xxNN', onde NN está funcionando número, também dar uma olhada em csplit manpage .
Talvez? Início ao fim com não-exclusão.
$ sed -i '/^\*\*\* Start/,/^\*\*\* Finish/d!' *
ou ... menos certeza disso ... mas, se ele funciona, deve remover as linhas de início e término, bem como:
$ sed -i -e '/./,/^\*\*\* Start/d' -e '/^\*\*\* Finish/,/./d' *
d!
pode depender da largura do sed
você tem - não tenho certeza
.
E, eu escrevi que a memória inteiramente em (provavelmente pobres).
Um hack Perl rápida, não testada. Eu sou o suficiente para não fluente em sed ou awk para obter este efeito com eles, mas eu estaria interessado em como isso seria feito.
#!/usr/bin/perl -w
use strict;
use Tie::File;
my $Filename=shift;
tie my @File, 'Tie::File', $Filename or die "could not access $Filename.\n";
while (shift @File !~ /^\*\*\* Start/) {};
while (pop @File !~ /^\*\*\* Finish/) {};
untie @File;
Alguns dos exemplos em perlfaq5: Como faço para alterar, excluir ou inserir uma linha em um arquivo ou acréscimo para o início de um arquivo? pode ajudar. Você vai ter que adaptá-las à sua situação. Além disso, a resposta do operador flip-flop de Leon é a maneira idiomática de fazer isso em Perl, embora você não tem que modificar o arquivo no lugar de usá-lo.
A Perl solução que substitui o arquivo original.
#!/usr/bin/perl -ni
if(my $num = /^\*\*\* Start/ .. /^\*\*\* Finish/) {
print if $num != 1 and $num + 0 eq $num;
}