Terug naar hoofdinhoud

Linux commando: tar

29 augustus 2026

Vrijwel iedereen die Linux gebruikt heeft weleens tar -xzf iets.tar.gz getypt zonder zeker te weten wat die letters betekenen. Dat is een prima startpunt, en het is waar de meeste mensen blijven staan. Dat gat doet ertoe, want tar is het gereedschap dat een website inpakt voor een verhuizing, dat de software uitpakt die je downloadt, en dat de backup maakt die je ooit onder druk zult moeten terugzetten.

1. De basis

tar neemt veel bestanden en maakt er een enkel bestand van. Dat is de hele taak. Hij loopt een lijst paden af, en schrijft voor elk pad een klein blok metagegevens (de naam, de grootte, de permissies, het tijdstempel) gevolgd door de inhoud van het bestand, achter elkaar, in een enkele stroom.

1.1 De drie dingen die je met tar doet

Elk tar-commando dat je ooit zult draaien gebruikt een van deze drie modi, en nooit meer dan een tegelijk:

VlagKort voorDoet
-c create Maak een nieuw archief van bestanden op schijf
-t table of contents Toon wat erin zit, verander niets
-x extract Pak de inhoud uit naar schijf

Daar voeg je -f aan toe (kort voor file), dat het archief benoemt. Dat is de vlag die mensen vergeten, en paragraaf 4.2 laat zien wat er dan gebeurt.

$ tar -cf site.tar site/      # create site.tar from the directory site/
$ tar -tf site.tar            # list what is in it
$ tar -xf site.tar            # extract it here

Daarmee kun je al uit de voeten. Al het andere in dit artikel is of compressie, of controle over waar bestanden terechtkomen en hoe ze eruitzien als ze aankomen.

1.2 tar comprimeert niet

Dit verrast mensen, en het verklaart de dubbele extensie op elk bestand dat je ooit gedownload hebt. tar plakt alleen aan elkaar. Hij maakt het resultaat groter, niet kleiner, want hij zet metagegevens en opvulling om elk bestand heen.

$ echo hello > greeting.txt
$ ls -l greeting.txt
-rw-rw-r-- 1 peter peter 6 Aug 23 16:24 greeting.txt

$ tar -cf one.tar greeting.txt
$ ls -l one.tar
-rw-rw-r-- 1 peter peter 10240 Aug 23 16:24 one.tar

Een bestand van zes bytes werd een archief van tien kilobyte. Paragraaf 7.4 legt precies uit waarom dat getal 10240 is en niet iets verstandigers.

Compressie is een apart programma. Als je tar -czf site.tar.gz site/ schrijft, zegt de z tegen tar dat hij zijn uitvoer door gzip moet sturen voordat hij het bestand wegschrijft. Daarom bestaat de naam uit twee delen:

site.tar.gz    a tar archive, then compressed with gzip
site.tar.bz2   a tar archive, then compressed with bzip2
site.tar.xz    a tar archive, then compressed with xz
site.tgz       the same as .tar.gz, shortened for old filesystems

Het juiste mentale model: tar is inpakwerk, geen compressiegereedschap. Hij doet veel dingen in een doos. Of je die doos daarna kleiner maakt is een aparte beslissing, genomen door een apart programma.

Naar boven

2. Waar komt de naam vandaan?

tar is kort voor tape archive, bandarchief.

tar  =  Tape ARchive

Dat is geen voetnoot uit de geschiedenis. Het is het ene feit dat vrijwel elke ontwerpkeuze in het gereedschap verklaart, want een magneetband kun je alleen van begin tot eind lezen.

Omdat het voor band gebouwd isZie je dit vandaag
Een band is een stroom, geen bestandssysteem Er is geen index. Een bestand vinden betekent alles ervoor lezen.
Bandstations schrijven in blokken van vaste grootte Archieven worden opgevuld tot een veelvoud van 10240 bytes (paragraaf 7.4)
Je kunt het midden van een band niet herschrijven Je kunt aan een archief toevoegen, maar er nooit iets uit halen
Banden waren het backupmedium Permissies, eigendom en tijdstempels worden allemaal bewaard
De standaarduitvoer was het bandapparaat Zonder -f schrijft tar nog steeds naar standaarduitvoer

Niemand in dit publiek heeft een bandstation, en het formaat is nog steeds volledig om zo'n apparaat heen gebouwd. Dat is het weten waard, want het maakt van een lijst eigenaardigheden een reeks gevolgen.

De vlaggen zijn ook het onderwerp van de bekendste grap in Unix-documentatie: xkcd 1168, waarin iemand binnen zestig seconden uit het hoofd een tar-archief moet uitpakken of de wereld vergaat. Het is grappig omdat die letters werkelijk lastig te onthouden zijn, en de reden staat in hoofdstuk 3: ze dateren van voor de afspraken die ze logisch gemaakt zouden hebben.

Naar boven

3. Een korte geschiedenis

tar verscheen voor het eerst in Version 7 Unix in 1979, als vervanger van een eerder paar bandprogramma's genaamd tp en tap. Hij werd geschreven toen een "bestandsserver" een kamer met bandspoelen was, en het formaat dat hij introduceerde heeft elk stuk hardware overleefd waarvoor het ontworpen was.

Het belangrijke latere werk was standaardisatie. Het oorspronkelijke formaat had geen versiemarkering, dus verschillende leveranciers breidden het op onverenigbare manieren uit. POSIX heeft dat twee keer rechtgezet:

PeriodeMijlpaal
1979 Version 7 Unix levert tar, met headers van 512 bytes en octale getallen in ASCII
1988 POSIX.1-1988 definieert ustar: dezelfde indeling plus een magische tekenreeks en een veld voor het padvoorvoegsel
Jaren 90 GNU tar voegt eigen uitbreidingen toe voor lange namen, sparse bestanden en incrementele backups
2001 POSIX.1-2001 definieert pax: uitgebreide headers die de lengtebeperkingen definitief opheffen
Vandaag GNU tar op Linux, bsdtar (libarchive) op de BSD's en macOS, en ze lezen elkaars archieven

Je kunt je eigen versie vragen wat hij aanneemt als je hem niets vertelt:

$ tar --version
tar (GNU tar) 1.35

$ tar --show-defaults
--format=gnu -f- -b20 --quoting-style=escape --rmt-command=/usr/sbin/rmt --rsh-command=/usr/bin/rsh

Drie daarvan doen ertoe. --format=gnu is het archiefformaat dat hij schrijft. -f- betekent dat het standaardarchief standaarduitvoer is, de moderne afstammeling van het bandapparaat. -b20 is de blokfactor, en dat is de reden dat een bestand van zes bytes in paragraaf 1.2 een archief van tien kilobyte opleverde.

De laatste twee zijn de echte museumstukken: rmt is het protocol voor remote magnetic tape, en rsh is de remote shell die ssh dertig jaar geleden verving. GNU tar levert nog steeds de mogelijkheid om naar een bandstation op een andere machine te schrijven over een onversleuteld protocol uit de jaren 80, omdat niemand ooit een reden had om het eruit te halen.

Naar boven

4. Eenvoudige toepassingen

4.1 De drie commando's die je echt nodig hebt

Begin met een map die site heet. Deze drie commando's dekken het meeste dagelijks gebruik:

$ tar -czf site.tar.gz site/     # create, compressed with gzip
$ tar -tzf site.tar.gz           # list the contents
$ tar -xzf site.tar.gz           # extract into the current directory

Lees de letters als een zin en ze zijn niet langer willekeurig: create zipped file, table of the zipped file, extract the zipped file. De f komt altijd als laatste, omdat de archiefnaam erachter volgt.

GNU tar accepteert de vlaggen ook zonder streepje, en zo hebben de meeste mensen het geleerd. Daarom zien de vlaggen er in voorbeelden zo vreemd uit:

$ tar czf site.tar.gz site/     # identical to -czf, and much older syntax

Dit is een overblijfsel van het oorspronkelijke commando uit 1979, dat het begrip streepje niet kende. Beide vormen werken; gebruik degene die je makkelijker onthoudt.

4.2 Wat -f werkelijk doet

De vlag -f benoemt het archief. Laat hem weg en tar valt terug op zijn standaard uit 1979, en dat is standaarduitvoer, want daar zat het bandstation. Moderne GNU tar vangt de voor de hand liggende fout af:

$ tar cz site
tar: Refusing to write archive contents to terminal (missing -f option?)
tar: Error is not recoverable: exiting now

Die bescherming geldt alleen als de terminal de bestemming is. Leid het om en tar doet vrolijk wat je vroeg, wat af en toe precies is wat je wilt:

$ tar cz site > site.tar.gz     # works, and is exactly what -f does
$ tar cf - site | ssh backup-server 'cat > site.tar'

Het enkele streepje in -f - betekent "gebruik standaarduitvoer", en het is de basis van elke pipe in paragraaf 6.4.

Nog een foutmelding is het herkennen waard, want de formulering helpt de eerste keer niet:

$ tar cf
tar: Old option 'f' requires an argument.

Dat betekent dat je -f schreef en vergat te zeggen welk bestand.

4.3 Compressie toevoegen

Een letter kiest de compressor. tar comprimeert zelf niets; hij draait het externe programma en stuurt de stroom erdoorheen.

VlagLange vormProgrammaGebruikelijke extensie
-z --gzip gzip .tar.gz, .tgz
-j --bzip2 bzip2 .tar.bz2
-J --xz xz .tar.xz
- --zstd zstd .tar.zst

Let op dat -j en -J alleen in hoofdlettergebruik verschillen, en dat het verschillende compressors zijn. Dat is een echte bron van verwarring, en daarom zijn de lange vormen in scripts de moeite waard.

Je kunt tar het ook uit de bestandsnaam laten afleiden met -a (kort voor auto-compress):

$ tar caf backup.tar.xz site/    # picks xz because of the extension
$ tar caf backup.tar.zst site/   # picks zstd

$ file backup.tar.xz
backup.tar.xz: XZ compressed data, checksum CRC64

Voor uitpakken is dit allemaal niet nodig. Moderne GNU tar herkent de compressie aan het bestand zelf, dus tar xf kan met elk formaat hierboven overweg:

$ tar xf anything.tar.gz     # works
$ tar xf anything.tar.xz     # also works, no -J needed

De gewoonte om xzf te typen is onschuldig, maar hij is niet nodig, en hij laat je in de steek op de dag dat iemand je een .tar.bz2 geeft.

De losse letters geven je elke compressor op zijn standaardinstellingen en verder niets. Wil je een ander niveau, of een compressor waar tar geen letter voor heeft, dan neemt -I (lange vorm --use-compress-program) een compleet commando:

$ tar -I 'zstd -19' -cf archive.tar.zst dir/    # maximum zstd compression
$ tar -I 'gzip -1'  -cf archive.tar.gz  dir/    # fastest gzip, for a big local copy
$ tar -I pigz       -cf archive.tar.gz  dir/    # parallel gzip, if installed

De aanhalingstekens doen ertoe zodra het commando argumenten heeft. Dit is ook de eerlijke versie van wat -z altijd al deed: tar heeft altijd een ander programma gedraaid en de stroom erdoorheen gestuurd.

4.4 De lijst lezen

Voeg -v toe (kort voor verbose) aan -t en je krijgt een lijst die op ls -l lijkt, met een belangrijk verschil:

$ tar -tvzf site.tar.gz
drwxrwxr-x peter/peter       0 2026-08-23 16:20 site/
drwxrwxr-x peter/peter       0 2026-08-23 16:20 site/logs/
-rw-rw-r-- peter/peter       9 2026-08-23 16:20 site/logs/error.log
-rw-rw-r-- peter/peter      14 2026-08-23 16:20 site/index.php
hrw-rw-r-- peter/peter       0 2026-08-23 16:20 site/hardlink.php link to site/index.php
drwxrwxr-x peter/peter       0 2026-08-23 16:20 site/images/
-rw-rw-r-- peter/peter  200000 2026-08-23 16:20 site/images/data.txt

De eigenaarskolom is gebruiker/groep in plaats van twee losse kolommen, en die namen staan in het archief. Ze zijn wat de bestanden waren op de machine die het archief maakte, niet wat ze op de jouwe zullen worden. Paragraaf 6.1 gaat over wat er bij het uitpakken werkelijk gebeurt.

Kijk naar de vijfde regel. Het typeteken is h, de grootte is 0, en de regel zegt link to site/index.php. tar merkte dat twee namen naar hetzelfde bestand wezen en sloeg de inhoud maar een keer op. Dit is een van de redenen dat een tar-archief van een echt systeem vaak kleiner is dan je verwacht, en een van de redenen dat het een systeem getrouw terugzet.

Naar boven

5. Gemiddelde toepassingen

5.1 Een compressor kiezen

Advies over compressors wordt meestal zonder cijfers gegeven, dus hier zijn er een paar. Het testmateriaal bestaat uit 944 PHP-bestanden uit een echte Joomla-installatie, 5.836.800 bytes als kale .tar, gemeten op een machine:

VlagResultaatVerhoudingInpakkenUitpakken
geen 5.836.800 1,00x - -
-z gzip 848.628 6,88x 0,1s 0,02s
-j bzip2 603.118 9,68x 0,3s 0,09s
-J xz 589.636 9,90x 1,3s 0,03s
--zstd 854.309 6,83x 0,0s 0,01s

Uit die tabel komen drie conclusies, en ze gelden ver buiten dit ene testmateriaal.

xz wint op grootte en kost je eenmalig tijd. Hij deed er dertien keer langer over dan gzip en leverde een bestand op dat 30% kleiner is. Maar hij pakte bijna net zo snel uit als gzip. Dat is precies de juiste ruil voor iets dat je een keer schrijft en dat vaak gedownload wordt, en daarom zijn kernel- en distributiearchieven .tar.xz.

bzip2 is nergens meer het antwoord op. Hij wordt verslagen door xz op grootte en door alles op snelheid, ook bij het uitpakken, waar hij de traagste van de test was. Hij overleeft omdat oude documentatie hem aanraadt.

zstd is degene om te kennen. Hij evenaarde de grootte van gzip en was in beide richtingen het snelst. Voor een nachtelijke backup, waar inpaktijd echt is en de verhouding meegenomen, is hij meestal de betere standaard. Het addertje is beschikbaarheid: gzip staat op elke machine die ooit gebouwd is, en zstd niet.

Een simpele regel: gzip als iemand anders het moet kunnen openen, xz als je het gaat verspreiden, zstd als jij de enige afnemer bent en de taak volgens een schema draait.

5.2 Waar de bestanden terechtkomen

Standaard pakt tar uit in de huidige map, met de paden zoals ze in het archief staan. Twee opties veranderen dat, en allebei zijn ze het kennen waard voordat je ze nodig hebt.

-C (kort voor change directory) vertelt tar waar hij moet werken. Bij uitpakken betekent het "pak daar uit":

$ tar -xzf site.tar.gz -C /var/www/     # extract into /var/www, not here

Bij aanmaken betekent het "behandel deze map als de wortel van het archief", en zo voorkom je dat je een lang pad opslaat dat je niet wilt:

$ tar -czf fromdir.tar.gz -C site .
$ tar -tzf fromdir.tar.gz
./
./a.txt
./c.txt
./b.txt

