Procure e exclua linhas que correspondam a um padrão junto com comentários na linha anterior, se houver

2

Eu tenho um requisito para escrever um script de shell em csh para pesquisar e excluir linhas que correspondam a um padrão junto com comentários na linha anterior, se houver. Por exemplo, se meu arquivo tiver as seguintes linhas

Shell script
#this is  a test
pattern1
format1
pattern2
format2
#format3
pattern3

Se o padrão de pesquisa for "padrão", a saída deverá ser a seguinte

Shell script
format1
format2

Para ser mais preciso, as linhas que têm o padrão e a linha anterior, se começar com "#", devem ser excluídas

Obrigado pela ajuda

    
por Dennis Williamson 02.12.2009 / 19:51

5 respostas

1

Provavelmente, uma maneira melhor de escrever isso logicamente, mas acho que isso pode ser feito:

#!/usr/bin/perl
use strict;
use warnings;


my $previous_line = '';
while(<>) {
    if ( /pattern/ ) {
        if ( (! ($previous_line =~ /^#/)) && (! ($previous_line =~ /pattern/))) {
            print $previous_line;
        }
    } elsif (! ($previous_line =~ /pattern/)) {
        print $previous_line;
    }
    $previous_line = $_;
}
print $previous_line if not ($previous_line =~ /pattern/);

Basicamente, o loop é uma linha atrás da linha anterior. Ele diz que não há problema em imprimir a linha anterior se:

  1. Se a linha atual corresponder ao padrão: OK para imprimir anterior, desde que o anterior também não corresponda ao padrão ou seja um comentário.
  2. Se esta linha não for padrão, é ok para imprimir a linha anterior como desde que não correspondesse ao padrão.

Você pode salvar o código em um arquivo e usá-lo como: perl thefile.pl textfile_you_want_to_filter

    
por 02.12.2009 / 21:41
0

Antes de qualquer coisa, ninguém deveria usar csh para nada - é desatualizado e não (não "sob") alimentado. Em segundo lugar, duvido que esteja à altura da tarefa. Em terceiro lugar, é muito mais provável que awk , sed ou mesmo Perl seja uma ferramenta muito melhor para a tarefa.

awk '/^#/ {printf line; line=$0"\n"; next} /pattern/ {line=""} ! /pattern/ {printf line; print; line=""}'

Editar: script fixo para lidar corretamente com linhas de comentários

    
por 02.12.2009 / 20:31
0

Aqui está uma solução de uma linha em Perl (não em shell C). Você pode modificar a expressão /pattern/ regular no meio.

perl -ne 'if(/^#/){$c=$_}elsif(!/pattern/){print$c,$_;$c=""}else{$c=""}' <file.in
    
por 02.12.2009 / 21:44
0

Aqui está uma versão sed . Algumas versões de sed podem precisar de partes deste separado em várias cláusulas -e .

sed '$b;N;/^#.*\npattern.*$/ ! {P;D}; :c; $d; s/.*\n//;N;/^#.*\npattern.*$/ {bc}; /^pattern/d; D' patterns

Aqui está uma versão do arquivo de script desse one-liner com comentários:

#!/bin/sed -f

# Search for a combination of a comment followed by a pattern
# until that, print what you find.
$b
N
/^#.*\npattern.*$/ ! {
P
D
}

:c
# Got a comment and a pattern combination in pattern space.
# At the end of the file we simply exit
$d

# Else, we keep reading lines with 'N' until we
# find a different one
s/.*\n//
N
/^#.*\npattern.*$/ {
bc
}

# Remove standalone lines that have "pattern"
/^pattern/d

# Remove the last instance of the combination
# and go back to the top
D

Isto é baseado no script em info sed seção 4.16 "Remover Todas as Linhas Duplicadas" (uniq -u).

    
por 03.12.2009 / 04:53
0

Tem que ser script de shell?

  1. abrir arquivo com vi
  2. :g/<pattern>/d
  3. repetir conforme necessário para mais tipos de padrão, a menos que você possa regex o padrão
  4. :g/^#/d

pode ser efetivamente reproduzido usando sed se tiver que ser roteirizado

editar:

1.criar o arquivo .script:

/pattern/d
/^#/d

2. sed -f .sedscript <inputfile> > <outputfile>

Isso não satisfaz um requisito para excluir a linha anterior, mas seu exemplo não parece exigir essa funcionalidade.

    
por 03.12.2009 / 03:51