Backing up a project directory, sending a batch of log files to a colleague, or shrinking a folder before uploading it somewhere with limited bandwidth — all of these tasks come back to the same core skill: archiving and compressing files from the command line. I still remember mixing up “archiving” and “compressing” as one and the same thing when I started, so let’s clear that up first before getting into the practical commands.
In this guide, I’ll walk through the tools Bash users rely on most — tar, gzip, bzip2, xz, and zip — with real examples, explanations of what each flag does, and the situations where you’d reach for one tool over another.
Archiving vs. Compressing: What’s the Difference?
- Archiving combines multiple files and directories into a single file, preserving structure and metadata (permissions, timestamps, etc.). It does not necessarily make the file smaller.
- Compressing reduces the size of a file (or archive) by encoding the data more efficiently.
In practice, these two steps are often combined in one command — you archive a directory into a single .tar file, then compress that file, resulting in something like .tar.gz.
The tar Command
tar (short for “tape archive”) is the standard tool for archiving in Linux and Unix-like systems.
Creating an Archive
tar -cvf archive.tar myfolder/
Breaking down the flags:
-c— create a new archive.-v— verbose, prints each file as it’s added, so you can see progress.-f— specifies the filename of the archive that follows.
Extracting an Archive
tar -xvf archive.tar
-x— extract files from the archive.
Listing Contents Without Extracting
tar -tvf archive.tar
-t— list the table of contents.
Combining tar With Compression
This is where things get useful. tar itself doesn’t compress data, but it can pipe its output through a compression tool automatically using extra flags.
Gzip Compression (.tar.gz)
tar -czvf archive.tar.gz myfolder/
-z— compress the archive using gzip.
To extract:
tar -xzvf archive.tar.gz
Gzip is fast and widely supported, making .tar.gz (sometimes shortened to .tgz) the most common archive format on Linux systems.
Bzip2 Compression (.tar.bz2)
tar -cjvf archive.tar.bz2 myfolder/
-j— compress using bzip2.
Bzip2 typically compresses better than gzip but is slower. Extract with:
tar -xjvf archive.tar.bz2
XZ Compression (.tar.xz)
tar -cJvf archive.tar.xz myfolder/
-J— compress using xz.
XZ usually achieves the best compression ratio of the three but takes the longest to compress. Extract with:
tar -xJvf archive.tar.xz
Choosing the Right Compression
| Format | Speed | Compression Ratio | Best For |
|---|---|---|---|
| gzip (.gz) | Fast | Moderate | General everyday use |
| bzip2 (.bz2) | Slower | Better | Larger files where size matters more than speed |
| xz (.xz) | Slowest | Best | Long-term archives, distribution packages |
Extracting to a Specific Directory
tar -xzvf archive.tar.gz -C /path/to/destination
-C— changes to the specified directory before extracting, so files land exactly where you want them instead of the current directory.
Compressing a Single File (Without tar)
If you just need to compress one file rather than a whole directory, you don’t need tar at all.
gzip myfile.txt
This compresses myfile.txt into myfile.txt.gz and removes the original file. To decompress:
gunzip myfile.txt.gz
If you want to keep the original file intact while creating the compressed copy:
gzip -k myfile.txt
-k— keep the original file after compression.
Working With ZIP Archives
ZIP is more universally recognized on Windows and macOS, so I reach for it when sharing archives across platforms.
Creating a ZIP Archive
zip -r archive.zip myfolder/
-r— recursive, includes all files and subdirectories.
Extracting a ZIP Archive
unzip archive.zip
Extracting to a Specific Directory
unzip archive.zip -d /path/to/destination
Listing Contents Without Extracting
unzip -l archive.zip
Excluding Files While Archiving
Sometimes you don’t want everything in a directory included — like .git folders or node_modules. Use --exclude:
tar --exclude='node_modules' --exclude='.git' -czvf archive.tar.gz myproject/
This creates a compressed archive of myproject/ while skipping the specified directories entirely, keeping the archive lean.
Checking Compression Ratios
To compare how much space you actually saved:
ls -lh myfolder.tar.gz
du -sh myfolder/
du -sh shows the original folder size in human-readable form, while ls -lh on the archive shows the compressed size, so you can quickly see the ratio.
Automating Backups With a Script
Here’s a simple backup script I use for a project directory, timestamped so I don’t overwrite previous backups:
#!/bin/bash
SOURCE_DIR="/home/user/projects/myapp"
BACKUP_DIR="/home/user/backups"
TIMESTAMP=$(date +"%Y%m%d_%H%M%S")
BACKUP_FILE="$BACKUP_DIR/myapp_backup_$TIMESTAMP.tar.gz"
mkdir -p "$BACKUP_DIR"
tar --exclude='node_modules' --exclude='.git' -czvf "$BACKUP_FILE" "$SOURCE_DIR"
echo "Backup created at $BACKUP_FILE"
How this works internally:
date +"%Y%m%d_%H%M%S"generates a timestamp string like20260728_143210, ensuring each backup filename is unique.mkdir -pcreates the backup directory if it doesn’t already exist, without throwing an error if it does.tararchives and compresses the source directory, excluding heavy or unnecessary folders.- The final
echoconfirms where the backup landed, which is useful if this script runs unattended via cron and you’re checking logs later.
You could schedule this with crontab -e to run nightly, giving you automated, timestamped backups with zero manual effort.
Real-World Use Cases
- Log rotation: Compressing old log files (
app.log.1.gz,app.log.2.gz) to save disk space while keeping historical records accessible. - Deployment packages: Bundling application code into a
.tar.gzbefore shipping it to a server. - Data transfer: Compressing large datasets before transferring them over a network to reduce transfer time.
- Website backups: Archiving an entire website directory alongside a database dump before making major changes, so you have a rollback point.
Best Practices
- Always verify an archive after creating it (
tar -tvf archive.tar.gz) before deleting the original files, especially for backups. - Use
.tar.gzfor general-purpose archiving unless you have a specific reason to use.bz2or.xz. - Exclude unnecessary directories (like
node_modules,.git, or cache folders) to keep archives small and fast to create. - Include timestamps in backup filenames to avoid accidentally overwriting previous backups.
- For very large archives, consider splitting them using
splitif you need to transfer over a medium with size limits.
Security Considerations
- Be cautious extracting archives from untrusted sources — a maliciously crafted archive can contain files with paths designed to overwrite system files (a “zip slip” style attack). Always inspect contents first with
-tor-lbefore extracting. - Set correct permissions on backup archives containing sensitive data, since anyone with read access to the archive can extract everything inside it.
- Encrypt sensitive backups using tools like
gpgin combination withtar, for example:tar -czf - myfolder/ | gpg -c > archive.tar.gz.gpg.
Optimization Tips
- For very large datasets, consider using
pigz(parallel gzip) instead of standardgzipto take advantage of multiple CPU cores and speed up compression significantly. - If compression speed matters more than ratio, stick with gzip; if storage space matters more, use xz despite the extra time.
- Avoid compressing already-compressed files (like
.jpg,.mp4, or.zipfiles) inside atar.gz— you’ll get little to no additional size reduction and waste CPU time.
Troubleshooting Common Issues
“tar: Error is not recoverable: exiting now”: Usually caused by a corrupted archive or incorrect flags. Double-check the file isn’t truncated by verifying its size matches expectations.
“gzip: stdin: not in gzip format”: You’re likely trying to decompress a file that isn’t actually gzip-compressed, or the file extension doesn’t match its real format.
Extraction overwrites existing files without warning: Use the -k flag with gunzip, or check flags for your specific tool that prevent overwriting, and always test extraction into a temporary directory first when unsure.
Archive is much larger than expected: Check whether you’re including directories you meant to exclude, like node_modules or build artifacts.
Frequently Asked Questions
Which is better, tar.gz or zip? For Linux/Unix environments, tar.gz is generally preferred because it preserves permissions and symbolic links better. Zip is more portable across Windows and macOS.
Can I add files to an existing tar archive without recreating it? Yes, using tar -rvf archive.tar newfile.txt, though this only works with uncompressed .tar files, not .tar.gz.
How do I compress a directory without archiving it into one file? You can compress individual files in place with gzip, but for a whole directory structure, archiving into a single file first (with tar) is the standard approach.
Is xz always better than gzip? Not always — it compresses better but takes significantly longer, so for quick, frequent backups gzip is often the more practical choice.
Common Mistakes to Avoid
- Confusing the order of flags, which can cause
tarto interpret them incorrectly (though modern versions are fairly forgiving). - Extracting an untrusted archive directly into a system directory without inspecting its contents first.
- Forgetting
--excludewhen archiving project directories, resulting in bloated backups full of dependencies that can be reinstalled anyway. - Not testing whether an archive is valid before deleting the source files it was meant to back up.
Summary
Archiving and compressing files in Bash comes down to a small set of reliable tools: tar for combining files, and gzip, bzip2, or xz for shrinking them. Once you understand the difference between archiving and compressing, and know which compression format fits your situation, you can build reliable backup scripts, ship deployment packages, and manage disk space efficiently — all from the command line.
References
- GNU Tar Manual: https://www.gnu.org/software/tar/manual/tar.html
- GNU Gzip Manual: https://www.gnu.org/software/gzip/manual/gzip.html