--strip-components haalt voorste padonderdelen weg terwijl de bestanden eruit komen. Dit is het antwoord op de veelvoorkomende ergernis van een archief dat alles in een map met een versienummer verpakt die je niet wilt:

$ tar -tzf webapp-6.1.1.tar.gz | head -3
webapp-6.1.1/
webapp-6.1.1/index.php
webapp-6.1.1/administrator/

$ tar -xzf webapp-6.1.1.tar.gz -C /var/www/site --strip-components=1
$ ls /var/www/site
administrator  index.php

De bestanden komen nu rechtstreeks in /var/www/site terecht in plaats van in /var/www/site/webapp-6.1.1. Vrijwel elke broncoderelease is zo verpakt, dus bij het uitrollen van software bespaart deze ene optie je elke keer een verplaatsing.

5.3 Dingen weglaten

--exclude neemt een patroon in shell-stijl en mag herhaald worden:

$ tar -czf p.tgz --exclude='node_modules' --exclude='*.log' proj
$ tar -tzf p.tgz
proj/
proj/src/
proj/src/app.php
proj/.git/
proj/.git/config

Er is ook --exclude-vcs, dat .git, .svn en hun equivalenten laat vallen zonder dat je ze hoeft op te noemen:

$ tar -czf p2.tgz --exclude-vcs proj

Zodra de lijst meer dan twee of drie patronen telt, zet je hem beter in een bestand. Dat bestand hoort in versiebeheer naast het backupscript, waar de volgende persoon kan zien wat er bewust niet in de backup zit:

$ cat exclude.lst
cache
*.log
node_modules
.git

$ tar -czf site.tar.gz --exclude-from=exclude.lst site/

Nu de valkuil, en het is een goede. --exclude moet voor de paden staan. Deze opties zijn positioneel: ze werken alleen op argumenten die erna komen. Zet het patroon aan het eind, waar het natuurlijker leest, en het doet niets:

$ tar -czf p3.tgz proj --exclude='*.log'
tar: The following options were used after non-option arguments.  These
options are positional and affect only arguments that follow them.
Please, rearrange them properly.
tar: --exclude '*.log' has no effect
tar: Exiting with failure status due to previous errors

$ echo $?
2

Moderne GNU tar waarschuwt luid en stopt met een foutcode, en dat is een gunst. Het gevaar zit in een backupscript dat zijn uitvoer naar /dev/null stuurt: het archief wordt gewoon geschreven, het bevat stilletjes de bestanden die je wilde weglaten, en niemand komt erachter. Paragraaf 6.9 gaat precies over dit soort dingen opmerken.

5.4 Een bestand uit een archief halen

Je hoeft niet alles uit te pakken. Noem het lid precies zoals het in de lijst staat:

$ tar -tzf p.tgz                       # find the exact path first
$ tar -xzf p.tgz proj/src/app.php      # extract just that one
$ tar -xzf p.tgz -O proj/src/app.php   # print it to the screen instead

Voor patronen in plaats van exacte namen voeg je --wildcards toe:

$ tar -xzf p.tgz --wildcards 'proj/src/*.php'

De vorm met -O is in een noodgeval echt nuttig: je leest er een configuratiebestand mee uit de backup van gisternacht, zonder een gigabyte uit te pakken en zonder aan te raken wat er op schijf staat.

5.5 Absolute paden

Geef tar een absoluut pad en hij haalt de voorste schuine streep er stilletjes af:

$ tar -czf abs.tar.gz /var/www/site/index.php
tar: Removing leading `/' from member names
tar: Removing leading `/' from hard link targets

$ tar -tzf abs.tar.gz
var/www/site/index.php

Dit is een beveiliging, en een goede. Bleven de paden absoluut, dan zou het archief ergens uitpakken /var/www/site/index.php overschrijven op de machine die uitpakt, ongeacht in welke map jij stond. Door elk pad relatief te maken garandeert tar dat het uitpakken gebeurt waar jij bent.

Het praktische gevolg is dat je beter naar de juiste plek gaat, of -C gebruikt, dan dat je tegen de melding vecht:

$ tar -czf site.tar.gz -C /var/www site     # stores site/... not var/www/site/...
Naar boven

6. Gevorderde toepassingen

6.1 Permissies, eigendom en de umask

"Waarom veranderden de permissies toen ik dit uitpakte?" is een van de meest gestelde tar-vragen, en het antwoord is een regel die vrijwel niemand verteld wordt.

Als je uitpakt als gewone gebruiker, past tar je umask toe. Hier zijn twee bestanden, waarvan een bewust voor iedereen schrijfbaar is:

$ ls -l perm/
-rw-rw-rw- open.txt
-rw------- secret.txt

$ ( umask 077; tar xf perm.tar -C pout1 )
$ ls -l pout1/
-rw------- open.txt          <-- was 666, now 600
-rw------- secret.txt

Het archief bewaarde 666 getrouw. De umask haalde de bits voor groep en anderen er onderweg naar buiten af. Voeg -p toe (kort voor preserve permissions) en de vastgelegde modus wint:

$ ( umask 077; tar xpf perm.tar -C pout2 )
$ ls -l pout2/
-rw-rw-rw- open.txt          <-- preserved
-rw------- secret.txt

Het naslagwerk legt de andere helft van de regel vast: -p en --same-owner zijn de standaard voor de superuser. Hetzelfde commando levert dus een ander resultaat op afhankelijk van wie het draait, en precies daarom gedraagt een restore met sudo zich anders dan een restore in je eigen account.

Met eigendom werkt het net zo. Het archief bewaart namen en nummers:

$ tar -tvf perm.tar
-rw------- peter/peter  0 2026-08-23 16:24 ./secret.txt

$ tar -tvf perm.tar --numeric-owner
-rw------- 1000/1000    0 2026-08-23 16:24 ./secret.txt

Als gewone gebruiker kun je een bestand niet weggeven, dus alles wat je uitpakt is van jou, wat het archief ook zegt. Als root zet tar de vastgelegde eigenaar terug, en hij zoekt eerst op naam. Dat is meestal goed, en af en toe heel verkeerd: als www-data UID 33 is op de oude server en UID 82 op de nieuwe, dan is zoeken op naam precies wat je wilt. Bestaan de accounts helemaal niet op het doel, gebruik dan --numeric-owner zodat de nummers letterlijk teruggezet worden.

Een archief legt permissies en eigendom vast; het dwingt ze niet af. Wat je bij het uitpakken werkelijk krijgt hangt af van wie tar draait en wat zijn umask is.

Voor het verhuizen van een website tussen servers is dit het verschil tussen een werkende restore en een middag chown:

$ sudo tar -xzpf site.tar.gz -C /var/www --numeric-owner

Naast de klassieke Unix-bits is er een tweede laag metagegevens waar een volledige systeembackup van kan afhangen, en tar heeft voor elk onderdeel een schakelaar:

$ tar --help | grep -E 'acls|xattrs|selinux'
      --acls                 Enable the POSIX ACLs support
      --no-acls              Disable the POSIX ACLs support
      --no-selinux           Disable the SELinux context support
      --no-xattrs            Disable extended attributes support

Of deze standaard aan staan hangt af van hoe jouw tar gebouwd is en van het bestandssysteem eronder, en daarom noemt de helptekst zowel de in- als de uitschakelende vorm. Voor een gewone website die niets in uitgebreide attributen bewaart maakt het niets uit. Voor een systeembackup wel, en de enige manier om het te weten is archiveren, terugzetten in een testmap, en vergelijken. Neem hier niets aan.

Standaard bewaart tar een symbolische link als symbolische link. Hij legt vast waar de link naartoe wijst en verder niets, en dat is bijna altijd wat je wilt:

$ ls -l
current -> releases/2026-08

