📦 zip Command Examples

Comprehensive guide to creating and managing ZIP archives in Linux

Overview

The zip command is a compression and file packaging utility that creates archives compatible across multiple platforms including Linux, Windows, and macOS. Unlike tar, zip combines archiving and compression in a single step and provides built-in encryption capabilities. It's the standard for cross-platform file distribution and supports various compression levels, encryption methods, and archive management operations.

Example 1: Basic Archive Creation

Creating a simple ZIP archive from files and directories.

$ zip myarchive.zip file1.txt file2.txt file3.txt
adding: file1.txt (deflated 45%) adding: file2.txt (deflated 52%) adding: file3.txt (deflated 38%)

Explanation:

Basic syntax: The most straightforward use of zip - creating an archive from specified files. The percentages show compression ratios.

Archive naming: If the .zip extension is omitted, zip will add it automatically. Archives are created in the current directory unless a path is specified.

Compression method: By default, zip uses deflate compression, which provides a good balance between speed and compression ratio.

Tip: You can verify archive contents without extracting using unzip -l myarchive.zip or zipinfo myarchive.zip.

Example 2: Recursive Directory Archiving

Creating an archive that includes entire directory structures.

$ zip -r project-backup.zip /home/craig/project/
adding: home/craig/project/ (stored 0%) adding: home/craig/project/src/ (stored 0%) adding: home/craig/project/src/main.c (deflated 63%) adding: home/craig/project/src/utils.c (deflated 58%) adding: home/craig/project/docs/ (stored 0%) adding: home/craig/project/docs/README.md (deflated 51%) adding: home/craig/project/Makefile (deflated 42%)

Explanation:

-r flag (recursive): Essential for archiving directories. Without this flag, zip only archives the directory entry itself, not its contents.

Path preservation: The archive maintains the full path structure from where you run the command. To avoid deep paths, cd into the parent directory first.

Stored vs deflated: Empty directories show "stored 0%" because there's nothing to compress. Files show their actual compression ratio.

# Alternative: Archive without full paths $ cd /home/craig $ zip -r project-backup.zip project/
Note: When archiving directories, the trailing slash in the path is optional but including it can make your intent clearer.

Example 3: Compression Level Control

Adjusting compression levels to balance speed versus file size.

# Maximum compression (slowest, smallest) $ zip -9 high-compression.zip large-database.sql # Fast compression (faster, larger) $ zip -1 quick-backup.zip *.log # Store only (no compression, fastest) $ zip -0 no-compression.zip already-compressed.mp4 # Default compression (balanced) $ zip regular.zip documents/*.txt
# -9 output: adding: large-database.sql (deflated 87%) # -1 output: adding: access.log (deflated 45%) adding: error.log (deflated 38%) # -0 output: adding: already-compressed.mp4 (stored 0%)

Explanation:

Compression levels: Range from -0 (no compression) to -9 (maximum compression). Default is -6 if not specified.

-0 (store only): Useful for already-compressed files (jpg, mp4, gz) where additional compression provides minimal benefit and wastes CPU time.

-1 (fast): Good for quick backups where speed matters more than size, or when you'll decompress frequently.

-9 (best): Ideal for archival storage or distribution where you compress once and decompress many times.

-0

Store only, no compression

-1

Fastest compression

-6

Default balanced compression

-9

Maximum compression

Tip: For mixed content archives, use -9. The zip format stores compression per-file, so already-compressed files won't be penalized.

Example 4: Password-Protected Archives

Creating encrypted archives with password protection.

# Basic password protection (will prompt) $ zip -e secure-docs.zip confidential/*.pdf # Password on command line (less secure, visible in history) $ zip -P MyPassword secure-backup.zip sensitive-data.txt # Encrypt with maximum compression $ zip -9 -e financial-records.zip taxes/*.pdf statements/*.csv
Enter password: Verify password: adding: confidential/report.pdf (deflated 12%) adding: confidential/contract.pdf (deflated 8%) adding: confidential/invoice.pdf (deflated 15%)

Explanation:

-e flag (encrypt): Prompts for a password interactively, which is more secure than using -P as the password won't appear in shell history.

