tar¶
Format: .tar (plus .tar.gz, .tar.bz2, .tar.xz, .tar.zst, …) · Type: archiver · First released: 1979, Version 7 Unix
tar (tape archive) bundles files and their metadata into a single stream. It doesn't compress by itself; it hands the stream to a compressor such as gzip, bzip2, xz or zstd. GNU tar is the standard on Linux. macOS, the BSDs and Windows ship bsdtar (libarchive), which uses mostly the same flags and reads more formats.
Archive formats: the original V7 format, POSIX ustar (1988), GNU extensions, and POSIX pax (2001), which removes old limits on path length, file size and metadata.
Operation modes (pick one)¶
| Flag | Long form | Meaning |
|---|---|---|
c |
--create |
Create |
x |
--extract |
Extract |
t |
--list |
List contents |
r |
--append |
Append files (uncompressed archives only) |
u |
--update |
Append newer versions (uncompressed only) |
A |
--concatenate |
Append another tar archive |
d |
--diff |
Compare archive to filesystem |
--delete |
Remove members (uncompressed only) |
Common modifiers¶
| Flag | Meaning |
|---|---|
f FILE |
Archive file (- = stdin/stdout). Must be followed directly by the filename. |
v |
Verbose (vv for a long listing) |
C DIR |
Change to DIR first |
z |
gzip |
j |
bzip2 |
J |
xz |
--zstd |
zstd (GNU tar 1.31+) |
--lzip, --lzma, --lzop, Z |
lzip, legacy LZMA, lzop, compress |
a, --auto-compress |
Pick the compressor from the archive extension when creating |
I CMD, --use-compress-program=CMD |
Use any compressor command, with options |
Creating archives¶
# Plain tar
tar cvf archive.tar src_dir/
# Compressed tarballs
tar czvf archive.tar.gz src_dir/ # gzip
tar cjvf archive.tar.bz2 src_dir/ # bzip2
tar cJvf archive.tar.xz src_dir/ # xz
tar --zstd -cvf archive.tar.zst src_dir/ # zstd
# Let tar pick from the extension
tar caf archive.tar.zst src_dir/
# Full control over the compressor (threads, level, long mode)
tar -I 'zstd -T0 -19 --long=31' -cf archive.tar.zst src_dir/
tar -I 'xz -T0 -9' -cf archive.tar.xz src_dir/
tar -I pigz -cf archive.tar.gz src_dir/
In bundled style, letter order mostly doesn't matter (czvf == zcvf == cvzf) except that f must come last, because the next word is taken as the filename. tar cfz archive.tar.gz dir creates an archive literally named z. Dashed options (-c -z -f archive.tar.gz) avoid the problem.
Extracting¶
GNU tar and bsdtar auto-detect compression when reading, so the compression flag is optional:
tar xvf archive.tar.gz # works for .gz, .bz2, .xz, .zst, .lz, .Z ...
tar xvf archive.tar.xz -C /opt # extract into /opt (must exist)
Explicit forms still work:
tar xzvf archive.tar.gz
tar xjvf archive.tar.bz2
tar xJvf archive.tar.xz
tar --zstd -xvf archive.tar.zst
Anything after the archive name is a list of members to extract, not a destination. Use -C for the destination:
tar xvf archive.tar.gz src_dir/config.yaml # one member
tar xvf archive.tar.gz --wildcards '*.conf' # by pattern
tar xvf archive.tar.gz -C /tmp/restore src_dir/ # member into a directory
tar xOf archive.tar.gz src_dir/config.yaml # member to stdout
Listing¶
tar tvf archive.tar.gz # auto-detects compression
tar tzvf archive.tar.gz # explicit gzip
tar tjvf archive.tar.bz2 # explicit bzip2
tar tJvf archive.tar.xz # explicit xz
tar tf archive.tar.gz | head # names only; check for a single top-level dir
Using the wrong flag (for example tar tjvf file.tar.gz) fails, so either match the flag to the compressor or leave it out.
Excluding and filtering¶
tar czf backup.tar.gz \
--exclude='*.log' \
--exclude='node_modules' \
--exclude-vcs \
--exclude-caches \
project/
tar czf backup.tar.gz -X exclude-list.txt project/ # patterns from a file
tar czf backup.tar.gz -T file-list.txt # files to include, from a file
find . -name '*.rs' -print0 | tar czf src.tar.gz --null -T -
tar czf recent.tar.gz --newer-mtime='7 days ago' project/
--exclude-vcs skips .git, .svn and friends. --exclude-caches skips directories with a CACHEDIR.TAG file (Cargo's target/ has one). Put --exclude options before the paths for portability.
Controlling paths¶
# Archive the contents of a dir without the dir as a prefix
tar czf site.tar.gz -C /var/www/site .
# Strip leading components on extract
tar xzf release.tar.gz --strip-components=1 -C /opt/app
# Rename on the fly (sed-style)
tar czf out.tar.gz --transform 's,^build,myapp-1.2.0,' build/
GNU tar strips the leading / from absolute paths when creating ("Removing leading /' from member names"). That's a safety feature;-P` disables it, which you almost never want.
Preserving metadata¶
tar --acls --xattrs --selinux -cpzf full.tar.gz /srv/data
tar --acls --xattrs --selinux -xpzf full.tar.gz -C /
tar --numeric-owner -czf data.tar.gz /srv/data
tar --one-file-system -czf root.tar.gz /
tar -S -czf vm.tar.gz disk.img # handle sparse files efficiently
-ppreserves permissions on extract (default as root).- As root, tar restores original ownership; as a normal user, files belong to you.
--no-same-ownerforces the latter even as root (useful in containers). --numeric-ownermatters when restoring onto a system whose names map to different UIDs/GIDs.--one-file-systemstops at mount points, avoiding/proc, network mounts and so on.-S/--sparsestores holes in sparse files instead of gigabytes of zeroes.
Incremental backups (GNU tar)¶
# Level 0 (full)
tar --listed-incremental=snap.snar -czf full.tar.gz /data
# Incrementals (copy the snapshot file first to keep the level-0 state)
cp snap.snar snap-1.snar
tar --listed-incremental=snap-1.snar -czf incr-1.tar.gz /data
# Restore: full, then each incremental in order
tar --listed-incremental=/dev/null -xzf full.tar.gz -C /
tar --listed-incremental=/dev/null -xzf incr-1.tar.gz -C /
For serious backups, restic, borg, or kopia add deduplication, encryption, and pruning, but this works with nothing but tar.
Appending, comparing, verifying¶
These only work on uncompressed .tar files:
tar rvf archive.tar newfile # append
tar uvf archive.tar src_dir/ # append changed files
tar --delete -f archive.tar oldfile # remove a member
tar df archive.tar # diff archive vs filesystem
tar cWf archive.tar dir/ # verify after writing
Formats and long paths¶
tar --format=posix -cf archive.tar dir/ # pax: no path/size limits, full metadata
tar --format=ustar -cf archive.tar dir/ # maximum compatibility, 255-char paths, 8 GiB files
GNU tar's default gnu format handles long names too; choose posix when other tools need to read the archive.
Reproducible tarballs¶
For byte-identical build artifacts:
tar --sort=name \
--mtime='2026-01-01 00:00Z' \
--owner=0 --group=0 --numeric-owner \
--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime \
-cf - dir/ | gzip -n > dir.tar.gz
Encrypted tarballs¶
tar has no encryption. Pipe the compressed stream through age, gpg, or openssl:
tar cf - dir/ | zstd -T0 | age -p > dir.tar.zst.age
age -d dir.tar.zst.age | zstd -d | tar xf -
See encryption for all the options and why openssl des3 should be avoided.
See also¶
- Pipelines — tar over SSH, splitting, progress bars
- Gotchas — tarbombs and path traversal
- cpio — the other classic Unix archiver
- Cheat sheet