Create and Safely Unpack Archives with GNU tar
One careless tar extraction can scatter files across your home directory or quietly overwrite the ones you needed. In about 15 minutes you will create a compressed archive, check what is inside, unpack it somewhere safe and prove the copy matches.
The route
Jump straight to the step you need, or tick off Done means at the end.
The examples use GNU tar 1.35 from the tar package. You need:
- A shell. Nothing fancy.
- A directory you can read. Ordinary files under your home directory need no elevated privileges.
- Enough free space for both the archive and its extraction.
Use sudo only when the source or destination genuinely belongs to another user or is a protected system location.
1. Pick the archive and source
Set the two paths, then look at the source before you archive it.
source_dir="$HOME/project"
archive="$HOME/project-2026-09-27.tar.gz"
test -d "$source_dir" && printf 'Source: %s\n' "$source_dir"
du -sh "$source_dir"
- The
.tar.gzsuffix is two facts..taris the archive format;.gzis gzip compression. - Tar will not guess the source. It does not infer a directory from the archive name, so keep the input path explicit.
- Quote the variables. That protects spaces and shell metacharacters in a path.
2. Create a compressed archive
Create it from the parent directory so every member has a predictable top-level name.
tar --create --gzip --file="$archive" \
--directory="$(dirname -- "$source_dir")" \
"$(basename -- "$source_dir")"
--createselects archive creation.--gzipsends the archive through gzip.--filenames the output.--directoryis order-sensitive. It changes directory before the following source name is processed. That avoids recording an absolute path, so the archive unpacks asproject/...rather than embedding your full home-directory path.
Tip
For another compressor, match the option to the suffix: --bzip2 for .bz2, --xz for .xz, or --zstd for .zst, provided the program is installed. The installed man page also documents --auto-compress, which picks compression from the suffix. Never combine several compression options.
Check the output exists and is not empty:
test -s "$archive" && ls -lh -- "$archive"
3. Inspect before you extract
Listing writes nothing to disk. Extraction is the step that changes things, so look first.
tar --list --gzip --file="$archive"
Checkpoint
You should see names such as project/ and project/readme.txt.
Treat this list as a safety review. Look for:
- Absolute paths you did not expect.
- Parent-directory components such as
../. - Device nodes.
- Anything that would overwrite valuable data.
For a large archive, save the list instead of scrolling past it:
tar --list --gzip --file="$archive" > /tmp/project-tar-members.txt
sed -n '1,40p' /tmp/project-tar-members.txt
Warning
An archive from an untrusted source is not safe just because it lists neatly. Tar can contain symbolic links, hard links and special files. Extract unknown archives into a new directory as an ordinary user, never into /, a home directory holding live data, or a service's working directory.
4. Extract into an empty destination
Only once the member list looks right, create a destination and unpack into it.
destination="$HOME/tmp/project-unpacked"
mkdir -p -- "$destination"
tar --extract --gzip --file="$archive" --directory="$destination"
find "$destination" -maxdepth 3 -type f -print
Tar normally extracts as the current user. Run it as root and GNU tar's defaults change: the superuser may restore recorded ownership and permissions. Prefer a non-privileged destination. If you must use sudo, inspect first and name the destination explicitly:
sudo tar --extract --gzip --file="$archive" --directory="/srv/example"
Warning
That command changes files under /srv/example. Stop if the directory holds files that must not be replaced. Add --keep-old-files to avoid overwriting: tar then reports an error for any member whose destination already exists.
Recovery
Tar has no general undo. If extraction created an unwanted directory, check its path carefully and remove only that directory, with a file manager or a reviewed command.
5. Verify the result
Compare the archive members with the extracted files:
tar --diff --gzip --file="$archive" --directory="$destination" project
Checkpoint
A clean comparison normally prints nothing and exits with status 0.
In a script, check the status straight away:
if tar --diff --gzip --file="$archive" --directory="$destination" project; then
printf '%s\n' 'Archive and extracted files match.'
else
status=$?
printf 'tar comparison failed with status %s\n' "$status" >&2
exit "$status"
fi
- Status 1 from
--diffmeans files differ. - Status 2 means a fatal error.
- Other non-zero statuses can come from an external compressor.
Recovery
If files differ, do not delete the destination straight away. Keep it for inspection, compare timestamps and permissions, and extract again into a fresh directory if you need a clean retry.
Common traps
- Extract one member. Put its exact name after the archive options:
tar --extract --gzip --file="$archive" --directory="$destination" project/readme.txt. - Strip leading path components.
--strip-components=1does it, but review the resulting paths first: it changes where every selected member lands. - Skip build output or caches. Use a checked glob such as
--exclude='project/.cache'. Exclusion patterns are glob-style and path matching can surprise you, so list the result afterwards. - Do not drop
--directorycasually mid-command. It affects the options and file names that follow it, not necessarily everything on the line. - Filenames starting with a dash. Use
--add-file=./-noteswhen creating an archive, or the name can be read as a tar option. --appendis not for compressed archives. It changes an existing uncompressed archive only.--updatedoes not replace. It appends newer files, so one archive can hold several versions of the same name. For a clean, predictable backup, create a new archive instead of relying on either operation.
Tip
The local tar(1) page is the authority for the GNU tar 1.35 behaviour used here. For the full reference, see the GNU Tar manual.
Done means
- The archive exists and uses the compression you intended.
tar --listwas reviewed and showed only expected member paths.- Extraction went to a deliberate destination, without unnecessary privileges.
tar --diffreturned 0, or any difference was investigated and kept for recovery.