Supponiamo che io abbia un file da 4 GB abc
sul mio computer locale. Lho caricato su un server distante tramite SFTP, ci sono volute alcune ore.
Ora ho leggermente modificato il file (probabilmente 50 MB al massimo, ma non byte consecutivi in questo file) localmente, e lho salvato in abc2
. Ho anche mantenuto il file originale abc
sul mio computer locale.
Come calcolare una differenza binaria di abc
e abc2
?
Applicazioni:
-
ho potuto inviare solo un file
patch
(probabilmente max 100 MB) a il server distante, invece di ricaricare lintero fileabc2
(ci vorrebbero ancora alcune ore!) e ricreareabc2
sul server remoto server solo daabc
epatch
. -
A livello locale, invece di sprecare 8 GB per il backup di
abc
eabc2
, ho potuto salvare soloabc
+patch
, quindi sono necessari < solo 4100 MB.
Come si fa?
PS: per il testo, so diff
, ma qui sto cercando qualcosa che potrebbe funzionare per qualsiasi formato binario grezzo, potrebbe essere file zip o eseguibili o anche altri tipi di file.
PS2: Se possibile, non voglio utilizzare rsync
; So che può replicare le modifiche tra 2 computer in modo efficiente (non rispedire i dati che non sono cambiati), ma qui voglio davvero avere un file patch
, che è riproducibile in seguito se Ho sia abc
e patch
.
Risposta
Per la seconda applicazione / problema, utilizzerei un programma di backup di deduplicazione come restic
o borgbackup
, invece di provare per tenere traccia manualmente di “patch” o diff. Il programma di backup restic
consente di eseguire il backup di directory da più macchine allo stesso repository di backup, deduplicando i dati di backup sia tra frammenti di file da una singola macchina che tra macchine. (Non ho esperienza utente con borgbackup
, quindi non posso “dire nulla su quel programma.)
Calcolo e memorizzazione di una differenza di abc
e abc2
possono essere eseguiti con rsync
.
Questo è un esempio con abc
e abc2
pari a 153 MB. Il file abc2
è stato modificato sovrascrivendo il primi 2,3 MB del file con alcuni altri dati:
$ ls -lh total 626208 -rw-r--r-- 1 kk wheel 153M Feb 3 16:55 abc -rw-r--r-- 1 kk wheel 153M Feb 3 17:02 abc2
Creiamo patch per trasformare abc
in abc2
e chiamarlo abc-diff
:
$ rsync --only-write-batch=abc-diff abc2 abc
$ ls -lh total 631026 -rw-r--r-- 1 kk wheel 153M Feb 3 16:55 abc -rw------- 1 kk wheel 2.3M Feb 3 17:03 abc-diff -rwx------ 1 kk wheel 38B Feb 3 17:03 abc-diff.sh -rw-r--r-- 1 kk wheel 153M Feb 3 17:02 abc2
Il file generato abc-diff
è il diff effettivo (il tuo “file patch”), mentre abc-diff.sh
èun breve script della shell che rsync
crea per te:
$ cat abc-diff.sh rsync --read-batch=abc-diff ${1:-abc}
Questo script modifica abc
in modo che diventi identico a abc2
, dato il file abc-diff
:
$ md5sum abc abc2 be00efe0a7a7d3b793e70e466cbc53c6 abc 3decbde2d3a87f3d954ccee9d60f249b abc2 $ sh abc-diff.sh $ md5sum abc abc2 3decbde2d3a87f3d954ccee9d60f249b abc 3decbde2d3a87f3d954ccee9d60f249b abc2
Il file ovunque tu abbia abc
. Con il comando rsync --read-batch=abc-diff abc
, applicheresti la patch al file abc
, trasformandone il contenuto in modo che corrisponda a abc2
sul sistema in cui hai creato il diff.
Riapplicare la patch una seconda volta sembra sicuro. Non ci sono messaggi di errore né il contenuto del file cambia (il checksum MD5 non cambia).
Nota che a meno che tu non crei una “patch inversa” esplicita, non cè modo di annullare facilmente lapplicazione della patch.
Ho anche provato a scrivere la modifica da 2,3 MB in qualche altro posto nei dati abc2
, un po più avanti (a circa 50 MB), così come allinizio. La “patch” generata era grande 4,6 MB, suggerendo che solo i bit modificati erano stati memorizzati nella patch.
Commenti
- Grazie mille @Kusalananda, ‘ è fantastico! PS:
rsync --read-batch=abc-diff ${1:-abc}
(script .sh generato automaticamente) ha fornitoremote destination is not allowed with --read-batch
rsync error: syntax or usage error (code 1) at main.c(1326) [Receiver=3.1.2]
, marsync --read-batch=abc-diff abc
ha funzionato correttamente.Qual è la differenza tra questi due comandi simili? - 2/2 Cè un modo per utilizzare
abc
come input, applicare la patchdiff-abc
con--read-batch
ma non modificareabc
” sul posto “, ma piuttosto output in un nuovo fileabc3
? (se possibile tutto conrsync
, senza piping, in modo che funzioni facilmente su Linux e Windows che ha anchersync.exe
disponibile) - @Basj I comandi farebbero cose diverse se
$1
avesse un valore.${1:-abc}
significa che ” utilizza il primo parametro posizionale ($1
) a meno che non ‘ è vuoto o non definito. Nel caso in cui ‘ sia vuoto o non definito, utilizzaabc
invece “. ‘ presumo che$1
avesse un valore quando lhai provato, forse qualcosa che ha interpretato come un indirizzo di destinazione remota. - @Basj I ‘ non sono del tutto sicuro che sia possibile, ma ‘ ll dai unocchiata domani dopo aver dormito.
- Grazie per la tua risposta su
${1:-abc}
. Probabilmente non è riuscito perché lho provato su Windows (io ‘ sto usando rsync sia su Linux per il mio server distante che su Windows localmente). Ma ‘ è perfetto poichérsync --read-batch=abc-diff abc
funziona 🙂
Risposta
Come calcolare una differenza binaria di abc e abc2?
Utilizzo di bsdiff / bspatch o xdelta e altri.
$ bsdiff older newer patch.bin # patch.bin is created [...] $ bspatch older newer patch.bin # newer is created
Tuttavia, questi ammonimenti dalle pagine man devono essere notati:
-
bsdiff
usa una memoria pari a 17 volte la dimensione di oldfile e richiede una dimensione del working set minima assoluta di 8 volte la dimensione del oldfile . -
bspatch
utilizza una memoria pari alla dimensione di oldfile più la dimensione di newfile , ma può tollerare un working set molto piccolo senza una drammatica perdita di prestazioni.
Commenti
Risposta
Hai provato a forzare diff
per trattare i file come testo:
diff -ua abc abc2
Come spiegato qui .
-
-u
restituisce NUM (predefinito 3) righe di contesto unificato -
-a
tratta tutti i file come testo
Questo dovrebbe farti ottenere una patch. Lo svantaggio di questo è che le “righe” potrebbero essere piuttosto lunghe e questo potrebbe gonfiare la patch.
Commenti
- Oops, sì, non ‘ in realtà voglio
n
. ‘ mi interessa sapere se funziona perché ‘ non so per quanto tempo ” lines ” lo saranno. - Grazie per il tuo commento! Ho creato due file da 256 MB molto simili
abc
eabc2
. Poi ho provatodiff -ua abc abc2 > patch
, poi ho copiatoabc
inabc3
e ho provato a recuperareabc2
grazie aabc3
epatch
:patch abc3 < patch
, ma non ha funzionato: alla fineabc3
era solo di 1 KB invece di 256 MB. Qualche idea? - Hmmm, non sono sicuro di cosa sia successo. Lho appena fatto sulla mia macchina e ha funzionato meglio di quanto mi aspettassi.Ho preso un file 382M che era numeri interi casuali scritti in binario in un file. Ho cambiato 3 byte in esso e ho fatto il diff e la patch e ha funzionato. I file risultanti erano md5sum uguali.
- Se un file di grandi dimensioni non ha byte
0x0a
, ovvero newline o pochissimi, sospetto che non lo farebbe ‘ t funziona così bene, sarebbe interessante testarlo. - Oh di sicuro. Puoi fare unipotesi plausibile su un binario con
wc -l
che cercherà le interruzioni di riga e nella mia esperienza viene eseguito molto rapidamente. Mi aspetterei che su un binario arbitrario funzionasse abbastanza bene. Ad esempio, sulla mia macchina ho trovato un 252 M mp4 con 1,2 milioni di ” linee ” e un 59 M.deb
che aveva circa 230 kB, quindi ” righe ” inferiore a 220 byte e 258 byte rispettivamente. Non ‘ non vedo perché questi file sarebbero così diversi dagli altri, ma potresti sicuramente essere sfortunato. In pratica sospetto che funzionerebbe abbastanza bene e in caso contrario ‘ è ancora un trucco divertente.
Risposta
Usa xdelta , è stato creato proprio per questo tipo di utilizzi. Basato su VCDIFF (RFC 3284) nelle ultime versioni.
Commenti
- Il collegamento non funziona (cè un altro URL?). Potresti anche aggiungere un esempio in poche righe per mostrare come: 1) calcolare il file diff
patch
e 2) ripristinareabc2
, dati soloabc
epatch
? - Scusa, URL corretto
- Grazie @vonbrand . Avresti un esempio del genere?
Risposta
Si integra con altre risposte in base ai miei test:
Con diff
ho creato due file da 256 MB molto simili abc
e abc2
. Quindi creiamo il file diff:
diff -ua abc abc2 > abc-abc2.diff
Ora proviamo a recuperare abc2
grazie al file abc
originale e abc-abc2.diff
:
cp abc abc3 patch abc3 < abc-abc2.diff
o
cp abc abc3 patch abc3 -i abc-abc2.diff
o
patch abc -i abc-abc2.diff -o abc3
Funziona su Linux. Ho provato anche su Windows (sono disponibili anche patch.exe e diff.exe), ma per un motivo sconosciuto non è riuscito: il file abc3
prodotto è di solo 1 KB invece di 256 MB (I ” aggiornerò questa risposta più avanti qui).
Con rsync
Come spiegato in dettaglio nella risposta accettata, funziona:
rsync --only-write-batch=abc-abc2-diff abc2 abc cp abc abc3 rsync --read-batch=abc-abc2-diff abc3
Con rdiff
Come descritto in questo answer , anche questa è una soluzione:
rdiff signature abc abc-signature rdiff delta abc-signature abc2 abc-abc2-delta rdiff patch abc abc-abc2-delta abc3
Testato anche su Windows con rdiff.exe da qui e funziona.
Commenti
- ‘ immagino che patch non riuscita su Windows perché stava leggendo il file di input in modalità ” text ” che segnala la fine del file quando incontra un CONTROL -Z (byte 0x18) nel file di input. Questa è una modalità legacy dai primi giorni del DOS, quando la directory non registrava la lunghezza di il file e quindi la lunghezza del file è stata calcolata in base al numero di settori da 512 byte. Se puoi dire a
patch
di aprire il file in modalità binaria, non dovrebbe ‘ avere questo errore.
bsdiff uses memory equal to 17 times the size of oldfile
quindi ‘ di solito non funziona con file da 4 GB (almeno sulla mia macchina con RAM da 8 GB).mydiff abc abc2 > patchfile
emypatch abc patchfile > abc3
) indipendentemente dalle dimensioni. Inoltre, se divido in blocchi da 128 MB, cosa succede se il primo 1 GB diabc
== lultimo (finale) 1 GB diabc2
? Quando ‘ confronteremoabc-first128mb
conabc2-first128mb
, non verrà trovata alcuna corrispondenza, quindi potrebbe non essere efficiente?