SQUASH(1)toolbelt manualSQUASH(1)

squash

Pack files and folders into any free format.

Synopsis

squash [options] path ... [-- tool options]
squash --compare path ...

Description

squash packs one or more files and folders into one archive. It picks the tool, the level and the thread count, writes the archive, reads it back to test it, and prints one line:

site/ -> site.tar.zst (60KB to 26KB, 3 files, 0.0s)

The line gives the source, the archive, the size before and after, the number of files and the time it took.

With no options the archive is a tar.zst in the current folder. zstd packs about as small as gzip at its best level and runs many times faster, and every Linux release from the last few years can open it. Pick another format with -f, or name the archive with -o and let its extension pick the format.

squash never overwrites anything. When the archive name is taken it stops and says which name -y would use. It checks free disk space before it starts. For the levels that need a lot of memory, it checks free memory too and lowers the thread count to fit.

Every archive is tested before squash offers to delete anything. The test reads the whole archive back through the same tool and counts the entries. When the count differs from the source, or the tool reports damage, the archive is removed and the source stays. When the test passes and you run squash in a terminal, it asks whether to move the source to the trash. The answer defaults to no, and a no still exits 0. The source goes to the trash, never straight to rm.

A single file with a plain compressor format, such as -f xz on a log file, skips tar and becomes server.log.xz. A folder always goes through tar, zip or 7z, since a plain compressor holds one file.

Options

Format and strength

OptionWhat it does
-f, --format FMTThe format. tar.zst by default. The table under Formats lists every name.
-l, --level 1..91 is the fastest and 9 the smallest, in every format. squash maps it onto the tool's own scale.
--maxThe tool's real top level, past what -l 9 gives, such as zstd --ultra -22. Slow, and hungry for memory.
-T, --threads NThreads for the tools that can use them. The default is every CPU, from nproc.
--comparePack a sample in every installed format and print a table of size, ratio and time. Writes no archive.

What goes in

OptionWhat it does
-x, --exclude PATLeave out files and folders whose name matches, at any depth. Can repeat.
-o, --out NAMEName the archive. Its extension picks the format when there is no -f. A folder puts the archive there.
-s, --split SIZEWrite parts of SIZE, such as 25M, 700M or 4G. Units are powers of 1024.
-p, --passwordAsk for a password, twice. zip and 7z only.

After writing

OptionWhat it does
-t, --testPrint the test result. The test runs anyway when squash would offer to delete the source.
--rmMove the source to the trash once the test passes, without asking.
-k, --keepKeep the source and never ask.
-y, --yesWhen the archive exists, write the next free name, such as site-1.tar.zst.
-q, --quietPrint only the summary line and errors.
-v, --verbosePrint each step, and each real command before it runs.
-h, --helpPrint the help.

--rm and -k contradict each other, and so do -l and --max. --rm with -x is refused, since it would delete the files that -x left out of the archive. With -x, squash never offers to delete the source.

Formats

FormatExtensionTool, first choice then fallbackPackage (apt)Threads-l 1..9 becomes
tar.zst.tar.zstzstdzstdyeszstd 1, 3, 5, 7, 10, 12, 14, 16, 19
tar.gz.tar.gzpigz, then gzippigz, gzippigz only1 to 9
tar.bz2.tar.bz2pbzip2, then bzip2pbzip2, bzip2pbzip2 only1 to 9
tar.xz.tar.xzxzxz-utilsyes1 to 9
tar.lzma.tar.lzmaxz --format=lzmaxz-utilsno1 to 9
tar.lz4.tar.lz4lz4lz4nolz4 1, 2, 3, 5, 6, 7, 9, 10, 12
tar.lz.tar.lzplzip, then lzipplzip, lzipplzip only1 to 9
tar.lzo.tar.lzolzoplzopno1 to 9
tar.br.tar.brbrotlibrotlinobrotli 1, 2, 3, 4, 6, 7, 8, 9, 11
zip.zipzip, or 7z for a passwordzip, 7zipno1 to 9
7z.7z7z7zipyes7z 1, 3, 3, 5, 5, 7, 7, 9, 9
tar.tartartarnono compression

The plain forms zst, gz, bz2, xz, lzma, lz4, lz, lzo and br compress one file without tar. On a folder they become the tar form, so -f zst on a folder writes a .tar.zst. -f also takes the short names tgz, tbz2, txz, tzst and tzo, and the tool names gzip, zstd, lzip, lzop and brotli.

rar is refused. Only the paid WinRAR tool can write rar, and squash sticks to free tools. unpack still opens rar archives.

With no -l, each tool runs at its own default level. zstd uses 3, gzip and xz use 6, bzip2 uses 9, lz4 uses 1, and 7z uses 5. brotli defaults to 11, which is far too slow for an archive, so squash gives it -q 6 instead.

--max means the level past 9 where a tool has one.

