tar

Archive and compress files and directories

Updated 2026-07-05

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):

  • -c create a new archive
  • -x extract an archive
  • -t list 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 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.

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

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

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