Skip to content

Archiving and Compression: tar, gzip, zip

Taking a backup, keeping logs for the long term, or shipping files to another server all involve the same two needs: gathering multiple files into one object, and shrinking its size. On Linux these are two distinct jobs — archiving (packing several files into one file) and compression (reducing size) — usually handled by two different tools that are almost always used together.

This article follows Finding Files and Searching Text and Rewriting Text: sed and awk: once files have been located and cleaned up, they often need to be stored or transferred. It covers creating, inspecting, and extracting an archive with tar; compressing with gzip; when zip is a better fit than tar.gz; and the habit of verifying an archive before you trust it.

Lab Setup

mkdir -p ~/lab/archive/project/{src,logs}
cd ~/lab/archive
printf 'def main():\n    pass\n' > project/src/app.py
printf 'level=INFO message=service started\n' > project/logs/app.log
printf 'level=ERROR message=connection timeout\n' >> project/logs/app.log
find project -type f -printf '%p %s bytes\n'

tar: Packing Files into One Archive

The name tar ("tape archive") is a holdover from an era of writing to magnetic tape, but it remains the most widely used archiving tool today. On its own, tar does not compress anything — it only bundles files and directories into one file while preserving the directory structure, permissions, and ownership.

Creating an Archive

tar -cvf project.tar project
  • -c: create a new archive.
  • -v: verbose, showing which files are being added.
  • -f project.tar: the archive's filename. -f must be the last flag in a bundled group, immediately followed by the filename.
project/
project/src/
project/src/app.py
project/logs/
project/logs/app.log

Viewing Contents Without Extracting

tar -tvf project.tar
drwxr-xr-x user/user         0 2026-07-29 10:00 project/
drwxr-xr-x user/user         0 2026-07-29 10:00 project/src/
-rw-r--r-- user/user        21 2026-07-29 10:00 project/src/app.py
drwxr-xr-x user/user         0 2026-07-29 10:00 project/logs/
-rw-r--r-- user/user        49 2026-07-29 10:00 project/logs/app.log

-t lists the archive's contents without writing anything to disk. Running this before extracting an archive from an untrusted source is good practice.

Warning

Extracting an archive without inspecting it first can be risky: a path inside the archive that begins with ../ can attempt to write outside the current directory (path traversal). Modern GNU tar rejects absolute paths and paths starting with .. by default and warns about them, but checking an untrusted archive with -tvf first is still worth the habit.

Warning

Extracting as root is riskier than as a normal user. GNU tar restores ownership, timestamps, and — with -p, which is implied when running as root — the original permission bits, including setuid/setgid. A hostile archive can therefore drop a root-owned setuid binary straight onto the system. Extract untrusted archives as an unprivileged user, into an empty directory, only after inspecting them with -tvf.

Extracting an Archive

mkdir extracted
tar -xvf project.tar -C extracted
find extracted -type f
  • -x: extract.
  • -C extracted: extract into the given directory instead of the current one. Without -C, tar extracts paths relative to the current directory.

Extracting a Single File

tar -xvf project.tar project/logs/app.log -C extracted

This extracts only the given path rather than the whole archive. The path must match exactly what tar -tvf reported.

Compression: gzip Alongside tar

tar alone does not compress. To shrink the resulting .tar file, pass it through a separate compression tool — usually gzip — either as a second step, or through a flag tar integrates directly, in a single command.

Archiving and Compressing in One Command

tar -czvf project.tar.gz project
ls -lh project.tar project.tar.gz

The -z flag tells tar to pipe its output through gzip. The extension is conventionally written .tar.gz or shortened to .tgz — this is purely a naming convention; tar does not infer behavior from the extension, only from the -z flag itself.

Extracting a Compressed Archive

tar -xzvf project.tar.gz -C extracted

-x (extract) and -z (gzip) are used together — tar first runs the equivalent of gunzip, then extracts the archive.

Compressing a Single File: gzip/gunzip

gzip compresses one file and, by default, replaces the original with a .gz-suffixed compressed copy:

cp project/logs/app.log app.log.copy
gzip app.log.copy
ls -l app.log.copy.gz

app.log.copy no longer exists — gzip compressed it and left app.log.copy.gz in its place. To keep the original file:

gzip -k project/logs/app.log
ls -l project/logs/app.log project/logs/app.log.gz

-k (keep) leaves the original file in place.

Restoring a compressed file:

gunzip -k project/logs/app.log.gz

Viewing a compressed file's contents without decompressing it to disk:

zcat project/logs/app.log.gz

zcat is equivalent to gunzip -c; it writes the result to standard output instead of a file.

Compression Level: Size versus Speed

gzip -k -9 project/logs/app.log
mv project/logs/app.log.gz project/logs/app.log.max.gz
gzip -k -1 project/logs/app.log
mv project/logs/app.log.gz project/logs/app.log.fast.gz
ls -l project/logs/app.log.max.gz project/logs/app.log.fast.gz

-1 through -9 (default -6) set the compression level: a lower value is faster but compresses less, a higher value is slower but compresses more. The difference is often negligible for small text files, but becomes clear on large log files.

Choosing a Compressor: gzip, bzip2, xz, zstd

gzip is the default, but tar integrates several compressors, each a different point on the speed-versus-ratio curve:

Flag Tool Typical use
-z gzip Fast, universal, the safe default when compatibility matters
-j bzip2 Smaller than gzip but noticeably slower — now largely superseded
-J xz Best ratio of the classic set, slowest and most memory-hungry — good for archives written once and downloaded many times (source tarballs, release artifacts)
--zstd zstd Near-gzip speed with far better ratios and very fast decompression — the modern default where it is installed
tar -cJvf project.tar.xz project          # xz
tar --zstd -cvf project.tar.zst project   # zstd

Extraction mirrors creation (tar -xJf, tar --zstd -xf), but modern GNU tar also auto-detects the compressor on extraction, so a plain tar -xf project.tar.zst usually just works. The rule of thumb: zstd for routine backups where it is available, xz when squeezing the last few percent off a file that will be distributed widely, and gzip when you cannot guarantee the other tools exist on the receiving end.

zip/unzip: A Cross-Platform Alternative

.tar.gz is the standard in the Linux and Unix world, but when an archive needs to go to a Windows user, or when a single file inside an archive needs updating without recompressing everything, the zip format is more convenient.

sudo apt install zip unzip
zip -r project.zip project
unzip -l project.zip
  • -r: add a directory recursively.
  • unzip -l: like tar -tvf, lists contents without extracting.
mkdir extracted-zip
unzip project.zip -d extracted-zip

tar.gz versus zip

Property tar.gz zip
Preserves Unix permissions and ownership Yes, fully Partially, platform-dependent
Native support on Windows No (requires extra software) Yes
Replace one file inside without recompressing everything No — the whole archive must be rebuilt Yes, with zip -u
Common default in the Linux ecosystem Yes (backups, packages, source distribution) Less common, mostly cross-platform cases

For backups and deployments between Linux servers, tar.gz is the usual choice; for sending a file to an external user, especially on Windows, zip is often preferred.

rsync: Incremental Synchronization

tar and zip both produce a single, complete snapshot every time they run — re-archiving a 50 GB directory to update one changed file still reads and repacks the whole thing. rsync solves a different problem: keeping two directory trees (locally, or across the network) in sync by transferring only the differences.

sudo apt install rsync
mkdir -p ~/lab/archive/backup-target
rsync -avz project/ ~/lab/archive/backup-target/
  • -a (archive): a shorthand for "recurse into directories and preserve almost everything that matters for a faithful copy" — permissions, ownership, timestamps, symbolic links, and device files. This is what makes rsync suitable as a backup tool rather than a plain file copy.
  • -v: verbose, listing which files are transferred.
  • -z: compress data during the transfer itself (useful over a network link, less relevant on local disk).

Running the same command a second time, after touching only one file, shows the difference from tar:

echo 'level=WARN message=disk usage high' >> project/logs/app.log
rsync -avz project/ ~/lab/archive/backup-target/
sending incremental file list
project/logs/app.log

sent 1,234 bytes  received 35 bytes  ...

Only app.log is retransferred — rsync compares file size and modification time (and, if needed, file content via a checksum algorithm) on each side, and sends just the changed data. This is the core reason rsync is the standard tool for incremental backups: a nightly backup of a large filesystem takes seconds after the first run, instead of repeating a full copy every time.

Danger

rsync's --delete flag removes files from the destination that no longer exist in the source, which makes a mistyped source or destination path capable of silently deleting backup data. Always check what a sync would do before running it for real:

rsync -avzn --delete project/ ~/lab/archive/backup-target/