$ tar cf sym.tar current releases
$ tar tvf sym.tar
lrwxrwxrwx peter/peter  0 2026-08-23 16:32 current -> releases/2026-08
drwxrwxr-x peter/peter  0 2026-08-23 16:32 releases/
drwxrwxr-x peter/peter  0 2026-08-23 16:32 releases/2026-08/
-rw-rw-r-- peter/peter  8 2026-08-23 16:32 releases/2026-08/index.php

Dat is de standaardindeling bij uitrollen: een symlink current die naar een gedateerde releasemap wijst. Het archief houdt de opzet intact, en terugzetten geeft je dezelfde structuur terug.

-h (lange vorm --dereference) verandert dit. tar volgt elke link en archiveert wat er aan de andere kant staat:

$ tar chf symh.tar current releases
$ tar tvf symh.tar
drwxrwxr-x peter/peter  0 2026-08-23 16:32 current/
-rw-rw-r-- peter/peter  8 2026-08-23 16:32 current/index.php
drwxrwxr-x peter/peter  0 2026-08-23 16:32 releases/
drwxrwxr-x peter/peter  0 2026-08-23 16:32 releases/2026-08/
hrw-rw-r-- peter/peter  0 2026-08-23 16:32 releases/2026-08/index.php link to current/index.php

current is nu een echte map met een echte kopie. In dit kleine voorbeeld was tar slim genoeg om de verdubbeling op te merken en de tweede kopie als harde link op te slaan, maar dat werkt alleen omdat beide uiteinden in hetzelfde archief zaten.

Het gevaar zit in het geval waarin dat niet zo is. Een symlink die buiten de map wijst die je archiveert wordt een volledige kopie van waar hij naar wijst:

$ ls -l /var/www/site/uploads
uploads -> /mnt/storage/media        # 40 GB of images on another volume

$ tar chzf site.tar.gz /var/www/site  # -h: now archiving 40 GB, not 200 MB

Dit is een echt veelvoorkomende manier waarop een backup 's nachts groeit zonder zichtbare reden. Gebruik -h bewust, wanneer het archief op zichzelf moet staan en de lezer de linkdoelen niet heeft, en laat hem er de rest van de tijd af.

6.3 Sparse bestanden

Een sparse bestand heeft een grote logische omvang maar gebruikt niet zoveel schijf, omdat het bestandssysteem de lege gebieden als gaten vastlegt in plaats van nullen op te slaan. Schijfimages van virtuele machines en sommige databasebestanden zijn de gebruikelijke voorbeelden:

$ truncate -s 100M sparse.img
$ du -h --apparent-size sparse.img
100M
$ du -h sparse.img
0

Honderd megabyte aan bestand, nul bytes op schijf. tar weet niets van de gaten tenzij je het hem vertelt, en het verschil is niet subtiel:

$ tar cf plain.tar sparse.img
$ ls -l plain.tar
104867840

$ tar cSf sparse.tar sparse.img       # -S, --sparse
$ ls -l sparse.tar
10240

Zonder -S leest tar de gaten als de nullen die het bestandssysteem meldt en schrijft hij ze allemaal in het archief: 104 megabyte. Met -S legt hij de gaten als gaten vast en is het archief tien kilobyte, een factor tienduizend.

Het kost dat -S tar elk bestand op gaten laat onderzoeken, en dat is verspilde moeite op een map met gewone webbestanden. Zet hem aan als het archief schijfimages of databasebestanden bevat, en laat hem er anders af. Compressie verbergt een deel hiervan (een reeks nullen comprimeert goed) maar niet de tijd die het lezen en schrijven ervan kost.

6.4 tar als pipe

Omdat tar stromen leest en schrijft, laat hij zich combineren. -f - betekent standaardinvoer of -uitvoer, en die ene afspraak geeft je drie echt nuttige commando's.

Kopieer een mappenboom en behoud alles:

$ tar cf - source/ | tar xf - -C /destination

Twee keer tar, een pipe, geen tijdelijk bestand. Anders dan cp -r behoudt dit harde links, sparse bestanden en permissies precies, omdat beide uiteinden hetzelfde formaat spreken.

Verplaats een boom naar een andere machine, zonder hem ergens op te slaan:

$ tar czf - /var/www/site | ssh user@newserver 'tar xzf - -C /var/www'

Dit is het goed begrijpen waard, want het lost een echt probleem op: je hebt aan geen van beide kanten schijfruimte nodig voor een tussenliggend archief. De compressie gebeurt op de verzendende machine, dus het bespaart ook bandbreedte. Voor een eenmalige verhuizing van een website is het vaak sneller en eenvoudiger dan rsync, dat pas het betere gereedschap is als je de overdracht gaat herhalen.

Kijk in een archief zonder het uit te pakken:

$ tar xzf backup.tar.gz -O var/www/site/configuration.php | grep password

Alle drie volgen uit dezelfde beslissing uit 1979 dat de standaarduitvoer een apparaat is en geen bestand.

6.5 Formaten, en de muur van 100 tekens

De oorspronkelijke header uit 1979 reserveerde precies 100 bytes voor de bestandsnaam. Dat was royaal voor een systeem met korte paden, en het werd een probleem zodra mappen dieper werden. Er bestaan nu drie formaten, en GNU tar schrijft standaard het derde:

FormaatNaamlengteGebruik het als
ustar 100 tekens, of 256 als hij op een / gesplitst kan worden Maximale overdraagbaarheid naar oeroude systemen
gnu Geen praktische grens De standaard; prima overal waar Linux bij betrokken is
pax Geen grens, plus tijdstempels onder de seconde en uitgebreide attributen De POSIX-standaard; de veiligste keuze voor de lange termijn

De grens is niet theoretisch. Een bestandsnaam van 124 tekens wordt door ustar ronduit geweigerd:

$ tar cf u.tar --format=ustar aaaa...124-characters...txt
tar: aaaa...: file name is too long (cannot be split); not dumped
tar: Exiting with failure status due to previous errors
$ echo $?
2

$ tar cf g.tar aaaa...124-characters...txt     # gnu, the default
$ echo $?
0

In de praktijk zul je nooit ustar kiezen. De keuze die de moeite waard is, is pax voor alles wat je jaren wilt bewaren, want dat is de echte standaard en het bewaart tijdstempels op volledige precisie in plaats van afgerond op de seconde.

$ tar --format=pax -czf archive.tar.gz site/

6.6 Toevoegen, en waarom nooit aan een .tar.gz

Omdat een archief een stroom met een eindmarkering is, kun je eraan toevoegen door die markering te overschrijven. -r (kort voor append) doet dat:

$ tar cf plain.tar site/index.php
$ tar rf plain.tar site/logs/error.log
$ tar tf plain.tar
site/index.php
site/logs/error.log

-u (kort voor update) doet hetzelfde maar voegt alleen bestanden toe die nieuwer zijn dan de kopie die al in het archief zit. Geen van beide haalt iets weg: een "bijgewerkt" bestand wordt toegevoegd, en de oude versie blijft staan. Herhaald bijwerken maakt een archief dat eeuwig groeit en meerdere versies van hetzelfde pad bevat, waarbij tar de laatste uitpakt die hij tegenkomt.

Op een gecomprimeerd archief werkt hier niets van:

$ tar rf site.tar.gz site/logs
tar: Cannot update compressed archives
tar: Error is not recoverable: exiting now
$ echo $?
2

De reden is structureel. gzip levert een doorlopende stroom op, dus er is geen manier om de eindmarkering te vinden zonder alles uit te pakken, en geen manier om er voorbij te schrijven zonder opnieuw te comprimeren. Moet je aan een gecomprimeerd archief toevoegen, dan pak je uit, voegt toe, en comprimeert opnieuw. In de praktijk maak je een nieuw archief.