-P flag: Allows specifying password directly on command line. Convenient for scripts but less secure - avoid for sensitive data.

Encryption method: Standard zip uses ZipCrypto encryption. For stronger security, use 7zip or GPG encryption instead.

Filenames visible: Zip encryption only encrypts file contents, not filenames. File and directory names remain visible in the archive listing.

Security Warning: Standard zip encryption (ZipCrypto) is relatively weak and vulnerable to known attacks. For truly sensitive data, consider using GPG encryption or 7zip with AES-256 encryption instead.
# Better security with 7zip (if available) $ 7z a -p -mhe=on -tzip secure.zip sensitive-files/ # -mhe=on encrypts headers (filenames)

Example 5: Excluding Files and Patterns

Selective archiving by excluding specific files or patterns.

# Exclude specific file patterns $ zip -r project.zip myproject/ -x "*.o" "*.tmp" "*~" # Exclude entire directories $ zip -r source-code.zip app/ -x "*/node_modules/*" "*/\.git/*" "*/__pycache__/*" # Exclude multiple patterns $ zip -r backup.zip /var/www/ -x "*.log" "*/cache/*" "*/tmp/*" "*.bak" # Combine with other options $ zip -9 -r clean-backup.zip project/ -x "*/.git/*" "*/build/*" "*.pyc"
adding: myproject/ (stored 0%) adding: myproject/src/ (stored 0%) adding: myproject/src/main.c (deflated 58%) adding: myproject/src/utils.c (deflated 62%) adding: myproject/Makefile (deflated 45%) (excluding: myproject/build/main.o) (excluding: myproject/src/test.tmp)

Explanation:

-x flag: Must come after all files/directories to include. Everything after -x is treated as an exclusion pattern.

Pattern syntax: Uses shell globbing patterns. Wildcards (* and ?) work as expected. Patterns are relative to archive paths, not filesystem paths.

Directory exclusion: Use "*/dirname/*" pattern to exclude a directory anywhere in the tree. The leading */ ensures it matches at any level.

Hidden files: Remember to escape the dot in patterns like "*/\.git/*" to exclude version control directories.

Tip: For complex exclusion patterns, create a script or use find with zip to have more control over what gets included.
# Advanced: Use find to create precise file list $ find project/ -type f ! -name "*.log" ! -path "*/node_modules/*" | zip -@ project.zip # -@ reads file list from stdin

Example 6: Updating and Adding to Existing Archives

Modifying existing archives by updating or adding new files.

# Add new files to existing archive $ zip existing-archive.zip newfile1.txt newfile2.txt # Update files that have changed $ zip -u backup.zip modified-file.txt updated-doc.pdf # Freshen only (update existing files, don't add new ones) $ zip -f archive.zip changed-file.txt # Delete files from archive $ zip -d archive.zip obsolete-file.txt "old-dir/*"
# Adding new files: adding: newfile1.txt (deflated 48%) adding: newfile2.txt (deflated 52%) # Updating changed files: updating: modified-file.txt (deflated 55%) updating: updated-doc.pdf (deflated 8%) # Deleting files: deleting: obsolete-file.txt deleting: old-dir/file1.txt deleting: old-dir/file2.txt

Explanation:

Default behavior: Simply running zip on an existing archive adds new files without checking if files already exist (can create duplicates).

-u (update): Adds new files and updates existing files that have newer modification times. Safer than default for backups.

-f (freshen): Only updates files already in the archive, never adds new files. Useful for updating specific documents in a release archive.

-d (delete): Removes files from the archive. Accepts patterns to delete multiple files matching criteria.

Note: Update operations (-u and -f) compare file modification times. Ensure your system clock is accurate for reliable updates.
# Safe incremental backup strategy $ zip -u -9 daily-backup.zip /home/craig/documents/ # Move updated files into archive then delete originals $ zip -m archive.zip newly-processed/*.dat # -m removes files after successful archiving

Example 7: Splitting Large Archives

Creating split archives for size-limited transfers or storage.

