tar, gzip and zip: Create and Extract Archives on Linux
On this page
Linux keeps two jobs separate that Windows tools usually combine. tar bundles many files and directories into one archive file, keeping names, permissions and timestamps. A compressor such as gzip, bzip2, xz or zstd makes a single file smaller. A .tar.gz is simply a tar archive that has been run through gzip. zip does both at once and is the format to use when the archive is going to someone on Windows or macOS.
The tar options you need
Almost every tar command is built from a handful of single-letter options:
| Option | Meaning |
|---|---|
c | Create an archive |
x | Extract an archive |
t | List the contents |
f | The archive file name follows (always last in the group) |
v | Verbose: show each file |
z / j / J | Compress with gzip / bzip2 / xz |
C dir | Change to a directory first |
Because f takes the file name as its argument, it must come last: tar -czf archive.tar.gz works, but tar -cfz archive.tar.gz creates an archive called z.
Create a tar.gz archive
$ tar -czf project.tar.gz project/
That reads as "create, gzip, file project.tar.gz, from the directory project/". Add v to watch the files go by. You can list several files and directories at the end, and a date in the name makes tidy backups:
$ tar -czf backup-$(date +%F).tar.gz project/ notes.txt
Swap z for J to use xz, which is slower but usually much smaller, or use --zstd on recent systems for a good balance of speed and size. On a test directory of mostly text, the same files came out like this:
$ tar -cjf project.tar.bz2 project/
$ tar -cJf project.tar.xz project/
$ tar --zstd -cf project.tar.zst project/
$ ls -l project.tar.* | awk '{print $5, $9}'
25565 project.tar.bz2
45455 project.tar.gz
5820 project.tar.xz
27419 project.tar.zst
Results vary a lot with the data. Already compressed files such as JPEGs, videos and zips barely shrink at all, so do not expect miracles from a photo backup.
List what is inside
$ tar -tzf project.tar.gz
project/
project/src/
project/src/nums.txt
project/src/a.txt
project/.env
project/logs/
project/logs/app.log
Use -tvf for an ls -l style listing with sizes, owners and dates. Modern GNU tar detects the compression by itself when reading, so tar -tf and tar -xf work on .tar.gz, .tar.xz and .tar.bz2 without the extra letter.
Extract an archive
$ tar -xzf project.tar.gz # into the current directory
$ tar -xzf project.tar.gz -C /tmp/out # into another directory
The directory given to -C must already exist; create it with mkdir -p first. To extract just one file, name it exactly as it appears in the listing:
$ tar -xzf project.tar.gz -C out2 project/src/a.txt
To drop the top-level folder while extracting, use --strip-components=1. That turns project/src/a.txt into src/a.txt, which is useful when a download unpacks into a versioned directory name you do not want.
Exclude files
$ tar -czf clean.tar.gz --exclude='*.log' --exclude='.env' project/
$ tar -tzf clean.tar.gz
project/
project/src/
project/src/nums.txt
project/src/a.txt
project/logs/
Quote the patterns so the shell does not expand them. Repeat --exclude as often as you need, or put patterns in a file and use --exclude-from=file. Leaving out .env files, logs and node_modules is a good habit when you share code.
Archive without the parent path
tar stores paths exactly as you give them. To archive the contents of a directory without its name, change into it with -C and archive .:
$ tar -C project -czf rel.tar.gz .
$ tar -tzf rel.tar.gz | head -3
./
./src/
./src/nums.txt
GNU tar strips a leading / from absolute paths and warns about it, so an archive made from /etc will not overwrite your real /etc when someone extracts it.
tar over pipes and SSH
Use - as the file name to write to standard output or read from standard input. That lets you copy a directory to another machine without a temporary file:
$ tar -czf - project/ | ssh user@host 'tar -xzf - -C /srv'
For repeated copies, rsync is usually a better choice because it only sends changes; see the SSH tips guide. To check an archive against the files on disk, use tar -dzf project.tar.gz, which prints nothing when everything matches.
Compress single files with gzip, xz and bzip2
$ gzip n.txt # replaces n.txt with n.txt.gz
$ gunzip n.txt.gz # and back again
$ gzip -k n.txt # keep the original
$ gzip -l n.txt.gz
compressed uncompressed ratio uncompressed_name
45010 108894 58.7% n.txt
By default gzip deletes the original after compressing it, which surprises people; -k keeps it. -9 compresses harder, -c writes to standard output, and -t tests an archive for damage. xz -k and bzip2 -k work the same way and produce .xz and .bz2 files.
You can read compressed logs without unpacking them:
$ zcat app.log.gz | head
$ zgrep "error" app.log.gz
$ zless app.log.gz
Rotated logs in /var/log are usually gzipped, so zgrep searches old logs directly. There are also xzcat and bzcat.
zip and unzip
$ zip -r project.zip project/ -x '*.log'
$ unzip -l project.zip # list contents
$ unzip -q project.zip -d unz # extract quietly into unz/
$ unzip -p project.zip project/src/a.txt
hello
-r is needed to include directories, and -x excludes patterns. unzip -d creates the target directory if needed. -p prints a file to standard output without extracting anything. zip -j stores files without their folders, and unzip -t tests the archive.
zip can also encrypt archives with -e, but classic zip encryption is weak. For anything sensitive, use 7z with AES or encrypt the tarball with gpg.
Which format should you use?
- tar.gz: the safe default on Linux. Fast and readable everywhere.
- tar.xz: smaller downloads and long-term archives where time does not matter.
- tar.zst: fast backups with good compression, on systems that have zstd.
- zip: anything going to Windows or macOS users, or files you need to pull out one at a time.
To clean up after yourself, the find guide shows how to locate and delete old archives, and the cheat sheet has these commands ready to copy.
Quick reference
| Goal | Command |
|---|---|
| Create tar.gz | tar -czf out.tar.gz dir/ |
| Create tar.xz | tar -cJf out.tar.xz dir/ |
| List contents | tar -tf file.tar.gz |
| Extract here | tar -xf file.tar.gz |
| Extract elsewhere | tar -xf file.tar.gz -C /target |
| Drop top folder | tar -xf file.tar.gz --strip-components=1 |
| Exclude pattern | tar -czf out.tar.gz --exclude='*.log' dir/ |
| gzip, keep original | gzip -k file |
| Search gzipped log | zgrep error app.log.gz |
| Zip a folder | zip -r out.zip dir/ |
| Unzip to folder | unzip file.zip -d target/ |