Verwijderen kan ook niet. tar kan nooit een lid uit een archief halen, op band noch op schijf, om dezelfde reden.

6.7 Incrementele backups

GNU tar kan een volledige backup maken en daarna alleen archiveren wat veranderd is. De toestand staat in een snapshotbestand dat je met -g meegeeft:

$ tar czf full.tgz -g snapshot.snar data
$ tar tzf full.tgz
data/
data/one.txt

$ touch data/two.txt

$ tar czf incr.tgz -g snapshot.snar data
$ tar tzf incr.tgz
data/
data/two.txt

Het tweede archief bevat alleen het nieuwe bestand. Het snapshotbestand is wat het laat werken, en het is ook de zwakke plek: raak je het kwijt, dan heeft tar geen idee meer wat hij al geback-upt heeft, dus de volgende run wordt stilletjes weer een volledige backup. Bewaar het naast de archieven.

Terugzetten betekent het volledige archief uitpakken en daarna elke aanvulling op volgorde, en dat is precies zo kwetsbaar als het klinkt. Incrementele tar is het kennen waard; voor iets belangrijks doet gereedschap dat zijn eigen geschiedenis bijhoudt, zoals restic of borg, minder pijn.

6.8 Reproduceerbare archieven

Pak dezelfde bestanden twee keer in en je krijgt twee verschillende archieven. Aan de inhoud veranderde niets; aan de metagegevens wel:

$ tar cf r1.tar d ; touch d/a.txt ; tar cf r2.tar d
$ sha256sum r1.tar r2.tar
4871b10e9a0df295ddd3da758d774ca9527b2381cb16ced15149230f9d0fe40f  r1.tar
c3e4021cbbf022087435c0c98e52fc37adebcbb1ca17537c0d714af92e404c25  r2.tar

Tijdstempels, eigendom en de volgorde waarin het bestandssysteem de mapregels teruggaf komen allemaal in het archief terecht. Zet ze allemaal vast en het resultaat wordt deterministisch:

$ tar --sort=name --mtime='UTC 2026-01-01' --owner=0 --group=0 --numeric-owner -cf p1.tar d
$ touch d/a.txt d/b.txt
$ tar --sort=name --mtime='UTC 2026-01-01' --owner=0 --group=0 --numeric-owner -cf p2.tar d
$ cmp p1.tar p2.tar && echo IDENTICAL
IDENTICAL

De tijdstempels zijn tussen de twee runs bewust veranderd en de archieven zijn nog steeds byte voor byte gelijk. Dat maakt van "is er sinds de vorige release eigenlijk iets veranderd?" een vergelijking van controlegetallen in plaats van een discussie.

Twee details over --mtime. Schrijf UTC voor de datum, anders volgt het stempel de tijdzone van de machine die het archief bouwde en zijn twee identieke builds in verschillende landen het oneens. En houd de aanhalingstekens: omdat de waarde een spatie bevat, splitst de shell deze vlaggen als je ze in een variabele zonder aanhalingstekens zet, en meldt tar 2026-01-01: Cannot stat: No such file or directory. Moet het in een variabele, gebruik dan --mtime=@0, want daar zit geen spatie in.

Nog een detail is het weten waard, want het is het omgekeerde van wat mensen verwachten: tar czf is reproduceerbaar, maar tar cf gevolgd door gzip niet. gzip legt de oorspronkelijke bestandsnaam en wijzigingstijd in zijn header vast, en als hij uit een pipe leest is er geen van beide om vast te leggen:

$ hexdump -C reproducible.tar.gz | head -1
1f 8b 08 00 00 00 00 00  00 03 ...        <-- flags 00, timestamp all zeros

$ gzip -k plain.tar ; hexdump -C plain.tar.gz | head -1
1f 8b 08 08 a3 07 8b 6a  00 03 74 2e 74 61 72 00   |.......j..t.tar.|
                                                    <-- flag 08, a timestamp,
                                                        and the filename

Een bestand op schijf comprimeren bewaart de naam en de tijd; een stroom comprimeren kan dat niet. Bouw je het archief toch in twee stappen, gebruik dan gzip -n om beide weg te laten.

6.9 Controleren of het archief goed is

tar heeft drie afsluitcodes, en het is de moeite waard om er in een script op te testen:

CodeBetekent
0 Alles werkte
1 Sommige bestanden verschillen (alleen van -d, of een bestand veranderde tijdens het lezen)
2 Een fatale fout. Het archief bestaat mogelijk wel en is onvolledig.

-d (kort voor diff, ook --compare) controleert een archief tegen het bestandssysteem:

$ tar df cmp.tar
site/index.php: Mod time differs
site/index.php: Size differs
$ echo $?
1

Direct na het maken van een archief gedraaid bewijst dit dat het archief overeenkomt met wat er op schijf staat. Het vervangt geen echte restoretest, maar het kost een commando.

--totals toont wat er geschreven is, en dat is een goedkope controle in een backupscript:

$ tar cf /dev/null --totals site
Total bytes written: 10240 (10KiB, 89MiB/s)

De waarde van dat getal is niet het getal zelf maar de stabiliteit ervan. Een nachtelijke backup die maandenlang ongeveer evenveel schrijft en ineens een tiende daarvan schrijft, vertelt je iets, en het is de enige waarschuwing die je gaat krijgen.

Geen van beide vertelt je of het archief een maand later nog intact is op de schijf waar je het naartoe kopieerde. Schrijf daarvoor een controlegetal ernaast op het moment dat je het maakt:

$ sha256sum backup.tar.gz > backup.tar.gz.sha256

# before you rely on it, wherever it has ended up
$ sha256sum -c backup.tar.gz.sha256
backup.tar.gz: OK

Een controlegetal beantwoordt precies een enkele vraag: zijn dit dezelfde bytes die geschreven zijn? Het zegt niets over de vraag of de juiste bestanden erin zijn gegaan. De drie controles stapelen, de goedkoopste eerst: tar tf archief > /dev/null bewijst dat de structuur leesbaar is, het controlegetal bewijst dat de bytes het overleefd hebben, en echt uitpakken in een testmap bewijst dat de backup een backup is. Alleen de laatste is bewijs.

Naar boven

7. Iets wat de meeste gebruikers niet weten

7.1 In de header van 512 bytes

Een tar-archief is eenvoudig genoeg om met het blote oog te lezen, en dat een keer doen maakt al het andere aan het formaat vanzelfsprekend. Hier zijn de eerste 512 bytes van een archief met een bestand genaamd greeting.txt dat het woord "hello" bevat:

$ tar cf one.tar greeting.txt
$ head -c 512 one.tar | hexdump -C
00000000  67 72 65 65 74 69 6e 67  2e 74 78 74 00 00 00 00  |greeting.txt....|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000060  00 00 00 00 30 30 30 30  36 36 34 00 30 30 30 31  |....0000664.0001|
00000070  37 35 30 00 30 30 30 31  37 35 30 00 30 30 30 30  |750.0001750.0000|
00000080  30 30 30 30 30 30 36 00  31 35 32 34 32 36 30 31  |0000006.15242601|
00000090  32 35 33 00 30 31 32 32  34 37 00 20 30 00 00 00  |253.012247. 0...|
00000100  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000100  00 75 73 74 61 72 20 20  00 70 65 74 65 72 00 00  |.ustar  .peter..|

Elk veld staat op een vaste positie, en elk getal is geschreven als octale cijfers in ASCII:

PositieVeldWaarde hierbovenBetekenis
0 naam (100 bytes) greeting.txt Opgevuld met nullen. Dit is de muur van 100 tekens uit 6.5.
100 modus 0000664 Permissies, octaal
108 uid 0001750 Octaal 1750 = 1000
124 grootte 00000000006 Zes bytes, octaal
136 mtime 15242601253 Octaal voor 1787495083, een Unix-tijdstempel
148 controlegetal 012247 De som van de bytes in de header
156 typevlag 0 Gewoon bestand. 5 is een map, 1 een harde link, 2 een symlink.
257 magic ustar De markering die POSIX in 1988 toevoegde
265 uname peter De naam van de eigenaar, en daarom kan 6.1 op naam zoeken

Waarom octale ASCII in plaats van binaire getallen? Omdat er in 1979 geen overeenstemming was over bytevolgorde of getalgrootte tussen machines, en een reeks cijfers overal hetzelfde betekent. Het is verkwistend en het is de reden dat een tar-archief dat op een PDP-11 geschreven is vandaag nog leesbaar is.

De inhoud van het bestand begint op positie 512, opgevuld tot de volgende grens van 512 bytes:

$ dd if=one.tar bs=512 skip=1 count=1 | head -c 20 | cat -A
hello$
^@^@^@^@^@^@^@^@^@^@^@^@^@^@

En het archief eindigt met twee volle blokken nullen. Die eindmarkering is wat -r overschrijft bij het toevoegen, en de afwezigheid ervan maakt een afgekapt archief herkenbaar.

7.2 Waarom .tar.gz wint op grootte en verliest op de rest

Dit is het nuttigste stuk van dit artikel voor iedereen die met websites werkt, want Linux geeft je .tar.gz en webapplicaties geven je .zip, en het verschil is niet cosmetisch.

Een zip-bestand comprimeert elk bestand apart en houdt aan het eind een index bij. Een .tar.gz plakt eerst alles aan elkaar en comprimeert de hele stroom als een geheel. Dat heet een solide archief, en het heeft een voordeel en een serieus nadeel.

Hier is dezelfde echte website van 125 MB op beide manieren ingepakt:

Handeling.tar.gz.zipVerschil
Grootte van het archief 27 MB 34 MB tar.gz is 21% kleiner
Alle regels tonen 0,397s 0,033s zip is 12x sneller
Een bestand achteraan eruit halen 0,393s 0,003s zip is 130x sneller

De winst op grootte komt doordat er over bestandsgrenzen heen gecomprimeerd wordt: duizend PHP-bestanden delen heel veel tekst, en gzip kan dat alleen benutten als hij ze als een stroom ziet.

De prijs is dat er geen index en geen willekeurige toegang is. Om een .tar.gz te tonen moet tar het hele bestand uitpakken. Om het laatste lid eruit te halen moet hij het hele bestand uitpakken. De tijd is in beide gevallen gelijk, en de cijfers hierboven laten dat duidelijk zien: 0,397s om alles te tonen, 0,393s om een klein bestand eruit te halen. Het werk is hetzelfde, want het werk is "27 MB uitpakken".

Een .tar.gz heeft geen inhoudsopgave. Elke vraag die je hem stelt wordt beantwoord door het geheel uit te pakken, en daarom kosten een archief tonen en er een klein bestand uit halen evenveel tijd.

Dat heeft directe gevolgen:

  • Voor een backup die je in zijn geheel terugzet is .tar.gz de betere keuze: kleiner, en je ging hem toch helemaal lezen.
  • Voor een installatie- of extensiepakket dat software moet onderzoeken, tonen of deels uitpakken is .zip de betere keuze. Daarom gebruiken Joomla, WordPress en browserextensies allemaal zip, en dat is geen toeval of een Windows-gewoonte.
  • Een kale .tar zonder compressie ondersteunt wel doorspoelen, en daarom bewaren sommige tools een ongecomprimeerde tar in een andere verpakking.

7.3 De tarbom

Een archief hoeft geen map op het hoogste niveau te bevatten. Bevat het die niet, dan strooit uitpakken de bestanden uit over de map waar je toevallig staat. Dat heet een tarbom, en zoiets met de hand opruimen is ellendig omdat je niet kunt zien welke bestanden er al stonden.

$ ls land/
existing.txt

$ tar xzf ../bomb.tar.gz
$ ls land/
a.txt  b.txt  c.txt  existing.txt

Twee gewoontes voorkomen dit voorgoed. De eerste is kijken voordat je uitpakt, en dat kost een seconde:

$ tar tzf bomb.tar.gz
a.txt
b.txt
c.txt

Geen gemeenschappelijk voorvoegsel op die regels betekent dat het archief in de huidige map uitpakt. De tweede gewoonte is tar de map voor je laten maken:

$ tar xzf bomb.tar.gz --one-top-level
$ ls -F
bomb/

--one-top-level maakt een map die naar het archief genoemd is, zonder de extensies, en zet alles daarin. Onvoorwaardelijk gebruiken is ongevaarlijk, want een archief dat al een enkele map op het hoogste niveau heeft, houdt die.

7.4 Waarom een bestand van zes bytes een archief van 10 KB maakt

Paragraaf 1.2 liet een getal onverklaard. Het antwoord staat in --show-defaults: -b20.

tar schrijft in records van 512 bytes, en groepeert die in blokken van 20 records voordat hij schrijft, want zo werkten bandstations. 20 keer 512 is 10240, en elk archief wordt opgevuld tot een veelvoud van dat getal.

$ tar cf one.tar greeting.txt      ; ls -l one.tar     # 10240
$ tar cf b1.tar -b1 greeting.txt   ; ls -l b1.tar      # 2048

Met -b1 is hetzelfde archief 2048 bytes: een header van 512 bytes, een datarecord van 512 bytes, en 1024 bytes eindmarkering. De opvulling is echt, en het is de reden dat een map met duizenden kleine bestanden een verrassend grote .tar oplevert.

Hij verdwijnt ook volledig zodra je comprimeert, want een lange reeks nullen is het makkelijkste ter wereld voor gzip om klein te maken. Er is geen reden om de blokfactor op een modern systeem bij te stellen; er is een goede reden om te begrijpen waarom het getal 10240 is als je het tegenkomt.

7.5 Een archief uitpakken dat je niet vertrouwt

Uitpakken schrijft naar je bestandssysteem, dus een archief van een vreemde verdient hetzelfde wantrouwen als elke andere onvertrouwde invoer. Het gebruikelijke advies noemt drie gevaren: paden met .. erin, absolute paden, en symlinks die schrijfacties buiten de doelmap omleiden. Het is het weten waard dat op moderne GNU tar alle drie al geblokkeerd zijn.

Relatieve ontsnappingen worden weggehaald bij het maken van het archief:

$ tar cf trav.tar ../../evil/sub/evil.txt
tar: Removing leading `../../' from member names

Absolute paden worden twee keer weggehaald, een keer bij het maken en opnieuw bij het uitpakken, dus zelfs een archief dat gebouwd is om ze te bevatten komt relatief terecht ten opzichte van waar jij staat:

$ tar tf abs.tar          # this archive really does contain an absolute path
/etc/hostname

$ cd /tmp/sandbox && tar xf abs.tar
tar: Removing leading `/' from member names
$ find .
./etc/hostname            <-- inside the sandbox, not the real /etc

De omleiding via een symlink wordt geweigerd. Dit is de interessante. De aanval is een archief met een symlink die naar buiten wijst, gevolgd door een lid dat daardoorheen geschreven wordt. tar maakt de link aan en weigert hem daarna te volgen:

$ tar tvf attack.tar
lrwxrwxrwx  0  link -> /tmp/scratch/OUTSIDE
-rw-rw-r-- 24  link/payload

$ tar xf attack.tar
tar: link/payload: Cannot open: Not a directory
tar: Exiting with failure status due to previous errors

$ ls /tmp/scratch/OUTSIDE
                          <-- empty. Nothing escaped.