# Split into 100MB chunks $ zip -s 100m -r large-archive.zip /var/backup/database/ # Split into 700MB chunks (CD-sized) $ zip -s 700m -r distribution.zip software/ # Split into 4.7GB chunks (DVD-sized) $ zip -s 4700m -r video-archive.zip videos/ # Split using different size units $ zip -s 50k small-splits.zip files/ # 50 kilobytes $ zip -s 2g huge-archive.zip data/ # 2 gigabytes
adding: var/backup/database/ (stored 0%) adding: var/backup/database/db1.sql (deflated 78%) adding: var/backup/database/db2.sql (deflated 81%) creating: large-archive.z01 (100.0 MB) creating: large-archive.z02 (100.0 MB) creating: large-archive.z03 (100.0 MB) creating: large-archive.zip (45.3 MB)

Explanation:

-s flag (split): Creates a split archive with specified maximum segment size. Produces numbered segments (.z01, .z02, etc.) with final segment as .zip.

Size units: Accepts k (kilobytes), m (megabytes), g (gigabytes), or t (terabytes). Default is bytes if no unit specified.

Extraction requirement: All segments must be present in the same directory to extract. Missing any segment makes the entire archive unusable.

Use cases: Transferring large files via email size limits, burning to optical media, or uploading to services with file size restrictions.

Warning: Split archives must be kept together. If you lose even one segment, the entire archive becomes unrecoverable.
# Extract split archive (all segments must be present) $ unzip large-archive.zip # Convert split archive to single archive $ zip -s 0 large-archive.zip --out single-archive.zip # -s 0 = no splitting
Tip: For large backups, consider using tar with compression and splitting separately, or modern tools like 7zip which offer better compression and recovery records.

Example 8: Verbose and Quiet Modes

Controlling output verbosity for different scenarios.

# Quiet mode (minimal output) $ zip -q -r backup.zip /home/craig/documents/ # Very quiet (no output except errors) $ zip -qq -r silent-backup.zip /var/logs/ # Verbose mode (detailed information) $ zip -v -r detailed.zip project/ # Show compression statistics $ zip -v -9 -r compressed.zip large-files/
# Quiet mode output: (no output unless errors occur) # Verbose mode output: adding: project/README.md (in=2543) (out=1234) (deflated 51%) adding: project/src/main.c (in=15678) (out=6543) (deflated 58%) adding: project/Makefile (in=456) (out=234) (deflated 48%) Total bytes=18677, compressed=8011 -> 57% savings

Explanation:

-q flag (quiet): Suppresses normal progress output. Useful in scripts and cron jobs where you only want to log errors.

-qq (very quiet): Completely silent except for critical errors. Perfect for automated backups where output goes to logs.

-v (verbose): Shows detailed information including original size, compressed size, and compression ratio for each file.

Statistics summary: Verbose mode includes overall compression statistics at the end showing total space savings.

# Scripting example with error checking #!/bin/bash if zip -qq -r backup-$(date +%Y%m%d).zip /home/craig/; then echo "Backup successful" else echo "Backup failed!" >&2 exit 1 fi # Verbose for troubleshooting $ zip -v -r debug-archive.zip problematic-files/ 2>&1 | tee zip-debug.log
Tip: Use -q in cron jobs to avoid email clutter, but ensure error output is still logged for troubleshooting.

Example 9: Preserving Symbolic Links and Permissions

Handling special file types and maintaining file attributes.

# Store symbolic links as links (not their targets) $ zip -ry project.zip project/ # Include hidden files and follow symlinks $ zip -r backup.zip /home/craig/ # Preserve Unix permissions and ownership $ zip -r -X system-backup.zip /etc/ # Don't include extra file attributes $ zip -r -X minimal.zip files/
adding: project/bin/script -> ../scripts/main.sh (stored 0%) adding: project/lib/libfoo.so -> libfoo.so.1.2.3 (stored 0%) adding: project/config (deflated 45%) Archive includes symbolic links and permissions

Explanation:

-y flag (symlinks): Stores symbolic links as links rather than following them and archiving their targets. Important for preserving system structure.

Default symlink behavior: Without -y, zip follows symlinks and archives the target files, which can duplicate data and break link relationships.

-X flag (no extras): Excludes extra file attributes like uid/gid and timestamps. Creates more portable archives but loses permission information.

