How to Create and Extract tar and gz Files in Linux

How to Create and Extract tar and gz Files in Linux

Reading time1 min
#linux#tar#gzip#compression#backup

How to Create and Extract tar and gz Files in Linux

Archiving and compression are two separate jobs on Linux:

  • tar bundles files and directories into one archive and keeps paths, permissions, ownership and timestamps. On its own it does not compress anything.
  • gzip, xz, zstd and bzip2 compress a single file or stream.

A .tar.gz (or .tgz) file is a tar archive that went through gzip. A plain .gz file is one compressed file, not an archive.

Create a tar archive

tar -cf archive.tar my-dir/                   # no compression
tar -czf archive.tar.gz my-dir/               # gzip
tar -cJf archive.tar.xz my-dir/               # xz: smaller, slower
tar --zstd -cf archive.tar.zst my-dir/        # zstd: fast and small
tar -caf archive.tar.zst my-dir/              # -a picks compression from the extension
tar -czf backup.tar.gz notes.txt config/ logs/   # several sources

The letters: c create, f archive file name, z gzip, J xz, j bzip2, v list files as they are processed, a choose compression by extension. f takes the next word as the archive name, so keep it last in the group: -czf name.tar.gz, not -cfz.

--zstd needs GNU tar 1.31 or newer. On older systems such as RHEL 8, use tar -I zstd -cf archive.tar.zst my-dir/.

Use relative paths

sudo tar -czf /backup/my-site-$(date +%F).tar.gz -C /var/www my-site

-C /var/www changes into that directory first, so the archive contains my-site/... instead of the full path. If you pass absolute paths, tar strips the leading / and prints Removing leading '/' from member names, so extraction always lands under the current directory (or the one given with -C).

Exclude files

tar -czf my-app.tar.gz --exclude='node_modules' --exclude='.git' --exclude='*.log' my-app/

Put --exclude options before the paths they should apply to. Newer GNU tar treats them as positional.

Permissions and ownership

tar always stores owner, group and mode. When root extracts an archive, ownership and permissions are restored. When a regular user extracts it, files belong to that user and the umask applies unless you add -p. For system backups add --acls --xattrs (and --selinux on the RHEL family) when those attributes matter, and --numeric-owner when restoring on a machine where user names map to different IDs.

List and extract

tar -tf archive.tar.gz                        # list contents
tar -tvf archive.tar.gz                       # with permissions, owners, sizes
tar -xf archive.tar.gz                        # extract into the current directory
tar -xf archive.tar.gz -C /opt/my-app         # extract into a directory (must exist)
tar -xf archive.tar.gz my-dir/config.yml      # extract a single file
tar -xf my-app-1.4.2.tar.gz --strip-components=1 -C /opt/my-app

GNU tar detects the compression when reading a file, so tar -xf works for .tar.gz, .tar.xz, .tar.bz2 and .tar.zst alike. It still needs the matching program installed (xz, zstd, bzip2). -z on extraction is harmless but unnecessary.

List an archive before extracting one you did not create. Some archives have no top-level directory and spill hundreds of files into the current directory. --strip-components=1 drops the first path component, which is useful for release tarballs that wrap everything in my-app-1.4.2/.

Compress a single file with gzip

gzip access.log                           # creates access.log.gz, deletes the original
gzip -k access.log                        # keep the original
gzip -9 dump.sql                          # best compression (1 fastest, 6 default)
gzip -c dump.sql > /backup/dump.sql.gz    # write to stdout, keep the source
pg_dump my_db | gzip > my_db.sql.gz       # compress a stream

gzip does not handle directories. gzip -r dir/ compresses every file inside separately, which is rarely what you want; use tar -czf for a directory.

Open a .gz file

gunzip access.log.gz                      # restores access.log, deletes the .gz
gzip -dk access.log.gz                    # decompress, keep the .gz
zcat access.log.gz | less                 # read without writing to disk
zless access.log.gz
zgrep 'ERROR' access.log.gz
gzip -l access.log.gz                     # sizes and ratio
gzip -t access.log.gz                     # test integrity

With gzip older than 1.12 (RHEL 8, Ubuntu 22.04), gzip -l shows a wrong uncompressed size for files of 4 GiB or more, because the header stores it modulo 4 GiB. gzip 1.12 and later get the real size by decompressing the file, so -l is slow on big archives.

Other formats

ExtensionDecompressNotes
.gzgunzipavailable everywhere, fast
.bz2bunzip2older, slow, still common
.xzunxzhigh ratio, slow to compress
.zstunzstdfast with a good ratio
.zipunzipbest for sharing with Windows users
.tar.*tar -xfcompression detected automatically

gzip uses one CPU core. For big archives use a multi-threaded compressor:

tar -I 'zstd -T0' -cf backup.tar.zst /srv/data    # zstd on all cores
tar -I pigz -cf backup.tar.gz /srv/data           # parallel gzip, if pigz is installed
xz -T0 big.img                                    # xz on all cores

For zip files (install zip and unzip if missing):

zip -r archive.zip my-dir/
unzip -l archive.zip                      # list
unzip archive.zip -d target/              # extract into target/

Verify, split and encrypt

sha256sum backup.tar.gz > backup.tar.gz.sha256
sha256sum -c backup.tar.gz.sha256
tar -tzf backup.tar.gz > /dev/null && echo OK      # reads the whole archive

split -b 1G backup.tar.gz backup.tar.gz.part-       # 1 GiB pieces
cat backup.tar.gz.part-* > backup.tar.gz            # join them again

gpg --symmetric --cipher-algo AES256 backup.tar.gz  # creates backup.tar.gz.gpg
gpg -o backup.tar.gz -d backup.tar.gz.gpg

Listing the archive with tar -t reads it end to end, so a truncated upload or a broken disk shows up as an error before you need the backup.

Quick reference

tar -czf out.tar.gz dir/              # create gzip archive
tar -cJf out.tar.xz dir/              # create xz archive
tar --zstd -cf out.tar.zst dir/       # create zstd archive
tar -czf out.tar.gz -C /path dir      # store relative paths
tar -tf archive.tar.gz                # list
tar -xf archive.tar.gz                # extract here
tar -xf archive.tar.gz -C /target     # extract elsewhere
gzip -k file                          # compress, keep original
gunzip file.gz                        # decompress
zcat file.gz | less                   # read compressed text
unzip archive.zip -d target/          # zip files