-n (also --dry-run) prints exactly what would be transferred and deleted without touching anything. Only drop -n once the dry-run output looks correct, and keep a separate, verified archive (from tar, or a previous rsync run to a different directory) as a rollback path.

The Trailing Slash Matters

rsync -avz project ~/lab/archive/backup-target/
rsync -avz project/ ~/lab/archive/backup-target/

The first command copies the project directory itself into the destination, producing backup-target/project/.... The second, with a trailing slash after project, copies the contents of project directly into the destination, producing backup-target/... with no extra project/ level. This distinction is one of the most common sources of rsync mistakes — always check the resulting path with ls after the first run against a new destination.

rsync versus tar for Backups

Property tar/tar.gz rsync
Transfers only changed data on repeat runs No — rebuilds the whole archive Yes — this is its main purpose
Produces a single portable archive file Yes No — it mirrors a directory tree
Good fit for "point-in-time snapshot to move or store" Yes Less direct (though --link-dest can approximate it)
Good fit for "keep this backup directory current" No — repeats full work each time Yes
Works over the network directly (user@host:/path) Only combined with ssh manually Yes, built in

In practice, many production backup strategies use both: rsync to mirror data efficiently to a backup host or volume, and tar/tar.gz when a single, self-contained archive file needs to be shipped elsewhere or retained as a dated snapshot.

Practical Scenario: Archive, Verify, Retire a Log Directory

Problem: compress project/logs as a backup, confirm the archive is not corrupted, and only then clean up the original logs.

backup_dir=$HOME/lab/archive/backups
mkdir -p "$backup_dir"
stamp=$(date -u +%Y%m%dT%H%M%SZ)
archive="$backup_dir/logs-$stamp.tar.gz"

tar -czf "$archive" -C "$HOME/lab/archive/project" logs

Once the archive exists, verify its integrity without extracting it:

gzip -t "$archive" && echo "gzip integrity OK"
tar -tzf "$archive" > /dev/null && echo "tar structure OK"
  • gzip -t checks compression-level integrity (whether the file is corrupted).
  • tar -tzf ... > /dev/null reads through the archive's internal structure and returns a non-zero status on error.

Only remove the original files once both checks succeed:

if gzip -t "$archive" && tar -tzf "$archive" > /dev/null; then
    echo "archive verified: $archive"
else
    echo "archive is corrupted, original files kept" >&2
    exit 1
fi

Danger

In any script that automatically deletes original files after archiving, verifying the archive's integrity is a required step, not an optional one. A full disk or an interrupted process can leave a half-written archive that gets treated as "successfully created" while the original data has already been removed.

Common Mistakes

  • Assuming tar compresses on its own — a separate flag such as -z (or a standalone compression tool) is always needed.
  • Mixing another flag in after -f (for example, tar -fcv) — -f must be immediately followed by the filename.
  • Extracting an untrusted archive directly instead of inspecting it first with -tvf or unzip -l.
  • Assuming gzip file.log keeps the original file — without -k, the original is replaced by the compressed copy.
  • Deleting original files in a backup script without verifying the archive's integrity first.
  • Sending a .tar.gz to a Windows user with no explanation — it may be harder to open without extra software, which is where zip fits better.

Exercises

  1. Compress the project directory with tar -czvf and compare its size against an uncompressed tar -cvf archive.
  2. Verify the resulting project.tar.gz with -tzf without extracting it, then pull only project/logs/app.log out of it.
  3. Compare the file sizes produced by gzip -k -1 and gzip -k -9, and explain the difference.
  4. Archive project with zip -r, inspect it with unzip -l, then compare its size against the tar.gz version.
  5. Deliberately corrupt a copy of the archive from the scenario above (for example, by truncating its final bytes) and confirm that the verification script correctly detects the problem.

Verification criterion: for each archive, you should be able to explain how you checked its contents before extracting it, and why you chose that particular format (tar.gz or zip).

References

  • GNU tar manual: https://www.gnu.org/software/tar/manual/tar.html
  • GNU tar: integrated compression: https://www.gnu.org/software/tar/manual/html_node/gzip.html
  • GNU Gzip manual: https://www.gnu.org/software/gzip/manual/gzip.html
  • Info-ZIP documentation for zip and unzip: https://infozip.sourceforge.net/
  • POSIX: tar: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/tar.html
  • rsync manual: https://download.samba.org/pub/rsync/rsync.1