Uma abordagem seria encontrar primeiro todos os conjuntos de 12 caracteres iniciais presentes em mais de um arquivo:
cut -c-12 file* | sort | uniq -c
O comando cut
acima imprime os primeiros 12 caracteres de cada arquivo cujo nome começa com file
, eles são classificados e o número de vezes que cada linha é encontrada é anexado por uniq -c
. Executando isso nos seus arquivos de exemplo retorna:
$ cut -c-12 file* | sort | uniq -c
1 -13 -3 -1
2 -13 -3 -2
2 -13 -3 -3
2 -13 -4 0
2 -13 -4 -1
2 -13 -4 -2
2 -13 -5 0
Assim, todas as linhas, exceto a primeira, aparecem nos dois arquivos. Agora, mantenha apenas as linhas que aparecem no número de vezes desejado (20 no seu caso):
cut -c-12 file* | sort | uniq -c | rev | sed -n 's/ 20 *$//p' | rev
rev
simplesmente imprime sua entrada invertida. Eu estou usando aqui para fazer o número de vezes que cada linha foi vista no último campo. Isso é então passado para sed
, que é dito para imprimir apenas as linhas que terminam com um espaço, 20 e 0 ou mais espaços. Isso mantém apenas as linhas que apareceram 20 vezes e a% final rev
nos traz de volta ao formato original.
Agora você pode passar a coisa toda para grep
como uma lista de strings para pesquisar:
$ grep -f <(cut -c-12 file* | sort | uniq -c |
rev | sed -n 's/ 20 *$//p' | rev) file*
-13 -5 0 19.3769 46.9197 1
-13 -4 -2 347.911 57.7232 1
-13 -4 -1 38.5696 39.0027 1
-13 -4 0 2227.39 124.894 1
-13 -3 -3 113.001 40.2117 1
-13 -3 -2 850.847 78.2881 1
Se o seu shell não suportar o formato <()
, você poderá salvar os resultados de cut
em um arquivo separado e usá-lo, ou apenas executá-lo em um loop:
cut -c-12 file* | sort | uniq -d |
while IFS= read -r l; do grep -- "^$l" file1; done
Para ter a saída de cada arquivo em um arquivo separado, use:
cut -c-12 file* | sort | uniq -c | rev | sed -n 's/ 20 *$//p' | rev > list
for f in file*; do grep -f list "$f" > "$f.new"; done