Format--max runs
tar.zstzstd --ultra -22
tar.gzpigz -11, which runs zopfli, or gzip -9 without pigz
tar.xz, tar.lzmaxz -9e
tar.lz4lz4 -12
tar.brbrotli -q 11 -w 24
the othersthe same as -l 9

Which one to pick

--compare answers the question for your own files. See the example below.

Output name

With no -o, the archive goes in the current folder and takes the source's name plus the extension, so squash site/ writes site.tar.zst. When the current folder is inside the source, as with squash ., the archive goes next to the source instead, since it must not land inside what it packs. Several sources share one archive named after the first, as in site/, server.log -> site.tar.zst.

With -o NAME, the name's extension picks the format when there is no -f. -o site.zip writes a zip.

Split archives

-s SIZE writes the archive in parts no bigger than SIZE, for a file host with a size limit or a FAT32 stick.

FormatPartsJoin or open with
tar formatsname.tar.zst.001, .002, ...cat name.tar.zst.0* > name.tar.zst, or unpack name.tar.zst.001
7zname.7z.001, .002, ...7z x name.7z.001, or unpack name.7z.001
zipname.z01, name.z02, ..., name.zip7z x name.zip, or unpack name.zip

zip parts must be 64K or larger, a limit of zip itself. The test reads every part back, and the summary line names the first and last part.

Passwords

-p asks for the password twice, with no echo. The two answers must match, and an empty password is refused. Nothing is written until the password is settled. -p needs a terminal, so a script or cron job gets exit 4 and never hangs on a prompt.

tar formats have no password. -p with a tar format exits 2 and points to lock, which encrypts any file with age or gpg:

squash -p site/
squash: -p works with zip and 7z only. For a tar.zst, run lock on the archive afterwards
Try 'squash --help' for the options.

Excluding files

-x PAT leaves out files and folders whose name matches, at any depth. Repeat it for more patterns. Quote each pattern so the shell does not expand it first.

squash -x node_modules -x '*.o' -x .git src/

tar gets --exclude, zip gets -x with the same pattern at every depth, and 7z gets -xr!. Since the archive now holds less than the source, the entry count cannot be checked. The test still reads every byte back.

Checks before writing

squash writes into a temporary file next to the final one and renames it only after the test passes. A failed or interrupted run leaves no half-written archive behind.

Pass-through

Options after -- go to the tool that compresses, placed after the options squash builds, so they win.

FormatGets the optionsExample
tar formatsthe compressorsquash -f xz src/ -- --check=sha256
tar.zstzstdsquash photos/ -- --long=27
tartarsquash -f tar src/ -- --owner=0 --group=0
zipzipsquash -f zip site/ -- -9
7z7zsquash -f 7z data/ -- -ms=off

-v shows where they went:

squash -v -f 7z -o p.7z site/ -- -mx=9 -ms=off 2>&1 | grep '^+'
+ 7z a -t7z -bso0 -bsp0 -snl -mmt=4 -mx=9 -ms=off p.7z /home/sam/site
squash -v -f tar.xz -o q.tar.xz site/ -- --check=sha256 2>&1 | grep '^+'
+ tar -cf - site | xz -c -T 4 --check=sha256 > q.tar.xz
squash -v -f tar -o q.tar site/ -- --owner=0 --group=0 2>&1 | grep '^+'
+ tar -cf - --owner=0 --group=0 site > q.tar

With --compare, options after -- are ignored.

Needs

tar and the tool for the format you pick. zstd is the default, so install it at least. pv is optional and draws a progress bar in a terminal.

Toolaptdnfpacmanzypperapk
zstdzstdzstdzstdzstdzstd
gzipgzipgzipgzipgzipgzip
pigzpigzpigzpigzpigzpigz
bzip2bzip2bzip2bzip2bzip2bzip2
pbzip2pbzip2pbzip2pbzip2pbzip2pbzip2
xzxz-utilsxzxzxzxz
lz4lz4lz4lz4lz4lz4
lziplziplziplziplziplzip
plzipplzipplzipplzipplzipnone
lzoplzoplzoplzoplzoplzop
brotlibrotlibrotlibrotlibrotlibrotli
zip, unzipzip, unzipzip, unzipzip, unzipzip, unzipzip, unzip
7z7zip7zip7zip7zip7zip

Per distro:

When a tool is missing, squash exits 3 and prints the install line for your package manager.

Examples

Pack a folder

squash site/
site/ -> site.tar.zst (60KB to 26KB, 3 files, 0.0s)

A zip for someone on Windows

squash -f zip -o site.zip site/
site/ -> site.zip (60KB to 29KB, 3 files, 0.0s)

Compress one log file

A single file with a plain format skips tar:

squash -f xz server.log
server.log -> server.log.xz (106KB to 4.8KB, 1 file, 0.0s)

Keep or trash the source

In a terminal, squash asks once the test passes:

