Como posso obter o diff para mostrar apenas linhas adicionadas e excluídas? Se o diff não pode fazê-lo, que ferramenta pode?

69

Como posso obter o diff para mostrar apenas linhas adicionadas e excluídas? Se o diff não pode fazê-lo, que ferramenta pode?

Cruz
fonte
2
Você precisa definir melhor o que você quer dizer com adicionado e excluído. Especificamente, uma linha pode mudar? Se sim, como você deseja que uma linha alterada seja manipulada? Se você estiver fazendo uma verificação estritamente orientada à linha, uma alteração de linha será idêntica à linha antiga que está sendo removida e à nova linha que está sendo adicionada. Por exemplo, como ele deve lidar com uma linha dividida em duas? Como duas linhas 1 mudaram? 2 linhas alteradas? 1 linha removida e 2 linhas adicionadas? A menos que você possa garantir que as linhas nunca mudem, apenas sejam adicionadas e excluídas, acho que isso está fadado ao fracasso sem melhores definições.
Christopher Cashell
Acho a pergunta pouco clara. Mas pelo menos uma interpretação da questão poderia ser respondida comdiff A B | grep '^[<>]'
kasperd
Você pode estar procurando comm.
Jenny D diz Restabelecer Monica
@ChristopherCashell, ele quer dizer ignorar a ordem de classificação; um problema tipicamente comum. Normalmente, isso é feito classificando primeiro os segmentos (linhas) de cada lado antes de fazer uma comparação típica.
Pacerier 10/03
@ Pacerier, você tem certeza disso? Ou você está adivinhando? Nada sobre classificação ou ordem de pesquisa é mencionado ou sugerido na pergunta. Tal como está, a questão não é clara e pode ser interpretada de várias maneiras diferentes. Sem saber ao certo o que ele está perguntando, estamos fazendo suposições e oferecendo soluções que podem ou não resolver o problema real. Além disso, o comentário do pôster original em uma das respostas sugere que isso não está relacionado à classificação. Tem a ver com o significado de "adicionado e excluído" vs. "alterado".
Christopher Cashell

Respostas:

82

Tente comm

Outra maneira de ver isso:

  • Mostrar linhas que existem apenas no arquivo a: (ou seja, o que foi excluído de a)

    comm -23 a b
    
  • Mostrar linhas que existem apenas no arquivo b: (ou seja, o que foi adicionado a b)

    comm -13 a b
    
  • Mostrar linhas que existem apenas em um arquivo ou no outro: (mas não ambos)

    comm -3 a b | sed 's/^\t//'
    

(Aviso: se o arquivo ativer linhas que começam com TAB, ele (o primeiro TAB) será removido da saída.)

Apenas arquivos classificados

NOTA: Os dois arquivos precisam ser classificados para commfuncionarem corretamente. Se eles ainda não estiverem classificados, você deve classificá-los:

sort <a >a.sorted
sort <b >b.sorted
comm -12 a.sorted b.sorted

Se os arquivos forem extremamente longos, isso pode ser um fardo, pois requer uma cópia extra e, portanto, duas vezes mais espaço em disco.

TomOnTime
fonte
5
só queria acrescentar que ambos os arquivos precisa ser resolvido (case sensitive) para esta solução para produzir resultados corretos
marmor
11
Nos reservatórios suficientes modernos, você pode classificar em linha com algo comocomm -12 <(sort a) <(sort b)
Joshua Huber
14

commpode fazer o que quiser. Na sua página de manual:

DESCRIÇÃO

Compare os arquivos classificados FILE1 e FILE2 linha por linha.

Sem opções, produza saída de três colunas. A coluna um contém linhas exclusivas para FILE1, a coluna dois contém linhas exclusivas para FILE2 e a coluna três contém linhas comuns aos dois arquivos.

Estas colunas são suppressable com -1, -2e -3respectivamente.

Exemplo:

[root@dev ~]# cat a
common
shared
unique

[root@dev ~]# cat b
common
individual
shared

[root@dev ~]# comm -3 a b
    individual
unique

E se você quer apenas as linhas exclusivas e não se importa em qual arquivo elas estão:

[root@dev ~]# comm -3 a b | sed 's/^\t//'
individual
unique

Como diz a página do manual, os arquivos devem ser classificados com antecedência.

markdrayton
fonte
9

Para mostrar adições e exclusões sem contexto, números de linhas, +, -, <,>! etc, você pode usar o diff assim:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

Por exemplo, dados dois arquivos:

a.txt

Common
Common
A-ONLY
Common

b.txt

Common
B-ONLY
Common
Common

O comando a seguir mostrará as linhas removidas de a ou adicionadas a b:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

resultado:

B-ONLY
A-ONLY

Este comando ligeiramente diferente mostrará as linhas removidas do a.txt:

diff --changed-group-format='%<' --unchanged-group-format='' a.txt b.txt 

resultado:

A-ONLY

Por fim, este comando mostrará linhas adicionadas ao a.txt

diff --changed-group-format='%>' --unchanged-group-format='' a.txt b.txt 

resultado

B-ONLY
iphonedroid
fonte
2

Isso é o que diff faz por padrão ... Talvez você precise adicionar alguns sinalizadores para ignorar o espaço em branco?

diff -b -B

deve ignorar linhas em branco e diferentes números de espaços.

