Eu encontrei algo que funciona:
grep -A3 derp filename | diff - filename
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.
Eu encontrei algo que funciona:
grep -A3 derp filename | diff - filename
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.
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
).
Tags grep