De angstaanjagende versie van deze waarschuwing is dus achterhaald. Wat overblijft is kleiner maar echt, en de twee gewoontes hieronder waard:

  • Overschrijven wordt niet voorkomen. Niets houdt een archief tegen om bestanden te vervangen die al in de map staan waarin je uitpakt. Dat is de tarbom van paragraaf 7.3, en het blijft de waarschijnlijkste manier om werk kwijt te raken.
  • Uitpakbommen worden niet voorkomen. Een paar kilobyte .tar.gz kan uitdijen tot een volle schijf. tar tvf toont je de vastgelegde groottes voordat je je aan het uitpakken vastlegt.
  • -P zet de bescherming uit. --absolute-names zegt tegen tar dat hij voorste schuine strepen moet houden, zowel bij maken als bij uitpakken. Er is geen reden om dat te gebruiken op een archief dat je niet zelf gemaakt hebt.
  • Uitpakken als root haalt het vangnet weg dat gewone bestandsrechten boden, en zet -p en --same-owner standaard aan.

De praktijk die dat allemaal afdekt kost drie commando's:

$ tar tvf unknown.tar.gz | less     # look first: paths, sizes, anything odd
$ mkdir unpack && cd unpack         # a new, empty directory
$ tar xf ../unknown.tar.gz          # as yourself, never as root

7.6 Weten waar tar ophoudt

Een deel van vakmanschap is weten wanneer een gereedschap het verkeerde is.

NodigGebruikWaarom
Een overdracht efficiënt herhalen rsync tar stuurt altijd alles; rsync stuurt verschillen
Backups met geschiedenis en deduplicatie restic, borg tar heeft geen index, geen deduplicatie, en kwetsbare aanvullingen
Een archief dat andere software moet openen zip Willekeurige toegang, en het is wat webapplicaties verwachten
Een bestand uit een archief verwijderen Opnieuw maken tar kan geen leden verwijderen, en dat is met opzet
Een consistente kopie van een draaiende database mysqldump en soortgenoten tar kopieert bestanden die onder hem veranderen

Die laatste rij verdient nadruk, want het is de duurste fout in de lijst. tar over een map draaien waarin geschreven wordt levert een archief op van een moment dat nooit bestaan heeft, en tar zegt het je alleen als hij het toevallig merkt, met een waarschuwing die met code 1 eindigt en meestal weggegooid wordt. De bestanden van een website zijn meestal veilig genoeg; de database niet.

Naar boven

8. Best practices

  • Toon voordat je uitpakt. tar tzf archief.tar.gz | head kost een seconde en vertelt je of het archief een map op het hoogste niveau heeft, waar de bestanden terechtkomen, en of het is wat je denkt.
  • Of gebruik gewoon --one-top-level. Onvoorwaardelijk. Het is ongevaarlijk bij nette archieven en het maakt tarbommen onmogelijk.
  • Zet --exclude voor de paden. Deze opties zijn positioneel. Moderne tar waarschuwt en stopt met code 2, maar alleen als iemand de uitvoer leest.
  • Gebruik -C in plaats van cd. Het werkt bij zowel maken als uitpakken, het is expliciet, en het voorkomt dat een backupscript afhangt van de map waarin het gestart werd.
  • Vecht niet tegen de melding over de voorste schuine streep. Absolute paden worden voor je veiligheid weggehaald. Maak het archief met -C /var/www site in plaats van het volledige pad te noemen.
  • Zet terug als root met -p en denk aan --numeric-owner. Permissies en eigendom overleven alleen als degene die uitpakt het recht heeft ze te zetten, en accountnummers komen tussen servers zelden overeen.
  • Weet wat -h gaat meenemen. Symlinks worden standaard als links bewaard, en dat is vrijwel altijd goed. -h volgt ze, en een enkele link naar een ander volume kan de omvang van een backup vermenigvuldigen.
  • Voeg -S toe als het archief schijfimages of databasebestanden bevat. Zonder die vlag wordt een sparse bestand van 100 MB 100 MB aan nullen in het archief in plaats van tien kilobyte.
  • Zet de metagegevens vast voor alles wat je uitbrengt. --sort=name --mtime='UTC ...' --owner=0 --group=0 --numeric-owner maakt het archief byte voor byte gelijk tussen builds, zodat een controlegetal de vraag "is er iets veranderd?" beantwoordt.
  • Schrijf een controlegetal naast het archief als je het maakt. sha256sum backup.tar.gz > backup.tar.gz.sha256 is de enige manier om later te weten dat de bytes de kopieerslag overleefd hebben.
  • Pak alles wat je niet zelf maakte uit in een nieuwe lege map, als jezelf. Moderne tar blokkeert de ontsnappingstrucs met paden, maar niets houdt een archief tegen om te overschrijven wat er al in de map staat die jij koos.
  • Voeg nooit toe aan een gecomprimeerd archief. Het kan niet werken. Maak een nieuw archief.
  • Kies de compressor bewust. gzip als iemand anders het moet kunnen openen, xz als het vaak gedownload wordt, zstd als het elke nacht draait en jij de enige afnemer bent.
  • Controleer de afsluitcode in scripts. 0 is goed, 1 betekent dat er iets onder je handen veranderde, 2 betekent dat het archief onvolledig kan zijn. Een backupscript dat dit negeert meldt in beide gevallen succes.
  • Dump de database apart. tar over een draaiende databasemap levert een bestand op dat op een backup lijkt en het niet is.
  • Test de restore, niet het archief. tar df en --totals zijn goedkope controles; geen van beide bewijst dat je de site opnieuw kunt opbouwen. Alleen ergens uitpakken en kijken doet dat.
$ man 1 tar               # the full manual, options grouped by mode
$ tar --help              # a much shorter summary
$ tar --show-defaults     # what your build assumes when you say nothing
$ info tar                # the GNU manual, far more detailed than the man page
Naar boven

9. Veelgemaakte fouten

9.1 Mythe versus werkelijkheid

MytheWerkelijkheid
"tar comprimeert bestanden." Dat heeft hij nooit gedaan. Hij plakt aan elkaar, en maakt het resultaat groter. gzip, xz en soortgenoten doen het comprimeren.
"Je moet -z meegeven om een .tar.gz uit te pakken." Moderne GNU tar herkent de compressie zelf. tar xf kan met gz, bz2, xz en zst overweg.
".tar.gz en .zip zijn hetzelfde met een andere naam." zip heeft een index en comprimeert per bestand; tar.gz is een solide stroom. Dat is een verschil van 130x bij het uithalen van een bestand.
"--exclude werkt waar je het ook zet." Het is positioneel. Achter de paden doet het niets, en tar stopt met code 2 en zegt dat.
"tar behoudt permissies." Hij legt ze vast. Of ze teruggezet worden hangt af van -p en van wie er uitpakt; bij een gewone gebruiker wordt de umask toegepast.
"Ik kan een bestand aan mijn backup.tar.gz toevoegen." Dat kan niet. Aan gecomprimeerde archieven kun je niets toevoegen, en uit een tar-archief kun je nooit iets verwijderen.
"bzip2 geeft de beste compressie." xz verslaat hem op verhouding en op uitpaksnelheid. bzip2 is een aanbeveling die zijn reden overleefd heeft.
"Een leeg tar-archief is leeg." Het minimum is 10240 bytes, door de blokfactor die van bandstations geerfd is.
"Een tar-archief kan overal op het bestandssysteem schrijven." Niet op moderne GNU tar. Voorste / en ../ worden weggehaald, en een omleiding via een symlink wordt geweigerd met "Cannot open: Not a directory". -P zet dat uit.
"Een sparse schijfimage wordt zo klein gearchiveerd als hij op schijf is." Alleen met -S. Zonder die vlag schrijft een sparse bestand van 100 MB 104.867.840 bytes aan nullen in het archief.
"Dezelfde bestanden twee keer inpakken geeft hetzelfde archief." Nee. Tijdstempels, eigendom en mapvolgorde verschillen allemaal. Er zijn vijf vlaggen nodig om tar deterministisch te maken.
"tar 0 betekent dat de backup goed is." Het betekent dat tar klaar is. Het zegt niets over de vraag of het archief een werkend systeem kan opbouwen.

