Linux-kommandot `patch` möjliggör en snabb och säker överföring av ändringar från en uppsättning filer till en annan. Den här guiden visar hur du använder `patch` på ett enkelt sätt.
`patch`- och `diff`-kommandon
Antag att du har en textfil på din dator och får en modifierad version av filen från någon annan. Hur överför du snabbt alla ändringar från den nya filen till din ursprungliga fil? Det är här `patch` och `diff` kommer in. Dessa verktyg är standard i Linux och andra Unix-liknande system, inklusive macOS.
Kommandot `diff` analyserar två versioner av samma fil och listar skillnaderna. Dessa skillnader kan sedan sparas i en så kallad patchfil.
Kommandot `patch` kan läsa en patchfil och använda den som en instruktionsuppsättning. Genom att följa dessa instruktioner återskapas ändringarna från den modifierade filen i originalfilen.
Tänk dig nu att detta sker med en hel mapp med textfiler, allt på en gång. Det är kraften i `patch`.
Ofta får du inte själva de ändrade filerna. Istället får du bara patchfilen. Varför skicka runt dussintals filer när du kan skicka en enda patchfil eller publicera den för enkel nedladdning?
Men hur använder du patchfilen för att faktiskt uppdatera dina filer? Det är en viktig fråga, och det ska vi gå igenom i denna artikel.
Kommandot `patch` används ofta av dem som arbetar med källkod för programvara, men det fungerar utmärkt med alla typer av textfiler.
Exempelscenario
Vi ska arbeta i en mapp som heter ”work”, som i sin tur innehåller två mappar: ”working” och ”latest”. ”working”-mappen innehåller en uppsättning källkodsfiler. ”latest”-mappen innehåller den senaste versionen av dessa filer, där vissa har blivit modifierade.
För säkerhets skull är ”working”-mappen en kopia av den nuvarande versionen av textfilerna. Det är alltså inte den enda kopian.
Hitta skillnader mellan två filversioner
Kommandot `diff` identifierar skillnaderna mellan två filer. Som standard listas de modifierade raderna i terminalfönstret.
En av filerna heter ”slang.c”. Vi ska jämföra versionen i ”working”-mappen med versionen i ”latest”-mappen.
Alternativet `-u` (unified) instruerar `diff` att även lista några av de omodifierade textraderna före och efter de ändrade avsnitten. Dessa rader kallas kontextrader. De underlättar för `patch`-kommandot att exakt hitta var en ändring ska göras i originalfilen.
Vi anger filernas namn så att `diff` vet vilka filer som ska jämföras. Originalfilen listas först, följt av den modifierade filen. Så här ser kommandot ut:
diff -u working/slang.c latest/slang.c
`diff` producerar en lista över skillnaderna mellan filerna. Om filerna vore identiska skulle det inte finnas någon utdata. Den här typen av utdata bekräftar att det finns skillnader mellan de två filversionerna och att originalfilen behöver uppdateras.
Skapa en patchfil
För att spara skillnaderna i en patchfil, använd följande kommando. Det är samma kommando som ovan, men med `diff`s utdata omdirigerad till en fil som heter ”slang.patch”.
diff -u working/slang.c latest/slang.c > slang.patch
För att använda patchfilen med `patch` och modifiera filen ”working/slang.c”, använd följande kommando. Alternativet `-u` (unified) indikerar för `patch` att patchfilen innehåller kontextrader i det enhetliga formatet. Det innebär att om vi använde `-u` med `diff` så måste vi också använda `-u` med `patch`.
patch -u working/slang.c -i slang.patch
Om allt går som det ska, kommer det ut en enda rad som talar om för dig att `patch` har uppdaterat filen.
Skapa en säkerhetskopia av originalfilen
Vi kan instruera `patch` att skapa en säkerhetskopia av de filer som ska uppdateras innan ändringarna görs. Detta görs med alternativet `-b` (backup). Alternativet `-i` (input) anger namnet på patchfilen som ska användas:
patch -u -b working/slang.c -i slang.patch
Filen uppdateras som tidigare, utan synbar skillnad i utdata. Men om du tittar i ”working”-mappen ser du att en fil med namnet ”slang.c.orig” har skapats. Filernas tidsstämplar visar att ”slang.c.orig” är originalfilen, och ”slang.c” är en ny fil som skapats av `patch`.
Använda `diff` med kataloger
Vi kan använda `diff` för att generera en patchfil som innehåller alla skillnader mellan filerna i två mappar. Sedan kan vi använda den patchfilen med `patch` för att applicera dessa skillnader på filerna i ”working”-mappen med ett enda kommando.
De alternativ som vi kommer att använda med `diff` är `-u` (unified context), som vi har använt tidigare, `-r` (rekursivt) för att få `diff` att titta i alla undermappar, och `-N` (ny fil).
Alternativet `-N` talar om för `diff` hur man hanterar filer i ”latest”-mappen som inte finns i ”working”-mappen. Det tvingar `diff` att lägga in instruktioner i patchfilen så att `patch` skapar filer som finns i ”latest”-mappen men saknas i ”working”-mappen.
Du kan kombinera alternativen så att de använder ett enda bindestreck (-).
Observera att vi bara anger mappnamnen, vi säger inte åt `diff` att titta på specifika filer:
diff -ruN working/ latest/ > slang.patch
Den övre delen av filen visar skillnaderna mellan de två versionerna av ”slang.c”.
Om vi scrollar längre ner i patchfilen ser vi att den beskriver ändringarna i en annan fil som heter ”structs.h”. Detta bekräftar att patchfilen innehåller skillnaderna mellan olika versioner av flera filer.
Kontrollera innan du kör
Att patcha en stor samling filer kan vara lite riskabelt, så vi kommer att använda alternativet `–dry-run` för att kontrollera att allt är i sin ordning innan vi utför ändringarna.
Alternativet `–dry-run` talar om för `patch` att göra allt förutom att faktiskt modifiera filerna. `patch` kommer att utföra alla sina kontroller och, om några problem uppstår, rapportera dem. Ingen fil kommer att ändras.
Om inga problem rapporteras kan vi upprepa kommandot utan `–dry-run` och med förtroende korrigera våra filer.
Alternativet `-d` (directory) talar om för `patch` vilken mapp den ska arbeta i.
Observera att vi inte använder alternativet `-i` (input) för att ange vilken patchfil som innehåller instruktionerna från `diff`. Istället omdirigerar vi patchfilen till `patch` med `<`.
patch --dry-run -ruN -d working < slang.patch
Av hela katalogen hittade `diff` två filer att patcha. Instruktionerna angående ändringarna för dessa två filer har kontrollerats av `patch`, och inga problem har rapporterats.
Kontrollerna före flygningen är OK; vi är redo för start.
Patcha en katalog
För att faktiskt applicera patcharna på filerna använder vi föregående kommando utan alternativet `–dry-run`.
patch -ruN -d working < slang.patch
Den här gången börjar inte varje utmatningsrad med ”checking”, utan med ”patching”.
Inga problem rapporteras. Vi kan kompilera vår källkod, och vi har den senaste versionen av programvaran.
Lös dina konflikter
Detta är det enklaste och säkraste sättet att använda `patch`. Kopiera dina målfiler till en mapp och patcha den mappen. Kopiera tillbaka dem när du är nöjd med att patchningsprocessen har slutförts utan fel.