compara o conteúdo de dois arquivos de texto no Ubuntu?

1

Eu preciso comparar o conteúdo dos arquivos de texto (como um todo e não em linha como o comando diff) e imprimir o texto que está faltando. Existe um comando para fazer isso? Agradecemos antecipadamente.

EDIT: Por exemplo, digamos file1 tem:

1 2 3
4 5

o arquivo 2 tem:

1 5
2 3 4 6

Eu quero comparar esses arquivos e imprimir como saída:

6

O comando diff compara os arquivos de texto linha por linha, nesse caso, quase todo o arquivo será impresso. (Meus arquivos reais são mais complicados e longos, então estou dando um exemplo simples.)

    
por samhitha 27.02.2017 / 06:28

5 respostas

4

Como o pedido não importa, você pode usar o awk para imprimir linhas exclusivas, mas com linhas de separação de espaço em branco:

awk -v RS='[[:space:]]+' 'FNR==NR {a[$0]++; next} {a[$0]--} END {for (i in a) if (a[i] != 0) print i}' file1 file2

Aqui:

  • -v RS='[[:space:]]+' define o separador de registro (RS) para qualquer espaço em branco, portanto, cada "linha" será separada por qualquer espaço em branco (incluindo novas linhas).
  • FNR == NR - FNR é o número do registro ( NR ) (ou, número da linha, se preferir) para o arquivo atual e NR é o número geral da linha em todos os arquivos de entrada. Então, sempre que esses dois são iguais, estamos lidando com o primeiro arquivo.
  • {a[$0]++; next} - define e incrementa a contagem de aparências da "linha" atual, depois passa para a próxima linha sem processar mais nenhuma regra. Esse bloco é executado apenas para o primeiro arquivo, portanto, o efeito é que essa regra se aplica a linhas do primeiro arquivo e o próximo bloco se aplica a todos os outros arquivos.
  • {a[$0]--} , diminui a contagem de aparências da "linha" atual.
  • END {for (i in a) if (a[i] != 0) print i} - no final de todas as entradas, para cada entrada na matriz a , imprima essa entrada se a contagem de aparências não for 0. Assim, qualquer "linha" que tenha sido vista um número igual de vezes em ambos os arquivos será ignorado.
por muru 27.02.2017 / 07:21
1

Esta é outra solução:

comm -3 <( cat file1 | tr ' \t' '\n' | sort) <(cat file2 | tr ' \t' '\n' | sort) | sort -u

onde:

  • tr ' \t' '\n' | sort substitui espaço e tab por nova linha e reordena o resultado
  • comm Compara os arquivos classificados file1 e file2 linha por linha e com -3 opção suprime as linhas que aparecem nos dois arquivos
  • sort -u , por último, remove linhas duplicadas, isso é necessário no caso de um token duplicado

Nesse caso, tr ' ' '\n' | sort output é usado como entrada padrão para o comando comm .

    
por Lety 14.03.2018 / 11:08
0

Outra solução (python):

def readFile(fi):
  return open(fi,"rb").read().decode(cod)
def process(text):
  return text.replace("\n"," ").split(" ")

print(set([x for x in process(readFile(file1,"utf-8")) if not x==""]).difference(set([x for x in process(readFile(file2,"utf-8")) if not x==""])))
    
por Gildo 14.03.2018 / 13:16
0

Preparação dos arquivos

Se bem entendi, você deseja imprimir números únicos ou palavras na comparação. Eu converteria os arquivos de modo que cada número / palavra tivesse uma linha própria, classificasse-os, removesse linhas em branco e duplicatas e depois comparasse os arquivos.

Eu assumo que os caracteres de espaço estão separando os números ou palavras. Para cada arquivo

< file-x.orig tr ' ' '\n' | tr -s '\n' '\n' |sort -u > file-x.1

Veja man tr para detalhes.

Se você quiser classificar numericamente, poderá adicionar a opção -n ou -h dependendo do formato numérico. Veja man sort para detalhes.

O exemplo da sua pergunta original,

No exemplo da pergunta original, usaria -n ,

< file-x.orig tr ' ' '\n' | tr -s '\n' '\n' |sort -nu > file-x.1

onde x pode ser aeb para os dois arquivos para comparar, por exemplo

< file-a.orig tr ' ' '\n' | tr -s '\n' '\n' |sort -nu > file-a.1
< file-b.orig tr ' ' '\n' | tr -s '\n' '\n' |sort -nu > file-b.1

Você pode inspecionar esses arquivos convertidos e classificados, se desejar.

Por fim, compare os arquivos com a seguinte linha de comando,

$ diff file-a.1 file-b.1
5a6
> 6

Isso identifica o número, que só é encontrado no segundo arquivo de sua entrada de amostra da pergunta original. Veja man diff para detalhes, se você quiser uma saída modificada de diff .

Meu exemplo

Este é um exemplo com um número único em cada um dos arquivos.

$ echo '1 2 3 4 5'>file-c.orig
$ echo '2 3 4 5 6'>file-d.orig
$ < file-c.orig tr ' ' '\n' | tr -s '\n' '\n' |sort -nu > file-c.1
$ < file-d.orig tr ' ' '\n' | tr -s '\n' '\n' |sort -nu > file-d.1
$ diff  file-c.1 file-d.1
1d0
< 1
5a5
> 6

Isso identifica

  • '1' que só é encontrado no primeiro arquivo, indicado por '<'
  • '6' que só é encontrado no segundo arquivo, indicado por '>'

O exemplo no comentário de Lety

% bl0ck_qu0te%
$ echo '1 3 1 4 5'>file-e.orig
$ echo '5 1 4 3 6'>file-f.orig

$ < file-e.orig tr ' ' '\n' | tr -s '\n' '\n' |sort -nu > file-e.1
$ < file-f.orig tr ' ' '\n' | tr -s '\n' '\n' |sort -nu > file-f.1
$ diff  file-e.1 file-f.14a5
> 6

$ comm -3 <( cat file-e.orig | tr ' \t' '\n' | sort) <(cat file-f.orig | tr ' \t' '\n' | sort) | sort -u
1
    6

$ awk -v RS='[[:space:]]+' 'FNR==NR {a[$0]++; next} {a[$0]--} END {for (i in a) if (a[i] != 0) print i}' file-e.orig file-f.orig
1
6

Nesse caso, meu método mostra um resultado diferente em comparação com os métodos de @Lety e @muru. Vamos esperar que o OP, @samhitha, nos diga qual é a saída desejada da comparação.

    
por sudodus 14.03.2018 / 11:39
0

Assumirei o seguinte: Seus arquivos consistem em dados, que são separados por um espaço ou nova linha E você não se importa em saber onde os dados estão faltando (ou sabe que está sempre, por exemplo, no arquivo2).

O que faremos é simples: Substitua cada espaço por uma nova linha em ambos os arquivos, concatene-os e pesquise apenas as entradas únicas (exclusivas):

sort <( tr ' ' '\n' < file1 ) <(tr ' ' '\n' < file2) | uniq -u
    
por Fiximan 27.02.2017 / 16:01