Procura por um arquivo por linhas que NÃO contêm uma frase com contexto

1

Eu tenho um arquivo com muitas entradas que consistem em uma palavra-chave seguida por várias linhas de números. Eu quero filtrar uma categoria de entradas, por isso, se derp entrada é seguido por três linhas eu quero algo como grep -v -A3 derp filename para obter cada entrada no nome do arquivo que não é do tipo derp. O problema é que -v e -A parecem ser incompatíveis. Quando os dois sinalizadores são usados, -v é ignorado. De que outra forma posso fazer isso? O arquivo é assim:

SOURCE: pI < min 45 16 0 7.4871483836177132E-004 5.1628324610858206E-004 -1.826383220714803 -9.4293105782888549E-004 -6.8875048798939895E-002 -0.2196057448134437 -6.6270591049115615E-003 SOURCE: pI < min 45 17 0 7.1266687952112871E-004 5.1628324610858206E-004 -2.169039713847648 -1.1198388644036935E-003 -8.2240618017566103E-002 -9.0412967200093102E-005 -7.5453919169102962E-003 SOURCE: pI < min 45 18 0 7.0936181176839061E-004 5.1628324610858206E-004 -2.589392543137075 -1.3368599876201657E-003 -9.8187643312659903E-002 -1.1762198384731523E-005 -9.4417591779528513E-003

Isso continua de forma semelhante por muitos milhares de linhas. Ocasionalmente, há uma entrada que começa com algo diferente de SOURCE: pI < min . São essas entradas que quero encontrar. O arquivo é ~ 50Mb.

    
por Matthew Bedford 21.09.2015 / 16:31

3 respostas

3

Eu encontrei algo que funciona:

grep -A3 derp filename | diff - filename
    
por 21.09.2015 / 18:27
1

Que tal fazer isso de uma direção diferente?

sed '/pattern/,+3d' input_file

Como alternativa, se você não tiver gnu sed :

sed '/pattern/ {N;N;N;d;} input_file

Exibirá todo o texto, menos a linha que contém o padrão e as três linhas que seguem essa linha.

ou se você quiser editar o arquivo no local:

sed -i '/pattern/,+3d' input_file

se -i não for suportado pelo seu sed :

sed '/pattern/ {N;N;N;d;} inputfile > output_file
mv output_file input_file

Estes devem essencialmente fazer o que você quer ... ou seja, com um arquivo que contenha

cat
dog
dog
dog
horse

Eu teria apenas horse , se cat fosse meu padrão.

    
por 22.09.2015 / 01:18
0

Assumindo que as outras entradas indesejadas não eram todas numéricas, você poderia criar uma lista delas com grep -v '^([0-9-]+|SOURCE:)' filename . Isso gera as linhas de correspondência inteiras, de modo que seria necessário um processamento adicional.

Se todos seguirem o padrão de uma palavra seguido por dois pontos, você poderá usar awk -F: '!/^([0-9]+|SOURCE:)/ { print $1}' .

Depois de ter a lista, você pode usá-la para criar uma expressão regular que corresponda a todas e, em seguida, usar isso em sed para excluir 4 linhas sempre que encontrar uma das correspondências.

Por exemplo:

LIST=$(awk -F: '!/^([0-9-]+|SOURCE:)/ { print $1}' filename | sort -u)
RE=$(echo $LIST | sed -e 's/ /|/g')

sed -r -e "s/^($RE):/,4 d" filename

Se você precisar realizar mais processamento na lista antes de criar a expressão regular, por exemplo, para remover algumas entradas, você poderia fazer assim:

RE=$(echo "$LIST" | egrep -v '^(FOO|BAR)$' | xargs echo | sed -e 's/ /|/g')

Observe as aspas duplas em torno de "$ LIST" desta vez - isso preserva as quebras de linha para uso do egrep (é por isso que temos que percorrer xargs echo mais tarde para obter todas as entradas da lista em uma linha por sed ).

    
por 22.09.2015 / 00:56

Tags