tar
Archive and compress files and directories
tar bundles a directory tree into a single archive file, preserving permissions,
ownership, and directory structure. The name is short for "tape archive," a holdover from when
the typical destination really was a tape drive, but today it's the standard way to package
source trees, backups, and release artifacts on Linux.
tar itself doesn't compress anything; it just concatenates files with metadata headers. The
familiar .tar.gz is a plain .tar piped through gzip afterwards. tar's -z, -j, and
-J flags do exactly that pipe for you in one command, using gzip, bzip2, or xz
respectively.
The three flags you'll use every time
Almost every tar invocation is one mode flag plus -v (verbose) plus -f (file):
-ccreate a new archive-xextract an archive-tlist an archive's contents without extracting
tar -czvf site-backup.tar.gz site/ # create, gzip, verbose, to this file
tar -tzvf site-backup.tar.gz # list, gzip, verbose
tar -xzvf site-backup.tar.gz # extract, gzip, verbose
-f always takes the archive filename as its argument and is usually written last, right
before the filename, since combined short flags (-czvf) still need their arguments in order.
Picking a compression format
gzip (-z) is fastest and universally supported; xz (-J) compresses noticeably smaller at
the cost of more CPU time; bzip2 (-j) sits between them and is less common today. Unless
you have a specific reason otherwise, .tar.gz is the safe default for sharing archives, and
.tar.xz is worth the extra CPU when archive size matters more (release downloads, long-term
backups).
Always verify before you trust an archive
tar -tzf archive.tar.gz > /dev/null reads through the whole archive and reports failure if
anything is corrupt, without writing any files to disk. Cheap insurance before you delete the
original data an archive is supposed to be backing up.
Creating archives
The -c mode, with a compression flag and a filename.
Create a gzip-compressed archive of a directory
tar -czvf site-backup.tar.gz site/
`-c` create, `-z` gzip, `-v` verbose (print each file as it's added), `-f` the archive filename. This is the combination you'll type most.
Show output
site/
site/img/
site/img/logo.png
site/index.html
site/css/
site/css/style.css
Create an archive without compression
tar -cvf site-backup.tar site/
Drop `-z` for a plain, uncompressed `.tar`: faster to create, larger on disk. Useful as an intermediate step before compressing separately.
Create an archive of specific files, not a whole directory
tar -czvf site-single.tar.gz site/index.html
Pass individual paths instead of a directory to archive just those files.
Show output
site/index.html
Create an archive whose paths don't include the parent directory
tar -czf site.tar.gz -C site .
`-C site` changes into `site/` before archiving, so paths inside the archive start from `.` instead of `site/`. Useful when you want the archive's contents to land directly in whatever directory it's extracted into, with no wrapper folder.
Exclude files matching a pattern
tar --exclude="*.png" -czvf site-noimg.tar.gz site/
`--exclude` takes a glob and skips any matching path. Repeat the flag for multiple patterns.
Show output
site/
site/img/
site/index.html
site/css/
site/css/style.css
Exclude version control metadata
tar --exclude-vcs -czf snapshot.tar.gz site/
`--exclude-vcs` skips `.git`, `.svn`, and other VCS directories automatically, without listing them by hand.
Exclude a list of patterns from a file
echo "*.png" > excludes.txt
tar --exclude-from=excludes.txt -czvf site-ex.tar.gz site/
`--exclude-from` reads one glob per line from a file, easier to maintain than a long list of repeated `--exclude` flags once you have more than a couple of patterns.
Show output
site/
site/img/
site/index.html
site/css/
site/css/style.css
Choosing a compression format
gzip, bzip2, and xz trade speed for ratio.
Compress with bzip2 instead of gzip
tar -cjvf site-backup.tar.bz2 site/
`-j` selects bzip2, slower than gzip but usually a bit smaller.
Compress with xz for the smallest archive
tar -cJvf site-backup.tar.xz site/
`-J` selects xz, slowest to compress, but noticeably smaller output, especially on text-heavy content.
Compare compressed sizes on the same content
tar -czf app.tar.gz access.log
tar -cjf app.tar.bz2 access.log
tar -cJf app.tar.xz access.log
ls -lh app.tar.*
On a large, repetitive text log, the difference is dramatic: xz and bzip2 both find redundancy gzip misses. On already-compressed content (images, video), expect all three to end up roughly the same size as the input.
Show output
-rw-r--r-- 1 user user 2.7K app.tar.bz2
-rw-r--r-- 1 user user 31K app.tar.gz
-rw-r--r-- 1 user user 1.9K app.tar.xz
Listing archive contents
Check what's inside before you extract it.
List an archive's contents
tar -tzvf site-backup.tar.gz
`-t` lists without extracting; `-v` here shows permissions, owner, size, and date, like `ls -l`.
Show output
drwxr-xr-x user/user 0 2026-07-05 15:35 site/
drwxr-xr-x user/user 0 2026-07-05 15:35 site/img/
-rw-r--r-- user/user 20480 2026-07-05 15:35 site/img/logo.png
-rw-r--r-- user/user 16 2026-07-05 15:35 site/index.html
drwxr-xr-x user/user 0 2026-07-05 15:35 site/css/
-rw-r--r-- user/user 16 2026-07-05 15:35 site/css/style.css
List contents without the long format
tar -tf site-backup.tar.gz
Just the paths, one per line, good for piping into `grep` or `wc -l`.
Show output
site/
site/img/
site/img/logo.png
site/index.html
site/css/
site/css/style.css
Search an archive's contents for a pattern
tar --list --wildcards "*.html" -f site-backup.tar.gz
`--wildcards` filters the listing itself, without extracting anything first.
Show output
site/index.html
Extracting archives
The -x mode, and where things land.
Extract an archive into the current directory
tar -xzvf site-backup.tar.gz
Recreates whatever directory structure was stored, relative to where you run the command.
Show output
site/
site/img/
site/img/logo.png
site/index.html
site/css/
site/css/style.css
Extract into a specific directory
tar -xzvf site-backup.tar.gz -C restore/
`-C` changes to the target directory first. The destination must already exist; `tar` won't create it.
Extract just one file from an archive
tar -xzf site-backup.tar.gz -C restore/ site/index.html
Add the specific in-archive path after the archive name to extract only that file, keeping its stored directory structure.
Extract without recreating the archive's top-level directory
tar -xzvf site-backup.tar.gz --strip-components=1 -C restore/
`--strip-components=1` drops the first path segment of every entry during extraction, turning `site/index.html` into just `index.html` in the destination. Increase the number to drop more levels.
Show output
site/img/
site/img/logo.png
site/index.html
site/css/
site/css/style.css
Extract without overwriting files that already exist
tar -xkvf plain.tar -C restore/
`-k` (`--keep-old-files`) refuses to overwrite existing files instead of silently replacing them, safer when restoring into a directory that might already have newer versions of some files.
Show output
site/css/style.css
tar: site/css/style.css: Cannot open: File exists
site/index.html
tar: site/index.html: Cannot open: File exists
tar: Exiting with failure status due to previous errors
Updating and appending
Adding to an archive that already exists.
Append a file to an existing uncompressed archive
tar -rvf plain.tar site/index.html
`-r` (`--append`) adds files to the end of an existing `.tar`. This only works on uncompressed archives; you can't append to a `.tar.gz` directly.
Show output
site/index.html
Update only files that are newer than what's in the archive
tar -uvf plain.tar site/index.html
`-u` (`--update`) is like `-r` but skips files whose in-archive copy is already up to date. No output here means nothing needed updating.
Verifying and troubleshooting
Trust, but check, before you delete the original.
Verify an archive is readable without extracting it
tar -tzf site-backup.tar.gz > /dev/null && echo "OK: archive is valid"
Reads through the entire archive and checks the compressed stream and headers, without writing anything to disk. Cheap insurance before deleting whatever the archive backs up.
Show output
OK: archive is valid
Detect a corrupted or truncated archive
head -c 100 site-backup.tar.gz > corrupt.tar.gz
tar -tzf corrupt.tar.gz; echo "exit=$?"
A truncated file fails partway through with a clear error instead of silently reporting an empty archive. `tar` exits non-zero, which a backup script should check.
Show output
gzip: stdin: unexpected end of file
tar: Child returned status 1
tar: Error is not recoverable: exiting now
exit=2
See progress on a large archive without keeping the output
tar -czvf /dev/null site/
Sending the archive itself to `/dev/null` while keeping `-v` gives you a pure progress listing, a quick way to sanity-check which files *would* be included before committing to a real destination.
Show output
site/
site/css/
site/css/style.css
Comparing to the source directory
How much did compression actually buy you?
Stream an archive to stdout instead of a file
tar -czf - site/ | wc -c
A single `-` as the filename means stdout (for `-c`) or stdin (for `-x`), the basis for streaming an archive straight over the network, e.g. `tar -czf - site/ | ssh deb1 'tar -xzf - -C /srv/backups'`, without ever writing the archive to disk on either end.
Show output
20861
Compare a directory's size to its compressed archive
du -sh site/
tar -czf site-current.tar.gz site/
ls -lh site-current.tar.gz
`du -sh` sums the directory's real disk usage; compare it to the resulting archive size to judge whether the compression flag you chose is pulling its weight on this particular content.
Show output
40K site
-rw-r--r-- 1 user user 21K site-current.tar.gz