Il risultato di due file diff con linee commutate dice che manca la stessa linea due volte


28

Sto cercando di capire il comando diff di Linux su due file le cui linee sono solo una permutazione l'una dell'altra ma non sono in grado di grok l'output che genera. Considera i tre comandi seguenti:

[myPrompt]$ cat file1
apples
oranges
[myPrompt]$ cat file2 
oranges
apples
[myPrompt]$ diff file1 file2
1d0
< apples
2a2
> apples

Qualcuno può spiegare l'output criptico di cui sopra diff.

  1. Perché non si parla affatto di "arance" nell'output?
  2. Cosa significa 1d0e cosa 2a2significa?

Da questa risposta capisco che:

"<" indica che la linea è mancante in file2 e ">" indica che la linea è mancante in file1

MA ciò non spiega perché mancano le arance nell'output.


12
Perché orangesè la più grande parte comune tra i due file, quindi quello che ottieni è il modo più breve per esprimere le differenze tra i due file.
Stéphane Chazelas,

10
E se vuoi un output più leggibile, usa diff -u file1 file2invece. Si chiama formato "unified diff". Il formato diff originale era pensato per essere molto compatto, ma i diff unificati dovevano essere molto più leggibili.
godlygeek,

4
@godlygeek Oppurediff -y file1 file2
user80551

Risposte:


27

Per comprendere il rapporto, ricorda che diffè prescrittivo, descrivendo quali modifiche devono essere apportate al primo file ( file1) per renderlo uguale al secondo file ( file2).

In particolare, din 1d0significa eliminare e ain in 2a2significa aggiungere .

Così:

  • 1d0significa che la riga 1 deve essere eliminata tra file1( apples). 0nel 1d0mezzo la linea 0 è dove sarebbero apparsi nel secondo file ( file2) se non fossero stati cancellati. Ciò significa che quando si cambia file2in file1(indietro) aggiungere la riga 1 file1dopo la riga 0 di file2.
  • 2a2significa aggiungere la seconda riga ( oranges) file2dall'ora seconda riga di file1(dopo aver eliminato la prima riga file1, orangespassata alla riga 1)

cosa c'è 0dentro 1d0?
Geek,

@Geek vedi la mia modifica
caos

1
@Geek Ma attenzione, questo può fare dei nodi nel cervello =)
caos

che ha effettivamente iniziato a fare nodi :-)
Geek,

13

Considera questi file:

file1:

# cat file1
apples
pears
oranges
peaches

file2:

# cat file2
oranges
apples
peaches
ananas
banana

Come difffunziona, dato che si basa sull'ordine:

  1. difflegge il primo blocco di righe di file1e file2e cerca di trovare righe uguali:

      file1        file2        differences on left (<) or right side (>)
      apples                   <apples
      pears                    <pears 
      -------------------------------
    ->oranges    ->oranges
      peaches      apples
                   peaches
                   ananas
                   banana
    
  2. Ora salterà tutte le righe uguali in entrambi i file, che è proprio orangesin questo caso:

      file1        file2        differences on left (<) or right side (>)
      apples                   <apples
      pears                    <pears 
      oranges      oranges
      -------------------------------
    ->peaches    ->apples
                   peaches
                   ananas
                   banana
    
  3. Ora trova un altro set di linee simili e stampa le differenze:

      file1        file2        differences on left (<) or right side (>)
      apples                   <apples
      pears                    <pears 
      oranges      oranges
                   apples      >apples
      -------------------------------
    ->peaches    ->peaches
                   ananas
                   banana
    
  4. Salta le righe simili

      file1        file2        differences on left (<) or right side (>)
      apples                   <apples
      pears                    <pears 
      oranges      oranges
                   apples      >apples
      peaches      peaches
      -------------------------------
    ->           ->ananas
                   banana
    
  5. Trova linee identiche, se possibile, e stampa le differenze:

    line_file1    file1    line_file2    file2        differences on left (<) or right side (>)
             1    apples                              <apples 
             2    pears                               <pears 
             3    oranges           1    oranges
                                    2    apples       >apples
             4    peaches           3    peaches
                                    4    ananas       >ananas
                                    5    banana       >banana
             -----------------------------------------------
    

Ora se lo faccio diff file1 file2:

# diff file1 file2
1,2d0
< apples
< pears
3a2
> apples
4a4,5
> ananas
> banana

Ora è semplice spiegare cosa diffsignifica l'output:

Per rendere file1uguale a file2:

  • 1,2d0: Elimina ( d) le righe 1-2da file1e modifica la riga 0di file2conseguenza
  • 3a2: Aggiungi ( a) alla riga 3della file1riga 2difile2
  • 4a4,5: Aggiungi alla linea 4di file1linee 4-5difile2

