tar, gzip and zip: Create and Extract Archives on Linux

Files · 8 min read · Updated 25 Oct 2026

On this page
  1. The tar options you need
  2. Create a tar.gz archive
  3. List what is inside
  4. Extract an archive
  5. Exclude files
  6. Archive without the parent path
  7. tar over pipes and SSH
  8. Compress single files with gzip, xz and bzip2
  9. zip and unzip
  10. Which format should you use?
  11. Quick reference

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:

OptionMeaning
cCreate an archive
xExtract an archive
tList the contents
fThe archive file name follows (always last in the group)
vVerbose: show each file
z / j / JCompress with gzip / bzip2 / xz
C dirChange 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.

Always list an archive from an unknown source before extracting it. You will see whether it unpacks into its own folder or scatters files into your current directory, which is sometimes called a tarbomb.

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.

Extracting overwrites existing files with the same names without asking. If you are unpacking into a directory that already has work in it, extract into an empty directory first and compare.

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

GoalCommand
Create tar.gztar -czf out.tar.gz dir/
Create tar.xztar -cJf out.tar.xz dir/
List contentstar -tf file.tar.gz
Extract heretar -xf file.tar.gz
Extract elsewheretar -xf file.tar.gz -C /target
Drop top foldertar -xf file.tar.gz --strip-components=1
Exclude patterntar -czf out.tar.gz --exclude='*.log' dir/
gzip, keep originalgzip -k file
Search gzipped logzgrep error app.log.gz
Zip a folderzip -r out.zip dir/
Unzip to folderunzip file.zip -d target/