Permission preservation: By default, zip preserves Unix permissions. When extracted on Unix systems, original permissions are restored (subject to umask).

Warning: Archives containing symbolic links may not extract properly on Windows systems, as Windows has different symlink semantics and restrictions.
# Backup system configuration with permissions $ sudo zip -ry system-config.zip /etc/apache2/ /etc/nginx/ # Create portable archive without Unix-specific attributes $ zip -r -X portable.zip documents/ # Archive with Unix attributes for Linux-to-Linux transfer $ zip -r linux-backup.zip /home/craig/.config/
Note: When archiving as root, be careful about preserving ownership. The -X flag prevents storing uid/gid, which may be desirable for portability.

Example 10: Advanced Options and Testing

Additional useful features for reliability and troubleshooting.

# Test archive integrity $ zip -T archive.zip # Create with test after creation $ zip -r -T important-backup.zip /data/ # Adjust compression method $ zip -Z bzip2 archive.zip files/* $ zip -Z store archive.zip already-compressed.mp4 # Show what would be done (dry run) $ zip -r project.zip code/ -v | grep "would add" # Repair corrupted archive $ zip -F broken-archive.zip --out repaired.zip $ zip -FF badly-broken.zip --out salvaged.zip
# Test output: test of archive.zip OK # Repair output: Fix archive (-F) - salvage what can copying: file1.txt copying: file2.txt Could not find: corrupted-entry.dat Archive repaired: 2 entries recovered, 1 lost

Explanation:

-T (test): Verifies archive integrity by attempting to decompress all entries. Essential for validating backups before trusting them.

-Z (compression method): Allows selecting alternative compression methods like bzip2 for better compression or store for speed.

-F (fix): Attempts to repair a corrupted archive by salvaging readable entries. Creates a new archive with recovered data.

-FF (fix harder): More aggressive repair mode that tries to recover from severe corruption. May take longer but can salvage more data.

# Comprehensive backup with verification $ zip -9 -r -T critical-backup-$(date +%Y%m%d).zip /home/craig/important/ $ zipinfo critical-backup-*.zip | grep -E "^-.*" | wc -l # Count files in archive # Script to verify all archives in directory for archive in *.zip; do echo -n "Testing $archive... " if zip -T "$archive" > /dev/null 2>&1; then echo "OK" else echo "FAILED" fi done
-T

Test archive integrity

-F

Repair corrupted archive

-FF

Aggressive repair mode

-Z

Select compression method

Best Practice: Always test critical archives immediately after creation. A corrupted backup discovered during restoration is useless.
Warning: Archive repair (-F/-FF) is a last resort. It may recover some files but cannot guarantee complete data recovery. Always maintain multiple backup copies.

💡 Best Practices for ZIP Archives:

  • Test backups regularly: Use -T flag to verify archive integrity immediately after creation
  • Choose appropriate compression: Use -9 for archival, -1 for temporary files, -0 for already-compressed content
  • Document your passwords: Store encryption passwords securely (password manager) - lost passwords mean lost data
  • Avoid deep directory paths: cd into the parent directory before archiving to create cleaner archives
  • Use exclusions wisely: Exclude cache directories, build artifacts, and temporary files to reduce archive size
  • Consider alternatives for large data: For multi-gigabyte archives, tar+compression may be more efficient
  • Maintain multiple copies: Keep 3-2-1 backup strategy - 3 copies, 2 different media, 1 offsite
  • Name archives descriptively: Include dates and content descriptions in filenames (backup-2025-11-29-home.zip)

âš¡ Common ZIP Scenarios for System Administrators:

  • Log rotation archival: zip -9 -q logs-$(date +%Y%m%d).zip /var/log/*.log
  • Configuration backup: sudo zip -ry etc-backup.zip /etc/
  • Web content distribution: zip -r -9 -x "*/\.git/*" website.zip public_html/
  • User home backup: zip -r -y home-backup.zip /home/username/
  • Database dump archiving: zip -9 db-$(date +%Y%m%d).zip database-dump.sql
  • Incremental updates: zip -u daily-backup.zip changed-files/