squash -f 7z site2/
site2/ -> site2.7z (60KB to 22KB, 3 files, 0.0s)
Delete the source, site2/ (3 files, 60 KB)? It goes to the trash. [y/N] y
site2/ is in the trash.

An archive name that is taken

squash site/
squash: site.tar.zst already exists. Pass -y to write site-1.tar.zst, or pick a name with -o
squash -y site/
site.tar.zst exists, writing site-1.tar.zst
site/ -> site-1.tar.zst (60KB to 26KB, 3 files, 0.0s)

Leave out build output and print the test

squash -t -x node_modules -x '*.o' -f 7z src/
src/ -> src.7z (40KB to 1.9KB, 3 files, 0.0s)
test passed: src.7z, 3 entries
src/ stays, -x left files out of the archive.

Split into parts

squash -s 10K -f tar.gz -o parts site/
site/ -> parts.tar.gz.001 to .004 (60KB to 31KB, 3 files, 0.0s)
ls parts*
parts.tar.gz.001  parts.tar.gz.002  parts.tar.gz.003  parts.tar.gz.004

A 7z with a password

squash -f 7z -p -o secret.7z site/
Password:
Again:
site/ -> secret.7z (60KB to 22KB, 3 files, 0.0s)

Every step, with the real commands

squash -v -l 9 -o v.tar.zst site/
squash: site/: 3 files, 60KB
squash: format: tar.zst, from the name v.tar.zst
squash: level: -l 9 is zstd -19
squash: threads: 4, zstd -T4
+ tar -cf - site | zstd -c -q --size-hint=61465 -19 -T4 > v.tar.zst
site/ -> v.tar.zst (60KB to 25KB, 3 files, 0.0s)

Compare every format on your own files

--compare packs up to the first 8MB of the source in each installed format at -l 6, sorts the table by size, and writes no archive. When the source is bigger, the last line estimates the time for all of it.

squash --compare site/
sample: all of site/ (60KB), every format at -l 6
format        size   ratio    time
tar.lz        21KB    3.2x    0.0s
tar.lzma      22KB    3.2x    0.0s
tar.xz        22KB    3.2x    0.0s
7z            22KB    3.2x    0.0s
tar.bz2       26KB    2.7x    0.0s
tar.zst       26KB    2.7x    0.0s
zip           30KB    2.3x    0.0s
tar.gz        31KB    2.2x    0.0s
tar.lz4       33KB    2.1x    0.0s
tar.lzo       36KB    1.9x    0.0s
skipped: tar.br, brotli is not installed

rar is refused

squash -f rar site/
squash: rar is not supported for creating, it needs the paid WinRAR tool. Use -f 7z or -f zip. unpack still opens rar
Try 'squash --help' for the options.

Troubleshooting

"already exists. Pass -y to write ..." An archive with that name is there. Pass -y to take the next free name, pick one with -o, or move the old archive away first. squash never replaces a file.

"... is 2.1 GB and . has 1.4 GB free" The disk check compares the whole source with the free space. Write somewhere else with -o /other/disk/, or free some space.

"xz at this level needs about 674 MB and 512 MB of memory is free. Use a lower -l" Even one thread does not fit. Use -l 6 or lower, close some programs, or pick tar.zst, which needs far less memory at -l 9.

"4 threads need about 3.4 GB of memory and 2.1 GB is free, using 2" A warning, not an error. The archive comes out the same, only slower. Pass -T 1 to use one thread from the start.

"the test failed. The archive was not kept and the source stays" The tool wrote an archive it could not read back, or the entry count differs from the source. The message above it says which. The usual causes are a failing disk, too little space in the middle of the write, or a file removed while squash read the folder. Run again with -v to see each command.

"a file changed while squash read it" A log or database was written to during the pack. The archive holds the version tar saw. Stop the program that writes, or copy the file first, for a clean copy.

"zip needs every path in one folder" zip stores paths relative to one folder. Move the sources into one folder, or use a tar format, which handles paths from anywhere.

"-p asks for the password in a terminal, and there is none" -p never reads a password from a pipe. For a script, write a tar format and encrypt it with lock, which can read a key file.

A zip with a password does not open in Windows Explorer. Older Explorer versions only know ZipCrypto, and squash uses AES-256. Send a 7z instead, or tell the person to use 7-Zip.

The archive is barely smaller than the source. The files are already compressed, such as JPEG, MP4 or other archives. Use -f tar, which is faster and comes out almost the same size.

Exit status

CodeMeaning
0The archive is written and tested. Also 0 when you answer no to the delete question.
1Packing or the test failed, the passwords differ, or a source is missing. Nothing was kept.
2Bad usage, including rar, -p with a tar format, and a name whose extension disagrees with -f.
3The tool for the format is missing. The message has the install line.
4A safety check refused, such as an existing name, too little disk or memory, or no terminal for -p.

See also

unpack, archdiff, archmount, lock, tar(1), zstd(1), xz(1), 7z(1)