Pack and Unpack Archives
Problem statement
Pack a folder into one compressed .tar.gz file, look inside it, unpack it somewhere else, and compress a single file with gzip. You use this to send logs to a teammate, back up a config folder before a change, ship a build, and read old rotated logs that end in .gz.
The script creates:
logs/access.log
GET /home 200GET /cart 200logs/error.log
db timeoutnotes.txt
deploy went fineDo these steps in order:
- Pack the
logsfolder intologs.tar.gz. - List what is inside the archive without unpacking it.
- Unpack it into a folder called
restore, list the files there, and printerror.log. - Compress
notes.txtwithgzip, keeping the original, list both files, and read the compressed one without unpacking it.
Expected output:
== inside logs.tar.gz ==logs/logs/access.loglogs/error.log== unpacked files ==restore/logs/access.logrestore/logs/error.log== restore/logs/error.log ==db timeout== notes files ==notes.txtnotes.txt.gz== read the .gz without unpacking ==deploy went fineHints
tar flags as words: c create, t list, x extract, z gzip, f "the archive file name comes next".Approach
Optimal: tar and gzip
Covers: tar -czf, tar -tzf, tar -xzf, tar -C, gzip, gzip -k, gunzip, zcat.
Two jobs, two tools. Packing a folder is really two separate steps, and Linux uses a separate tool for each:
tarbundles many files and folders into one file, keeping names, folders and permissions. It does not shrink anything on its own. A plain bundle ends in.tar.gzipshrinks one file. It cannot bundle a folder. A compressed file ends in.gz.
Put together, you get a .tar.gz (also written .tgz): a bundle that has been shrunk. The z flag tells tar to run gzip for you, so it is still one command.
split the bundle"]):::purple --> R["restore/logs/"]:::blue end PACK ~~~ UNPACK classDef blue fill:#dbeafe,stroke:#2563eb,color:#1e3a8a,stroke-width:2px classDef yellow fill:#fef3c7,stroke:#d97706,color:#78350f,stroke-width:2px classDef green fill:#d1fae5,stroke:#059669,color:#064e3b,stroke-width:2px classDef red fill:#fee2e2,stroke:#dc2626,color:#7f1d1d,stroke-width:2px classDef purple fill:#ede9fe,stroke:#7c3aed,color:#4c1d95,stroke-width:2px classDef gray fill:#f3f4f6,stroke:#6b7280,color:#111827,stroke-width:2px linkStyle default stroke:#94a3b8,stroke-width:2px style PACK fill:transparent,stroke:#2563eb,stroke-width:2px style UNPACK fill:transparent,stroke:#059669,stroke-width:2px
Read the flags as words. Most people only need these:
| Flag | Word | Meaning |
|---|---|---|
c |
create | make a new archive |
t |
table | list what is inside |
x |
extract | unpack |
z |
gzip | compress or decompress with gzip |
f |
file | the archive name is the next word |
v |
verbose | print each file as it goes |
-C dir |
change dir | go into dir before unpacking |
So tar -czf logs.tar.gz logs reads as "create, gzip, file named logs.tar.gz, from the folder logs". tar -xzf logs.tar.gz -C restore reads as "extract, gzip, file named logs.tar.gz, into restore".
f must come last in the group. f takes the next word as the archive name. In -czf logs.tar.gz, the next word is logs.tar.gz, which is right. If you write -cfz logs.tar.gz, the next word after f is z, and tar tries to make an archive called z.
gzip on a single file. gzip notes.txt replaces the file with notes.txt.gz. gzip -k notes.txt keeps the original too. gunzip notes.txt.gz (or gzip -d) turns it back. zcat notes.txt.gz prints the content without unpacking anything, which is how you read old rotated logs like syslog.2.gz. zgrep searches inside them the same way.
Walking through the code. The # Setup: lines only create the sample files, so skip past them.
tar -czf logs.tar.gz logspacks the folder.tar -tzf logs.tar.gzlists the contents, andlogs/with a slash is the folder itself.tarstores files in whatever order the disk gives them, sosortmakes the list stable.mkdir restorecomes first, because-Cneeds the folder to exist.tar -xzf ... -C restoreunpacks there, so the files land inrestore/logs/.find restore -type f | sortlists the files.gzip -k notes.txtmakesnotes.txt.gzand keepsnotes.txt.ls -1 notes.txt*shows both, andzcatreads the compressed one.
Always list before you unpack. tar -xzf unpacks into the current folder and overwrites any files with the same names, without asking. Running tar -tzf first shows you what will appear and where. This is extra important for archives from someone else.
Edge cases. An empty folder still packs fine, and the archive holds just the folder entry. If the archive name is wrong, tar stops with "Cannot open: No such file or directory". gzip refuses to compress a file that already ends in .gz.
# Setup: a logs folder with two files, plus a notes file
cd "$(mktemp -d)"
mkdir logs
printf 'GET /home 200\nGET /cart 200\n' > logs/access.log
printf 'db timeout\n' > logs/error.log
printf 'deploy went fine\n' > notes.txt
# 1. Pack: c = create, z = gzip it, f = the archive file name comes next
tar -czf logs.tar.gz logs
# 2. Look inside without unpacking: t = list
echo "== inside logs.tar.gz =="
tar -tzf logs.tar.gz | sort
# 3. Unpack into another folder: x = extract, -C = go to this folder first
mkdir restore
tar -xzf logs.tar.gz -C restore
echo "== unpacked files =="
find restore -type f | sort
echo "== restore/logs/error.log =="
cat restore/logs/error.log
# 4. gzip one file; -k keeps the original next to the .gz
gzip -k notes.txt
echo "== notes files =="
ls -1 notes.txt*
echo "== read the .gz without unpacking =="
zcat notes.txt.gzInterview follow-ups
How do you archive only the log files that changed in the last day?
Let
findchoose the files and hand the list totar.find logs -name '*.log' -mtime -1 -print0 | tar --null -czf recent.tar.gz -T -does it.-mtime -1means "changed less than a day ago".-print0ends each name with a special null character, and--null -T -tells tar to read that list from the pipe. Using null characters keeps names with spaces safe. These flags are GNU tar, which is the tar on almost every Linux server.
Frequently asked questions
You packed an absolute path, like tar -czf etc.tar.gz /etc. tar strips the leading /, so the archive holds etc/... instead of /etc/.... This is a safety feature: when you unpack it later, the files go into the current folder instead of overwriting the real /etc. It is a notice, not an error. To avoid it, change into the parent folder first: tar -czf etc.tar.gz -C / etc.
On Linux servers, .tar.gz is the usual choice. tar and gzip are installed almost everywhere, and tar keeps Linux permissions and owners, which matters for scripts and configs. .zip is better when the archive is going to Windows users, because Windows opens it without extra tools. Other formats exist too: .tar.bz2 (j flag) and .tar.xz (J flag) shrink more but are slower. Use file name.tar.gz if you are not sure what an archive really is.
Give tar the path of that file as it appears in the listing: tar -xzf logs.tar.gz logs/error.log. List the archive first with tar -tzf, so you copy the exact path, including the folder at the front. To print it without writing anything to disk, add -O: tar -xzOf logs.tar.gz logs/error.log. This saves time and disk space with large backups.