diffconfronta file1con file2riga per riga e regola le differenze nella memoria temporanea. Dopo aver reso file1 uguale a file2 fino alla prima occorrenza di una riga in file1, che si verifica anche in file2, tutte le righe uguali fino a quando non viene menzionata una differenza, spesso indicate come ---. In questo caso c'è solo una linea simile, che è oranges. Si noti che ho detto file1uguale a file2, quindi file1è visto in relazione file2e non viceversa.

L'output è in relazione al primo file fornito, in questo caso file1.


2
Non mi piace la spiegazione iniziale: si applesverifica anche in entrambi i file.
OR Mapper

1
@ORMapper Ho cambiato la spiegazione. Suona più chiaro / migliore ora :)?
polimero

Non del tutto, per ora hai scritto "c'è solo una linea simile, che è oranges". Sbagliato: in realtà ci sono due linee, che non sono solo simili , ma assolutamente identiche . Uno legge oranges, l'altro legge apples. Inoltre, la tua spiegazione (basata esclusivamente sull'ordine) è in contraddizione con il commento di Stéphane sulla domanda (basata sulla lunghezza): chi ha ragione?
OR Mapper,

@ORMapper Hai dimenticato "In questo caso" e le righe precedenti. Volevo dire che in questo passaggio c'è solo una linea simile. Aggiungerò solo un esempio alla mia risposta in modo che possa essere compreso meglio.
polimero

1
@ORMapper Puoi anche darmi un esempio che dimostri che la risposta basata sulla lunghezza è corretta?
polimero

8

Sono là:

$ diff file1 file2
1d0
< apples
2a2
> apples
$ diff file2 file1
1d0
< oranges
2a2
> oranges

8

Il formato di output standard (precedente) visualizzerà la differenza tra i file senza testo circostante con aree in cui i file differiscono.

Ad esempio: 1d0 <(elimina) significa che le mele devono essere rimosse dalla prima riga di file1, e 2a2 >(append) indica il mele devono essere aggiunte nella file2seconda riga, quindi è possibile abbinare entrambi i file.

Documentazione disponibile all'indirizzo info diff spiega ulteriormente:

Mostrando differenze senza contesto

Il diffformato di output "normale" mostra ogni pezzo di differenze senza alcun contesto circostante. A volte tale output è il modo più chiaro per vedere come sono cambiate le linee, senza il disordine delle linee invariate vicine (anche se puoi ottenere risultati simili con il contesto o formati unificati usando 0 linee di contesto). Tuttavia, questo formato non è più ampiamente utilizzato per l'invio di patch; a tal fine, il formato di contesto e il formato unificato sono superiori. Il formato normale è l'impostazione predefinita per la compatibilità con le versioni precedenti didiff e lo standard POSIX. Utilizzare l' --normalopzione per selezionare esplicitamente questo formato di output.

Descrizione dettagliata del formato normale

Il normale formato di output è costituito da uno o più blocchi di differenze; ogni pezzo mostra un'area in cui i file differiscono. Gli hunk di formato normale si presentano così:

 CHANGE-COMMAND
 < FROM-FILE-LINE
 < FROM-FILE-LINE...
 ---
 > TO-FILE-LINE
 > TO-FILE-LINE...

Esistono tre tipi di comandi di modifica. Ciascuno è costituito da un numero di riga o da un intervallo di righe separate da virgola nel primo file, da un singolo carattere che indica il tipo di modifica da apportare e da un numero di riga o da un intervallo di righe separate da virgola nel secondo file. Tutti i numeri di riga sono i numeri di riga originali in ciascun file. I tipi di comandi di modifica sono:

LaR Aggiungi le righe nell'intervallo R del secondo file dopo la riga L del primo file. Ad esempio, 8a12,15significa aggiungere le righe 12-15 del file 2 dopo la riga 8 del file 1; oppure, se si modifica il file 2 nel file 1, eliminare le righe 12-15 del file 2.

FcT Sostituisci le righe nell'intervallo F del primo file con le righe nell'intervallo T del secondo file. Questo è come un combinato aggiungere ed eliminare, ma più compatto. Per esempio,5,7c8,10 significa cambiare le righe 5-7 del file 1 per leggerle come righe 8-10 del file 2; oppure, se si modifica il file 2 nel file 1, modificare le righe 8-10 del file 2 per leggerle come righe 5-7 del file 1.

RdL Elimina le righe nell'intervallo R dal primo file; la riga L è dove sarebbero apparsi nel secondo file se non fossero stati eliminati. Ad esempio, 5,7d3significa eliminare le righe 5-7 del file 1; oppure, se si modifica il file 2 nel file 1, aggiungere le righe 5-7 del file 1 dopo la riga 3 del file 2.

Guarda anche:


Quindi, per vedere le arance, dovresti differenziarle fianco a fianco o usando un contesto unificato.

Per esempio:

$ diff -y file1 file2
apples                                <
oranges                             oranges
                                  > apples

$ diff -u file1 file2
@@ -1,2 +1,2 @@
-apples
 oranges
+apples
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.