9.2 Andere valkuilen om te vermijden

  • Uitpakken zonder te kijken. Een tarbom strooit bestanden uit over je huidige map, door elkaar met wat er al stond. Eerst tar tzf, of altijd --one-top-level.
  • -j en -J verwarren. Kleine letter is bzip2, hoofdletter is xz. Gebruik --bzip2 en --xz in scripts, waar niemand ze verkeerd leest.
  • Een map in zichzelf back-uppen. tar czf /var/www/backup.tar.gz /var/www probeert het bestand te archiveren dat hij aan het schrijven is. tar merkt het meestal en slaat het over, maar het resultaat is niet wat je bedoelde. Schrijf het archief ergens anders heen.
  • Een draaiende databasemap archiveren. De bestanden veranderen terwijl tar ze leest, en het archief bevat een toestand die nooit bestaan heeft. Dump eerst de database, archiveer daarna de dump.
  • Aannemen dat eigendom teruggezet wordt. Als gewone gebruiker gebeurt dat nooit; alles wordt van jou. Als root gebeurt het op naam, en dat klopt tot de doelmachine die accounts niet heeft.
  • Erop vertrouwen dat -u een archief actueel houdt. Hij voegt nieuwe versies toe en haalt oude nooit weg, dus het archief groeit en bevat meerdere kopieën van hetzelfde pad.
  • Het snapshotbestand kwijtraken. Zonder het -g-bestand wordt een incrementele backup stilletjes een volledige, en de keten die je voor een restore nodig hebt is verbroken.
  • -h toevoegen zonder te kijken waar de links naartoe wijzen. Een symlink naar een mediavolume maakt van een sitebackup van 200 MB een van 40 GB, en het enige symptoom is dat de backup traag werd.
  • De vlaggen voor reproduceerbaarheid in een variabele zonder aanhalingstekens zetten. --mtime='UTC 2026-01-01' bevat een spatie, dus de shell splitst hem en tar meldt 2026-01-01: Cannot stat: No such file or directory. Gebruik --mtime=@0 als het in een variabele moet.
  • In tar pipen zonder set -o pipefail. tar czf - map | ssh host 'cat > backup.tar.gz' meldt succes zodra de andere kant slaagt, ook als tar halverwege faalde.
Naar boven

10. Samenvatting

tar is een programma dat gebouwd is voor hardware die al decennia niemand meer gebruikt, en het is nog steeds het juiste antwoord op "zet deze map in een bestand" op elk Unix-systeem ter wereld.

  • tar betekent tape archive. Vrijwel elke eigenaardigheid volgt uit het feit dat een band een stroom is die je alleen van begin tot eind kunt lezen.
  • Hij plakt aan elkaar; hij comprimeert niet. -z, -j, -J en --zstd sturen het resultaat door een apart programma, en daarom bestaat de extensie uit twee delen.
  • Drie modi, waarvan er altijd precies een geldt: -c maken, -t tonen, -x uitpakken. -f benoemt het archief, en zonder die vlag schrijft tar naar standaarduitvoer.
  • Uitpakken heeft geen compressievlag meer nodig. tar xf zoekt het formaat zelf uit.
  • Op echte gegevens gaf xz de beste grootte en gzip de beste uitwisselbaarheid, terwijl zstd in beide richtingen het snelst was. bzip2 werd op elk punt verslagen.
  • -C kiest de map bij zowel maken als uitpakken; --strip-components haalt de map met het versienummer weg die broncodereleases gebruiken.
  • --exclude is positioneel en moet voor de paden staan, anders doet het stilzwijgend niets en stopt tar met code 2.
  • Absolute paden worden met opzet weggehaald, zodat uitpakken altijd gebeurt waar jij bent.
  • Permissies worden vastgelegd maar door je umask gefilterd, tenzij je -p meegeeft, en dat is alleen voor root de standaard. Eigendom wordt op naam gezocht.
  • Symlinks worden als links bewaard; -h volgt ze wel, en dat kan de omvang van een backup stilletjes vermenigvuldigen.
  • -S gaat om met sparse bestanden. Zonder die vlag schrijft een image van 100 MB waar niets in staat 100 MB aan nullen.
  • Archieven zijn niet vanzelf reproduceerbaar, maar vijf vlaggen maken ze byte voor byte gelijk tussen builds.
  • Moderne GNU tar blokkeert de klassieke uitpakaanvallen al. Wat hij niet blokkeert is overschrijven van wat er al in de map staat die jij koos.
  • tar laat zich als pipe combineren: twee keer tar kopieert een boom, en een keer over ssh verhuist een site zonder ergens een tijdelijk bestand.
  • Een .tar.gz is een solide archief: kleiner dan een zip, maar zonder index, dus een bestand eruit halen kost evenveel als alles uitpakken.
  • Kijk voordat je uitpakt, of geef --one-top-level mee, en een tarbom kan je nooit meer verrassen.

Dit is het spiekbriefje dat je wilt bewaren:

tar czf out.tar.gz dir/        create, gzip
tar caf out.tar.xz dir/        create, compressor chosen by extension
tar tzf out.tar.gz             list (ALWAYS do this before extracting)
tar tvzf out.tar.gz            list with sizes, owners and modes
tar xf out.tar.gz              extract (format detected automatically)
tar xf out.tar.gz -C /target   extract somewhere else
tar xf out.tar.gz --one-top-level    never be tarbombed again

-c create   -t list   -x extract   -f FILE   -v verbose
-h follow symlinks (CHECK first)   -S sparse files (disk images)
-z gzip     -j bzip2  -J xz        --zstd    -a by extension
-C DIR      change directory (create AND extract)
-p          keep permissions exactly (default only for root)

--strip-components=1           drop the wrapper directory
--exclude='*.log'              BEFORE the paths, or it does nothing
--exclude-vcs                  drop .git, .svn and friends
--numeric-owner                restore UIDs, not names, across servers
--one-top-level                unpack into a directory named after the archive
--format=pax                   the standard format, for long-term archives
--exclude-from=list.txt        patterns from a file, kept in version control
-I 'zstd -19'                  any compressor, with its own options
-g snapshot.snar               incremental backup state

--sort=name --mtime='UTC 2026-01-01' --owner=0 --group=0 --numeric-owner
                               byte-identical archives between builds

tar cf - src | tar xf - -C dst          copy a tree, keeping hard links
tar czf - dir | ssh host 'tar xzf -'    move a site, no temp file
tar xzf a.tgz -O path/to/file           read one file out, without unpacking
tar df archive.tar                      compare archive against disk
tar tf archive.tar >/dev/null           cheap "is it corrupt" check
sha256sum a.tgz > a.tgz.sha256          prove the bytes survive the copy
tar tvf unknown.tgz | less              ALWAYS, before unpacking a stranger's

exit 0 ok | 1 files differ or changed while reading | 2 fatal

Backups en verhuizingen zijn de twee klussen waarbij tar stilletjes het meeste werk doet, en allebei zijn ze niet beter dan de restore die niemand getest heeft. Wil je dat de archieven die je server maakt archieven zijn waarmee je echt een website kunt herbouwen, dan is dat precies het soort rustige werk waar ik graag bij help.

Naar boven
Linux commando: tar
Peter Martin
Peter Martin
Joomla Specialist

Peter is Joomla specialist en Linux admin voor snelle, veilige en schaalbare websites.

Gerelateerde artikelen