Verifique se todas as linhas de arquivo ocorrem em arquivos diferentes

12

Eu tenho dois arquivos: file1 com cerca de 10 000 linhas e file2 com algumas centenas de linhas. Eu quero verificar se todas as linhas de arquivo2 ocorrem no arquivo1. Ou seja: ∀ linha ℓ ∈ arquivo2: ℓ ∈ arquivo1

Se alguém não souber o que significam esses símbolos ou o que "verificar se todas as linhas do arquivo2 ocorrem no arquivo1" significa: Várias linhas equivalentes em um dos arquivos não influenciam se a verificação retorna ou não os arquivos. .

Como faço isso?

    
por UTF-8 12.10.2017 / 19:25

8 respostas

15
comm -13 <(sort -u file_1) <(sort -u file_2)

Este comando exibirá linhas exclusivas para file_2 . Portanto, se a saída estiver vazia, todas as linhas file_2 estarão contidas no file_1 .

Do homem do comm:

   With  no  options,  produce  three-column  output.  Column one contains
   lines unique to FILE1, column two contains lines unique to  FILE2,  and
   column three contains lines common to both files.

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)
    
por 12.10.2017 / 21:48
7
[ $(grep -cxFf file2 <(sort -u file1)) = $(sort -u file2 | wc -l) ] && 
  echo all there || 
  echo some missing

Se o número de correspondências do arquivo2 em (as linhas exclusivas de) arquivo1 for o mesmo que o número de linhas exclusivas no arquivo2, elas estarão todas lá; caso contrário, eles não são.

    
por 12.10.2017 / 20:28
5

Usando o GNU awk , onde ele suporta o recurso length(array) específico (e algumas outras implementações awk que podem suportar) e não é necessário se os arquivos forem classificados.

gawk 'FNR==NR{seen[$0];next} ($0 in seen){delete seen[$0]};
    END{print (!length(seen))?"Matched":"Not Matched"}' file2 file1

Isto está lendo arquivo2 em uma matriz chamada seen com a chave como linha inteira de arquivo2 .

Em seguida, leia arquivo1 e, para cada linha, se combinada com as linhas da matriz, exclua essa chave.

No final, se a matriz estiver vazia significa que todas as linhas em arquivo2 existem em arquivo1 e imprimirão Matched , caso contrário serão exibidas Not Matched .

Para a compatibilidade em todas as implementações de awk .

awk 'FNR==NR{seen[$0];next} ($0 in seen){delete seen[$0]};
    END{for(x in seen);print (!x)?"Matched":"Not Matched"}' file2 file1

Para ignorar linhas vazias / ou linhas com espaços em branco somente se em arquivo2 , você precisaria adicionar NF à condição em NR==FNR && NF {... para ignorar a leitura delas na matriz.

    
por 12.10.2017 / 20:21
3
diff -q <(sort -u file2) <(grep -Fxf file2 file1 | sort -u)

não produzirá saída se file1 contiver todas as linhas em file2 e sair com status 0 , caso contrário, será impresso algo como

Files /proc/self/fd/11 and /proc/self/fd/12 differ

e saia com o status 1

    
por 12.10.2017 / 19:54
3

Usando comm você pode encontrar linhas comuns em ambos os arquivos.

comm -12 file1 file2

Veja man comm para mais detalhes

    
por 12.10.2017 / 19:32
2

Se eu fosse fazer isso ocasionalmente, usaria um visualizador de diferenças gráficas como meld . Abra ambos os arquivos nele ( meld file1 file2 ) e trabalhe seu caminho no arquivo mais curto, certificando-se de que todas as suas linhas existam no outro arquivo. Demoraria alguns minutos, mas é uma ótima maneira visual de se convencer de que estão todos lá. Funcionaria melhor se muitas ou a maioria das linhas fossem agrupadas no arquivo maior.

    
por 12.10.2017 / 21:37
2

Use um programa em Python:

#!/usr/bin/env python3
import sys

def open_arg(path):
    return sys.stdin if path == '-' else open(path)

def strip_linebreak(s):
    return s[:-1] if s.endswith('\n') else s

with open_arg(sys.argv[1]) as pattern_file:
    patterns = set(map(strip_linebreak, pattern_file))

with open_arg(sys.argv[2]) as dataset_file:
    for l in map(strip_linebreak, dataset_file):
        patterns.remove(l)
        if not patterns:
            break

sys.exit(int(bool(patterns)))

Uso:

python3 contains-all.py file2 file1

O status de saída do programa indica se todos os padrões do arquivo 2 foram correspondidos:

  • 0 (sucesso) significa que todos os padrões foram correspondidos.
  • 1 (falha) significa que alguns padrões não foram correspondidos.

Para consultar o status de saída em um shell (script), você pode usar a variável $? special ou outras expressões que avaliam o status de saída do comando, e. g. operadores de curto-circuito && e || e expressões condicionais como if ou while . Exemplo:

if python3 compare-all.py file2 file1 && some-other --condition; then
    # do stuff
fi
    
por 12.10.2017 / 22:42
1

combine de moreutils mostrará todas as linhas em file2 que não estão em file1 com :

combine file2 not file1

Em seguida, você pode contar o número de linhas canalizando-o para wc -l , como:

if [ $(combine file2 not file1 | wc -l) != 0 ]; then
  echo "lines missing"
else
  echo "You're fine"
fi
    
por 12.10.2017 / 22:27