extracttodisk
Unpacks backup archives back onto disk, and shows you exactly which files would be overwritten before it touches anything. The companion to backuptousb, but it accepts any tar archive.
The problem it solves
Restoring is more dangerous than backing up. A backup writes to an empty disk. A restore writes on top of what you have, and done on autopilot it can replace a fresh folder with a three-week-old copy without you noticing until it is too late.
Plain tar -x says nothing. It just writes, and files that were there before disappear without a word. This script reads the archive index first, compares it against what is actually on disk, and puts the facts in front of you before anything happens.
Getting started
$ chmod +x ~/scripts/extracttodisk $ echo "alias extracttodisk='~/scripts/extracttodisk'" >> ~/.bashrc $ source ~/.bashrc
The default restore folder is set at the top of the file:
DEFAULT_RESTORE="/home/youruser/backuprestore" # where archives get unpacked
The default is deliberately not your home directory. Archives hold relative paths, so an archive called myproject.tar.zst creates backuprestore/myproject/. Your live ~/myproject/ is left untouched, and you can compare the two before moving anything back.
Usage
extracttodiskWith no arguments: takes the newest archive sitting next to the script itself. On a backup disk that is usually exactly what you want.extracttodisk a.tar.zstOne named archive.extracttodisk *.tar.zstEverything in the folder, one after another, into the same destination.-lLists the contents of the archive and stops there. Extracts nothing.-qSkips reading the archive index. Starts immediately, but with no collision list.-yNo prompts. Always picks the safe option.-o <path>Extract somewhere other than the default folder.-hThe whole comment block from the top of the file.See what is in the archive first
If you are not sure what you have, list it. Nothing is written to disk:
$ extracttodisk notes.txt.tar.zst -l
notes.txt
A typical restore
If the destination folder does not exist, it offers to create it rather than aborting:
$ extracttodisk myproject.tar.zst Restore into (Enter to accept): /home/youruser/backuprestore Folder does not exist: /home/youruser/backuprestore Create it? [Y/n] y Created /home/youruser/backuprestore Reading archive index (use -q to skip)... 55 files Extracting myproject.tar.zst -> /home/youruser/backuprestore/myproject/ 100% 00:00 taken Flushing to disk... done Archive 689 (55 files) Restored 220K -> /home/youruser/backuprestore/myproject Time 0m 0s Speed (too fast to measure) Scripts in the restore folder: + /home/youruser/backuprestore/extracttodisk + /home/youruser/backuprestore/backuptousb
The collision warning, the important part
Run the same restore again, on top of a folder that is already there, and it stops. It does not guess whether the folder "is the same one", because that is not decidable. It shows you the numbers and lets you choose:
$ extracttodisk myproject.tar.zst Reading archive index (use -q to skip)... 55 files /home/youruser/backuprestore/myproject already exists: on disk now 220K (52 files would be overwritten) incoming archive 689 packed 2026-08-05 12:15 Would OVERWRITE these existing files. First few: myproject/src/file1.js myproject/src/file26.js myproject/src/file39.js myproject/src/file22.js myproject/src/file17.js myproject/src/file11.js ... and 46 more [o] overwrite in place [n] extract to a fresh myproject-restored-N/ [s] skip this archive Choose [o/N/s]: _
Note that the capital letter in [o/N/s] is N. Press Enter and the data lands in a new folder with nothing overwritten. Run it with -y, or without a terminal, from cron or through a pipe, and it takes that same safe route entirely on its own, and says so:
Non-interactive: extracting to a fresh folder to avoid overwrite. Extracting to a fresh folder: myproject-restored-2/ Archive 689 (55 files) Restored 220K -> /home/youruser/backuprestore/myproject-restored-2
Run it a third time and you get myproject-restored-3. It counts upward until it finds a free name, so an automated run can never eat its own previous restore.
Details worth knowing
Fresh folders go via a staging directory, not tar --transform
The obvious way to extract under a new name is tar --transform. It is also a trap: the expression is sed syntax, and folder names containing regex metacharacters, something as ordinary as my[test], make the rename fail silently and the contents land straight on top of the existing folder. Which is exactly the overwrite you were trying to avoid. The script extracts into a temporary directory instead and moves the result into place afterwards. No regex, no surprises.
The archive index is read exactly once
Both the file count for the progress bar and the collision check need the list of what is in the archive. It is read once and cached. On a large archive that takes a while: a 50 GB .zst can sit at "Reading archive index" for minutes. If you know the destination is empty, -q skips the whole pass and starts immediately, with a spinner instead of a bar.
Interruptions clean up after themselves
Ctrl-C mid-restore removes both the cache in /tmp and a half-finished staging directory under the destination. You are not left with a .extracttodisk-stage.XXXX full of half files.
Both scripts copy themselves. Every run drops both backuptousb and extracttodisk next to the data: on the backup disk when you pack, in the restore folder when you unpack. The copies are overwritten whenever they differ, so the tool on the disk is always the same version that made the archives. A backup disk you find again in two years carries what it takes to unpack itself.
The raw command behind it
# unpack $ tar -I zstd -xf myproject.tar.zst -C /home/youruser/backuprestore # just list the contents $ tar -I zstd -tf myproject.tar.zst | less # pull out a single directory from the archive $ tar -I zstd -xf myproject.tar.zst myproject/src/ # check the archive is not corrupt $ zstd -t myproject.tar.zst
Not maintained, change it yourself
Written for my own machine, published as-is. No updates, no support.
If you want it to behave differently, download the file and hand it to an AI along with what you want: "extract straight into my home directory", "never ask, always overwrite", "verify checksums afterwards". The code is commented to be read, both by you and by whichever model you ask.