Usando Diff em uma coluna específica em um arquivo

6

Será possível usar o diff em colunas específicas em um arquivo?

arquivo1

Something  123 item1
Something  456 item2
Something  768 item3
Something  353 item4

arquivo2

Another   123 stuff1
Another   193 stuff2
Another   783 stuff3
Another   353 stuff4

saída (esperada)

Something  456 item2
Something  768 item3
Another   193 stuff2
Another   783 stuff3

Eu quero diff da segunda coluna de cada arquivo e, em seguida, o resultado conterá a coluna de comparação, mas junto com a linha inteira.

    
por kickass13 17.12.2014 / 04:50

2 respostas

8

awk é uma ferramenta melhor para comparar colunas de arquivos. Veja, por exemplo, a resposta para: compare duas colunas de arquivos diferentes e imprima se corresponder a - existem respostas semelhantes para imprimir linhas de colunas correspondentes.

Como você deseja imprimir linhas que não correspondam, podemos criar um comando awk que imprime as linhas no arquivo2 para as quais a coluna 2 não tem visto no arquivo1:

$ awk 'NR==FNR{c[$2]++;next};c[$2] == 0' file1 file2
Another   193 stuff2
Another   783 stuff3

Como explicado de forma semelhante por terdon em a questão acima mencionada ,

  • NR==FNR : NR é o número da linha de entrada atual e FNR o número da linha do arquivo atual. Os dois serão iguais apenas enquanto o primeiro arquivo estiver sendo lido.
  • c[$2]++; next : se este for o primeiro arquivo, salve o segundo campo na matriz c . Em seguida, pule para a próxima linha para que isso seja aplicado apenas no primeiro arquivo.
  • c[$2] == 0 : o bloco else só será executado se este for o segundo arquivo, então checamos se o campo 2 deste arquivo já foi visto ( c[$2]==0 ) e se foi, imprimimos a linha. Em awk , a ação padrão é imprimir a linha, portanto, se c[$2]==0 for true, a linha será impressa.

Mas você também quer as linhas do arquivo1 para as quais a coluna 2 não corresponde no arquivo2. Isso você pode obter simplesmente trocando sua posição no mesmo comando:

$ awk 'NR==FNR{c[$2]++;next};c[$2] == 0' file2 file1
Something  456 item2
Something  768 item3

Agora, você pode gerar a saída desejada, usando awk duas vezes. Talvez alguém com mais awk de especialistas possa fazê-lo de uma só vez.

Você marcou sua pergunta com /ksh , então presumo que esteja usando o shell korn. Em ksh você pode definir uma função para seu diff, digamos diffcol2 , para facilitar seu trabalho:

diffcol2()
{
   awk 'NR==FNR{c[$2]++;next};c[$2] == 0' $2 $1      
   awk 'NR==FNR{c[$2]++;next};c[$2] == 0' $1 $2      
}

Isso tem o comportamento que você deseja:

$ diffcol2 file1 file2
Something  456 item2
Something  768 item3
Another   193 stuff2
Another   783 stuff3
    
por 17.12.2014 / 06:14
3

Eu não acho que o diff (mesmo em combinação com o corte) seja flexível o suficiente para lidar com isso. E parece que o que você realmente quer é as chaves no arquivo1 que não estão no arquivo2 e vice-versa - não estritamente um diff de linha por linha. Se os arquivos de entrada são grandes, eu iria com perl, mas para arquivos pequenos este script awk funciona para a entrada fornecida:

%cat a.awk

BEGIN {
  while (getline < "file1") {
    line=$0;
    split(line,f," ");
    key=f[2];
    f1[key]=line
  }
  while (getline < "file2") {
    line=$0;
    split(line,f," ");
    key=f[2];
    f2[key]=line
  }
}
END {
  for (c in f1) {
    if (c in f2 == 0) print f1[c]
  }
  for (c in f2) {
    if (c in f1 == 0) print f2[c]
  }
}

E é assim que você o executa (note o truque com / dev / null, já que o awk espera um arquivo de entrada como parâmetro:

%awk -f a.awk /dev/null
Something  456 item2
Something  768 item3
Another   193 stuff2
Another   783 stuff3
    
por 17.12.2014 / 06:17