Scott Lundberg
fonte
11
Não, mostra também linhas ALTERADAS (linhas que possuem um caractere ou quatro diferentes). Eu quero linhas que existem apenas na esquerda ou direita.
259 Ross C.
2
Você pode argumentar que as diferentes versões de um arquivo CHANGED existem apenas à esquerda ou à direita.
markdrayton
2
Não há como o diff (ou qualquer outra ferramenta) dizer com segurança o que é uma alteração e o que é uma linha excluída sendo substituída por uma nova linha.
Cian
11
Tecnicamente, o diff trata uma linha "alterada" como se a linha original tivesse sido excluída e uma nova linha fosse adicionada ... portanto, tecnicamente, ele mostra apenas as linhas adicionadas e excluídas.
KFro
2

Não, diffna verdade não mostra as diferenças entre dois arquivos da maneira que se pensa. Ele produz uma sequência de comandos de edição para uma ferramenta que patché usada para mudar um arquivo para outro.

A dificuldade para qualquer tentativa de fazer o que você está procurando é como definir o que constitui uma linha que foi alterada versus uma excluída, seguida por uma adicionada. Também o que fazer quando as linhas são adicionadas, excluídas e alteradas adjacentes umas às outras.

Dennis Williamson
fonte
Meus pensamentos exatamente. Qual a porcentagem de caracteres em uma linha que precisa ser alterada para considerá-la nova em vez de uma modificação do original? Tecnicamente, mesmo se você tiver um caractere em comum, considere-o uma "alteração" em vez de uma exclusão e inserção.
27511 Kamil Kisiel
11
Já faz muito tempo que não vejo as difffontes, mas me lembro de todos os tipos de variações para acompanhar onde dois arquivos correspondem para ficar sincronizados e acho que há um limite para desistir com base na distância entre os arquivos. linhas são. Mas não me lembro de nenhuma correspondência intra-linha, exceto pelo espaço em branco recolhido (opcionalmente) ou caso de ignorância. Ou (talvez) palavras para esse efeito. De qualquer forma, tudo se patchresume e o "vgrep" aparece para o passeio. Talvez. Na terça-feira.
Dennis Williamson
2

As ferramentas de comparação visual ajustam dois arquivos, para que um segmento com o mesmo número de linhas, mas com conteúdo diferente, seja considerado um segmento alterado. Linhas completamente novas entre segmentos correspondentes são consideradas segmentos adicionados.

É também assim que a ferramenta de linha de comando sdiff funciona, que mostra uma comparação lado a lado de dois arquivos em um terminal. As linhas alteradas são separadas por | personagem. Se uma linha existir apenas no arquivo A, <será usado como caractere separador. Se uma linha existir apenas no arquivo B,> será usado como separador. Se você não tiver caracteres <e> nos arquivos, poderá usar isso para mostrar apenas linhas adicionadas:

sdiff A B | grep '[<>]'
Seppo Enarvi
fonte
2

Obrigado senarvi, sua solução (que não foi votada) na verdade me deu EXATAMENTE o que eu queria depois de procurar por séculos em várias páginas.

Usando sua resposta, aqui está o que eu criei para alterar a lista / adicionar / excluir. O exemplo usa 2 versões do arquivo / etc / passwd e imprime o nome de usuário para os registros relevantes.

#!/bin/bash
sdiff passwd1 passwd2 | grep '[|]' | awk -F: '{print "changed: " $1}'
sdiff passwd1 passwd2 | grep '[<]' | awk -F: '{print "deleted: " $1}'
sdiff passwd1 passwd2 | grep '[>]' | awk -F\> '{print $2}' | awk -F: '{print "added: " $1}'
geniosidade
fonte
Observe que como a diferença entre "uma linha foi modificada" e "uma linha foi removida e outra linha foi adicionada abaixo ou acima dela" é semântica. Uma ferramenta diff genérica baseada em texto não pode separar esses casos. Como resultado, sua resposta baseada em sdiff não pode funcionar de maneira confiável em todos os casos.
Mikko Rantalainen
0

Acho esse formulário em particular frequentemente útil:

diff --changed-group-format='-%<+%>' --unchanged-group-format='' f g

Exemplo:

printf 'a\nb\nc\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

Resultado:

-b
-c
+B
+C
-e
-f
+E
+F

Portanto, mostra as linhas antigas com -seguidas imediatamente pela nova linha correspondente com +.

Se tivéssemos uma exclusão de C:

printf 'a\nb\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

Se parece com isso:

-b
+B
+C
-e
-f
+E
+F

O formato está documentado em man diff:

       --line-format=LFMT
              format all input lines with LFMT`

e:

       LTYPE is 'old', 'new', or 'unchanged'.
              GTYPE is LTYPE or 'changed'.

e:

              LFMT (only) may contain:

       %L     contents of line

       %l     contents of line, excluding any trailing newline

       [...]

Pergunta relacionada: https://stackoverflow.com/questions/15384818/how-to-get-the-difference-only-additions-between-two-files-in-linux

Testado no Ubuntu 18.04.

Ciro Santilli adicionou uma nova foto
fonte
-1

Arquivo1:

text670_1
text067_1
text067_2

Arquivo2:

text04_1
text04_2
text05_1
text05_2
text067_1
text067_2
text1000_1

Usar:

diff -y file1 file2

Isso mostra duas colunas para arquivos de perspectivas.

Resultado:

text670_1                           
                                  > text04_1
                                  > text04_2
                                  > text05_1
                                  > text05_2
text067_1                           text67_1
text067_2                           text67_2
                                  > text1000_1
Adriano
fonte