Sobreposição / Comparação de dois arquivos e impressão do que não corresponde

7

Olá, eu tenho dois arquivos com alguns nomes de arquivos que se parecem com isso:

Arquivo 1:

123.txt
456.txt
789.txt
101112.txt

Arquivo 2:

123.txt 
789.txt
101112.txt

Existe algum comando bash que eu possa usar para sobrepô-los e para imprimir apenas as linhas ou nomes de arquivos que não correspondem. Então estou esperando algo assim:

456.txt
    
por milan 15.01.2018 / 09:59

4 respostas

13

comm é seu amigo aqui:

Se os arquivos já estiverem classificados:

comm -3 f1.txt f2.txt

Se não estiver classificado, sort e passá-los como descritores de arquivos usando a substituição de processos (para que não seja necessário nenhum arquivo temporário):

comm -3 <(sort f1.txt) <(sort f2.txt)

Exemplo:

% cat f1.txt
123.txt
456.txt
789.txt
101112.txt

% cat f2.txt
123.txt
789.txt
101112.txt

% comm -3 <(sort f1.txt) <(sort f2.txt)
456.txt
    
por heemayl 15.01.2018 / 10:38
3

Uma abordagem simples seria usar dois comandos 'grep', que cada um pega um dos arquivos como uma lista de linhas para pesquisar o outro arquivo. Supondo que seus arquivos são nomeados f1.txt e f2.txt:

grep -Fxvf f1.txt f2.txt ; grep -xvf f2.txt f1.txt

As opções grep usadas são as seguintes:

  • -F - Use cada linha como uma string fixa para corresponder, em vez de uma expressão regular
  • -x - corresponde apenas linhas inteiras
  • -v - Inverte a correspondência para selecionar linhas não correspondentes
  • -f - Use o arquivo fornecido como argumento como uma lista de padrões para corresponder
por Arronical 15.01.2018 / 10:54
2

Eu entendo sua pergunta da maneira que você quer que todas as linhas apareçam em apenas um dos arquivos, não em ambos, e desconsiderando a ordem da linha.

Suponho também que comparamos os arquivos f1.txt e f2.txt . Insira seus respectivos nomes.

Usando o Bash, você pode fazer isso com dois loops, onde cada um processa um arquivo e verifica cada linha se ela aparecer no outro. Essa abordagem não é muito eficiente, mas deve funcionar:

# This loops over f1.txt and searches each line in f2.txt
while read line ; do grep -Fxqe "$line" f2.txt || echo "$line" ; done < f1.txt 

# This loops over f2.txt and searches each line in f1.txt
while read line ; do grep -Fxqe "$line" f1.txt || echo "$line" ; done < f2.txt 

Ambos os loops juntos produzem o resultado desejado. Cada um por si só verifica as linhas em um arquivo que não aparecem no outro.

Uma solução mais simples poderia ser escrita, por ex. com um one-liner curto em Python:

python3 -c 's1=set(open("f1.txt")); s2=set(open("f2.txt")); print(*s1.symmetric_difference(s2), sep="")'

Isso usa uma estrutura de dados Set, que contém apenas valores exclusivos e permite definir operações como "diferença simétrica".

Observe que, ao usar as duas soluções, se algum dos arquivos contiver linhas duplicadas, elas serão ignoradas e tratadas apenas como uma única ocorrência.

    
por Byte Commander 15.01.2018 / 10:40
1

Supondo que você não precisa que os resultados permaneçam na ordem original, use:

cat file1 file2 | sort | uniq -u

Explicação:

cat file1 file2

Gera os dois arquivos para a saída padrão, um após o outro.

sort

Classifica o conteúdo combinado dos dois arquivos. O efeito colateral útil em que estamos interessados é que isso coloca linhas idênticas dos dois arquivos ao lado um do outro.

uniq -u

Exibe apenas as linhas que são "exclusivas", ou seja, que ocorrem apenas uma vez. Bastante irritante, isso apenas analisa pares de linhas adjacentes, e é por isso que o comando anterior sort é necessário.

Você também pode usar uniq -d para gerar apenas as linhas que ocorrem duas vezes. Isso fornecerá as linhas comuns aos dois arquivos.

OBSERVAÇÃO: Não tenho certeza de como essa solução funciona se as mesmas linhas ocorrerem mais de uma vez no mesmo arquivo.

    
por Micheal Johnson 15.01.2018 / 22:52