Jacksum's primary purpose is to deal with hashes. However, since Jacksum supports both many encodings and customized formatting you get additional features that can be quite useful sometimes.
The Jacksum Hacks were not planned. I was also quite surprised about this side effect which works pretty well.
Two options switch the hashing off, and the difference between them is the key to almost every hack
on this page:
| reads the content of files | reports read errors | knows file size and timestamp | |
|---|---|---|---|
-a none |
no | no | yes |
-a read |
yes | yes | yes |
So -a none turns Jacksum into a converter and a metadata tool, and -a read turns it into a tool
that touches every single byte without producing a hash value.
With -a none the option -E needs an explicit -F, otherwise Jacksum stops:
Jacksum: Parameter Error: -a none and -E without -F cannot go together.
Either write -F "#SEQUENCE" -E hex or use the short form -F "#SEQUENCE{hex}".
Table of contents
find)stat, du, ls)realpath, dirname, basename, cygpath)date -r)iconv)wc -c)For all examples in this part we set -a none, because we are not interested in hashing at all.
The file myfile.dat used below contains the seven bytes Jacksum.
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE" -E hex -g 1
4a 61 63 6b 73 75 6d
-g <count> groups the output in <count> bytes, -G <char> sets the separator.
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE" -E hex -g 2 -G :
4a61:636b:7375:6d
Base16 (RFC 4648) is hexadecimal in uppercase.
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{base16}"
4A61636B73756D
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{base32}"
JJQWG23TOVWQ====
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{base32-nopadding}"
JJQWG23TOVWQ
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{base32hex}"
99GM6QRJELMG====
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{base32hex-nopadding}"
99GM6QRJELMG
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{base64}"
SmFja3N1bQ==
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{base64-nopadding}"
SmFja3N1bQ
Safe for URLs and file names, because + and / are replaced by - and _.
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{base64url}"
SmFja3N1bQ==
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{base64url-nopadding}"
SmFja3N1bQ
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{z85}"
n)#jBB9hs
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{z-base-32}"
jjosg45uqiso
Since 4.0.0 Jacksum also reads z-base-32 back in, see z-base-32 to ....
Pronounceable pseudowords, as used by OpenSSH and SSH2.
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{bubblebabble}"
xidik-comuk-resyl-hyrix
Since 4.0.0 Jacksum also reads BubbleBabble back in, see BubbleBabble to ....
The whole file is treated as one big number, not as a list of byte values.
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{dec}"
20936227908973933
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{oct}"
1123026155334672555
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{bin}"
01001010011000010110001101101011011100110111010101101101
$ jacksum -a none -q file:myfile.dat -F "#LENGTH"
7
-q file: keeps the entire file in memory and is therefore limited to 128 MiB. For bigger files,
pass the file as a normal parameter instead of using -q.
$ jacksum -a none -q "txt:Hello World" -F "#LENGTH"
11
#LENGTH counts bytes, not characters. The five characters of Grüße are seven bytes in UTF-8:
$ jacksum -a none -q "txt:Grüße" -F "#LENGTH bytes, hex: #SEQUENCE{hex}"
7 bytes, hex: 4772c3bcc39f65
$ jacksum -a none -q "txt:Hello World" -F "#SEQUENCE" -E hex -g 1
48 65 6c 6c 6f 20 57 6f 72 6c 64
txtf: interprets \t, \n, \r, \", \', \\ and \xhh.
$ jacksum -a none -q "txtf:Hello World\n" -F "#SEQUENCE" -E hex -g 1
48 65 6c 6c 6f 20 57 6f 72 6c 64 0a
$ jacksum -a none -q "txtf:tab\there\n" -F "#SEQUENCE" -E hex -g 1
74 61 62 09 68 65 72 65 0a
$ jacksum -a none -q "txt:Hello World" -F "#SEQUENCE{base64}"
SGVsbG8gV29ybGQ=
$ jacksum -a none -q "txt:Hello World" -F "#SEQUENCE{base32}"
JBSWY3DPEBLW64TMMQ======
$ jacksum -a none -q "txt:Hello World" -F "#SEQUENCE{z85}"
nm=QNzY&b1A+]m
$ jacksum -a none -q "txt:Hello World" -F "#SEQUENCE{bubblebabble}"
xidak-hyryk-sored-buhok-zusuk-sunex
$ jacksum -a none -q "txt:Hello World" -F "bin: #SEQUENCE{bin}, dec: #SEQUENCE{dec}, oct: 0#SEQUENCE{oct}, hex:#SEQUENCE{hex-uppercase}"
bin: 0100100001100101011011000110110001101111001000000101011101101111011100100110110001100100, dec: 87521618088882533792115812, oct: 044145330661571005355734466144, hex:48656C6C6F20576F726C64
--string-list reads one string per line. #MESSAGE is the string itself.
$ cat strings.txt
Hello World
foo
Grüße
$ jacksum -a none --string-list strings.txt -F "#MESSAGE -> #SEQUENCE{base64}"
Hello World -> SGVsbG8gV29ybGQ=
foo -> Zm9v
Grüße -> R3LDvMOfZQ==
$ jacksum -a none --string-list strings.txt -F "#LENGTH #MESSAGE"
11 Hello World
3 foo
7 Grüße
-q readline reads one line from the console and echoes it back through any format you like — handy
for investigating strings and encodings without leaving them in the shell history.
$ jacksum -a none -q readline -F "msg=#MESSAGE len=#LENGTH hex=#SEQUENCE{hex} b64=#SEQUENCE{base64}"
Requires a real console; it cannot be fed through a pipe or a redirection.
$ jacksum -a none -q bin:1010101010101010 -F "#SEQUENCE{dec}"
43690
$ jacksum -a none -q bin:1010101010101010 -F "#SEQUENCE{oct}"
125252
$ jacksum -a none -q bin:1010101010101010 -F "#SEQUENCE{hex}"
aaaa
$ jacksum -a none -q bin:1010101010101010 -F "bin: #SEQUENCE{bin}, dec: #SEQUENCE{dec}, oct: 0#SEQUENCE{oct}, hex:#SEQUENCE{hex-uppercase}"
bin: 1010101010101010, dec: 43690, oct: 0125252, hex:AAAA
$ jacksum -a none -q bin:1010101010101010 -F '{ "bin": "#SEQUENCE{bin}", "dec": "#SEQUENCE{dec}", "oct": "0#SEQUENCE{oct}", "hex": "0x#SEQUENCE{hex-uppercase}" }'
{ "bin": "1010101010101010", "dec": "43690", "oct": "0125252", "hex": "0xAAAA" }
$ jacksum -a none -q bin:1010101010101010 -F "#SEQUENCE{base64}"
qqo=
$ jacksum -a none -q bin:1010101010101010 -F "#SEQUENCE{z85}"
S&u
Octal input is a list of byte values, separated by commas or spaces.
$ jacksum -a none -q oct:312,376 -F "#SEQUENCE{bin}"
1100101011111110
$ jacksum -a none -q oct:312,376 -F "#SEQUENCE{dec}"
51966
$ jacksum -a none -q oct:312,376 -F "#SEQUENCE{hex-uppercase}"
CAFE
$ jacksum -a none -q oct:312,376 -F "bin: #SEQUENCE{bin}, dec: #SEQUENCE{dec}, oct: 0#SEQUENCE{oct}, hex:#SEQUENCE{hex-uppercase}"
bin: 1100101011111110, dec: 51966, oct: 0145376, hex:CAFE
$ jacksum -a none -q oct:312,376 -F '{ "bin": "#SEQUENCE{bin}", "dec": "#SEQUENCE{dec}", "oct": "0#SEQUENCE{oct}", "hex": "0x#SEQUENCE{hex-uppercase}" }'
{ "bin": "1100101011111110", "dec": "51966", "oct": "0145376", "hex": "0xCAFE" }
$ jacksum -a none -q oct:312,376 -F "#SEQUENCE{base64}"
yv4=
$ jacksum -a none -q oct:312,376 -F "#SEQUENCE{z85}"
+kI
$ jacksum -a none -q oct:"145 147 40 64 62 12" -F "#SEQUENCE{hex}"
65672034320a
$ jacksum -a none -q dec:42 -F "#SEQUENCE{bin}"
00101010
$ jacksum -a none -q dec:42 -F "#SEQUENCE{hex-uppercase}"
2A
$ jacksum -a none -q dec:42 -F "#SEQUENCE{oct}"
52
$ jacksum -a none -q dec:42 -F "bin: #SEQUENCE{bin}, dec: #SEQUENCE{dec}, oct: 0#SEQUENCE{oct}, hex:#SEQUENCE{hex-uppercase}"
bin: 00101010, dec: 42, oct: 052, hex:2A
$ jacksum -a none -q dec:42 -F '{ "bin": "#SEQUENCE{bin}", "dec": "#SEQUENCE{dec}", "oct": "0#SEQUENCE{oct}", "hex": "0x#SEQUENCE{hex-uppercase}" }'
{ "bin": "00101010", "dec": "42", "oct": "052", "hex": "0x2A" }
$ jacksum -a none -q dec:42 -F "#SEQUENCE{base64}"
Kg==
$ jacksum -a none -q dec:42 -F "#SEQUENCE{z85}"
dG
$ jacksum -a none -q hex:cafe08 -F "#SEQUENCE{bin}"
110010101111111000001000
$ jacksum -a none -q hex:7A -F "#SEQUENCE{dec}"
122
$ jacksum -a none -q hex:7A -F "#SEQUENCE{oct}"
172
$ jacksum -a none -q hex:cafe08 -F "#SEQUENCE{hex-uppercase}"
CAFE08
$ jacksum -a none -q hex:CAFE08 -F "#SEQUENCE{hex-lowercase}"
cafe08
$ jacksum -a none -q hex:CAFE -F "bin: #SEQUENCE{bin}, dec: #SEQUENCE{dec}, oct: 0#SEQUENCE{oct}, hex:#SEQUENCE{hex-uppercase}"
bin: 1100101011111110, dec: 51966, oct: 0145376, hex:CAFE
$ jacksum -a none -q hex:CAFE -F '{ "bin": "#SEQUENCE{bin}", "dec": "#SEQUENCE{dec}", "oct": "0#SEQUENCE{oct}", "hex": "0x#SEQUENCE{hex-uppercase}" }'
{ "bin": "1100101011111110", "dec": "51966", "oct": "0145376", "hex": "0xCAFE" }
$ jacksum -a none -q hex:C0DECAFE -F "#SEQUENCE{base32}"
YDPMV7Q=
$ jacksum -a none -q hex:C0DECAFE -F "#SEQUENCE{base64}"
wN7K/g==
$ jacksum -a none -q hex:C0DECAFE -F "#SEQUENCE{base64url}"
wN7K_g==
$ jacksum -a none -q hex:C0DECAFE -F "#SEQUENCE{z85}"
Z#0lk
$ jacksum -a none -q hex:C0DECAFE -F "#SEQUENCE{bubblebabble}"
xubat-vidyz-vexox
$ jacksum -a none -q base32:YDPMV7Q= -F "#SEQUENCE{hex-uppercase}"
C0DECAFE
$ jacksum -a none -q base32:YDPMV7Q= -F "#SEQUENCE{base32hex}"
O3FCLVG=
$ jacksum -a none -q base32:YDPMV7Q= -F "#SEQUENCE{base64}"
wN7K/g==
$ jacksum -a none -q base32:YDPMV7Q= -F "#SEQUENCE{z85}"
Z#0lk
$ jacksum -a none -q base32:YDPMV7Q -F "bin: #SEQUENCE{bin}, dec: #SEQUENCE{dec}, oct: 0#SEQUENCE{oct}, hex:#SEQUENCE{hex-uppercase}"
bin: 11000000110111101100101011111110, dec: 3235826430, oct: 030067545376, hex:C0DECAFE
$ jacksum -a none -q base32hex:O3FCLVG= -F "#SEQUENCE{hex-uppercase}"
C0DECAFE
$ jacksum -a none -q base32hex:O3FCLVG= -F "#SEQUENCE{base32}"
YDPMV7Q=
$ jacksum -a none -q base32hex:O3FCLVG= -F "#SEQUENCE{base64}"
wN7K/g==
$ jacksum -a none -q base32hex:O3FCLVG= -F "bin: #SEQUENCE{bin}, dec: #SEQUENCE{dec}, oct: 0#SEQUENCE{oct}, hex:#SEQUENCE{hex-uppercase}"
bin: 11000000110111101100101011111110, dec: 3235826430, oct: 030067545376, hex:C0DECAFE
$ jacksum -a none -q base64:wN7K/g== -F "#SEQUENCE{hex-uppercase}"
C0DECAFE
$ jacksum -a none -q base64:wN7K/g== -F "#SEQUENCE{base64url}"
wN7K_g==
$ jacksum -a none -q base64:wN7K/g== -F "#SEQUENCE{z85}"
Z#0lk
$ jacksum -a none -q base64:wN7K/g -F "#SEQUENCE{hex-uppercase}"
C0DECAFE
$ jacksum -a none -q base64url:wN7K_g== -F "#SEQUENCE{hex-uppercase}"
C0DECAFE
$ jacksum -a none -q base64url:wN7K_g== -F "#SEQUENCE{base64}"
wN7K/g==
$ jacksum -a none -q base64url:wN7K_g== -F "#SEQUENCE{z85}"
Z#0lk
$ jacksum -a none -q base64url:wN7K_g== -F "bin: #SEQUENCE{bin}, dec: #SEQUENCE{dec}, oct: 0#SEQUENCE{oct}, hex:#SEQUENCE{hex-uppercase}"
bin: 11000000110111101100101011111110, dec: 3235826430, oct: 030067545376, hex:C0DECAFE
$ jacksum -a none -q "z85:Z#0lk" -F "#SEQUENCE{hex}"
c0decafe
$ jacksum -a none -q "z85:Z#0lk" -F "#SEQUENCE{base64}"
wN7K/g==
$ jacksum -a none -q "z85:Z#0lk" -F "#SEQUENCE{base64url}"
wN7K_g==
-q z-base-32: is new in Jacksum 4.0.0. Until then z-base-32 was an output encoding only, so a
z-base-32 string could be produced but not read back.
$ jacksum -a none -q z-base-32:adxci9o -F "#SEQUENCE{hex-uppercase}"
C0DECAFE
The same bytes, a different alphabet:
$ jacksum -a none -q z-base-32:adxci9o -F "#SEQUENCE{base32}"
YDPMV7Q=
$ jacksum -a none -q z-base-32:adxci9o -F "#SEQUENCE{base64}"
wN7K/g==
$ jacksum -a none -q z-base-32:adxci9o -F "bin: #SEQUENCE{bin}, dec: #SEQUENCE{dec}, oct: 0#SEQUENCE{oct}, hex:#SEQUENCE{hex-uppercase}"
bin: 11000000110111101100101011111110, dec: 3235826430, oct: 030067545376, hex:C0DECAFE
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{z-base-32}"
jjosg45uqiso
$ jacksum -a none -q z-base-32:jjosg45uqiso -F "#SEQUENCE{hex}"
4a61636b73756d
z-base-32 input is lowercase only and carries no padding. Both ADXCI9O and adxci9o====
are rejected with Invalid z-base32 input data., and the alphabet has no l, v, 0 or 2.
The type is available for -k as well, because the secret key of an HMAC uses the same syntax as
-q:
$ jacksum -a hmac:sha256 -k z-base-32:adxci9o myfile.dat
-q bubblebabble: is new in Jacksum 4.0.0 as well. BubbleBabble is the only encoding on this page
that carries redundancy: every second tuple contains a checksum, and the string is framed by an
x. The decoder verifies all of that, so a mistyped string is rejected rather than being decoded to
arbitrary bytes.
$ jacksum -a none -q bubblebabble:xubat-vidyz-vexox -F "#SEQUENCE{hex-uppercase}"
C0DECAFE
$ jacksum -a none -q bubblebabble:xubat-vidyz-vexox -F "#SEQUENCE{base32}"
YDPMV7Q=
$ jacksum -a none -q bubblebabble:xubat-vidyz-vexox -F "#SEQUENCE{base64}"
wN7K/g==
$ jacksum -a none -q bubblebabble:xubat-vidyz-vexox -F "#SEQUENCE{z85}"
Z#0lk
$ jacksum -a none -q bubblebabble:xubat-vidyz-vexox -F "bin: #SEQUENCE{bin}, dec: #SEQUENCE{dec}, oct: 0#SEQUENCE{oct}, hex:#SEQUENCE{hex-uppercase}"
bin: 11000000110111101100101011111110, dec: 3235826430, oct: 030067545376, hex:C0DECAFE
$ jacksum -a none -q file:myfile.dat -F "#SEQUENCE{bubblebabble}"
xidik-comuk-resyl-hyrix
$ jacksum -a none -q bubblebabble:xidik-comuk-resyl-hyrix -F "#SEQUENCE{hex}"
4a61636b73756d
Three kinds of damage, three different messages, and never a silently wrong result (exit code 2 in
all three cases):
$ jacksum -a none -q bubblebabble:xidik-comuk-resyl-hyrax -F "#SEQUENCE{hex}"
BubbleBabble decoding error: the checksum of the tuple at index 19 does not match.
$ jacksum -a none -q bubblebabble:xidqk-comuk-resyl-hyrix -F "#SEQUENCE{hex}"
BubbleBabble decoding error: 'q' is not a valid vowel.
$ jacksum -a none -q bubblebabble:idik-comuk-resyl-hyrix -F "#SEQUENCE{hex}"
BubbleBabble decoding error: 22 is not a valid length for a BubbleBabble string.
That is what makes BubbleBabble the encoding of choice if a fingerprint has to be read out loud,
dictated over the phone, or typed in by a human.
The three examples from the BubbleBabble specification, in both directions:
$ jacksum -a none -q "txt:" -F "#SEQUENCE{bubblebabble}"
xexax
$ jacksum -a none -q "txt:1234567890" -F "#SEQUENCE{bubblebabble}"
xesef-disof-gytuf-katof-movif-baxux
$ jacksum -a none -q "txt:Pineapple" -F "#SEQUENCE{bubblebabble}"
xigak-nyryk-humil-bosek-sonax
$ jacksum -a none -q bubblebabble:xesef-disof-gytuf-katof-movif-baxux -F "#SEQUENCE{hex}"
31323334353637383930
Unlike z-base-32, BubbleBabble input is case insensitive, so XIDIK-COMUK-RESYL-HYRIX is
accepted as well. The empty input is xexax, not the empty string. For -q and -k the long
form bubblebabble: is the only valid indicator; bb: is not a type and ends up in the hex
fallback (Not a hex number.). Wherever an encoding is expected, bb is fine: -E bb,
#SEQUENCE{bb}.
The type is available for -k as well, because the secret key of an HMAC uses the same syntax as
-q:
$ jacksum -a hmac:sha256 -k bubblebabble:xubat-vidyz-vexox myfile.dat
And since Jacksum can turn a BubbleBabble string back into bytes, the option -e compares a
BubbleBabble encoded hash value byte-wise now, no matter how it was written:
$ jacksum -a sha256 -E bb -e XIDOF-GANEG-HUFUV-VIBOM-PYZYG-FUNUL-GUFIB-BEHIG-KAKAS-GUVYK-NUVAH-NUZOH-ZIZUH-RIVEV-TORIB-TYSOP-GUXUX myfile.dat
MATCH myfile.dat (XIDOF-GANEG-HUFUV-VIBOM-PYZYG-FUNUL-GUFIB-BEHIG-KAKAS-GUVYK-NUVAH-NUZOH-ZIZUH-RIVEV-TORIB-TYSOP-GUXUX)
Jacksum: Expectation met.
Jacksum: 1 of the successfully read files matches the expected hash value.
The same four bytes, C0DECAFE, through every encoding Jacksum knows:
$ jacksum -a none -q hex:C0DECAFE -F "#SEQUENCE{<encoding>}"
<encoding> |
output |
|---|---|
bin |
11000000110111101100101011111110 |
dec |
3235826430 |
oct |
30067545376 |
hex |
c0decafe |
hex-lowercase |
c0decafe |
hex-uppercase |
C0DECAFE |
hexup |
C0DECAFE (deprecated since 3.0, use hex-uppercase) |
base16 |
C0DECAFE |
base32 |
YDPMV7Q= |
base32-nopadding |
YDPMV7Q |
base32hex |
O3FCLVG= |
base32hex-nopadding |
O3FCLVG |
base64 |
wN7K/g== |
base64-nopadding |
wN7K/g |
base64url |
wN7K_g== |
base64url-nopadding |
wN7K_g |
z85 |
Z#0lk |
z-base-32 |
adxci9o |
bb / bubblebabble |
xubat-vidyz-vexox |
The same 19 values are valid for -E, and the input side (-q <type>:) understands
bin, dec, oct, hex, base32, base32hex, base64, base64url, z85, z-base-32 and
bubblebabble (the last two are new in 4.0.0), txt, txtf and file.
Anything that Jacksum can read with -q <type>: it can also write with #SEQUENCE{<encoding>}, so
you can chain conversions:
$ jacksum -a none -q "txt:Hello World" -F "#SEQUENCE{z85}"
nm=QNzY&b1A+]m
$ jacksum -a none -q "z85:nm=QNzY&b1A+]m" -F "#SEQUENCE{hex}"
48656c6c6f20576f726c64
$ jacksum -a none -q hex:48656c6c6f20576f726c64 -F "#SEQUENCE{z-base-32}"
jb1sa5dxrbms6hucco
$ jacksum -a none -q z-base-32:jb1sa5dxrbms6hucco -F "#SEQUENCE{base64}"
SGVsbG8gV29ybGQ=
$ jacksum -a none -q base64:SGVsbG8gV29ybGQ= -F "#SEQUENCE{bubblebabble}"
xidak-hyryk-sored-buhok-zusuk-sunex
$ jacksum -a none -q bubblebabble:xidak-hyryk-sored-buhok-zusuk-sunex -F "#SEQUENCE{hex}"
48656c6c6f20576f726c64
Jacksum always writes text. It can read a binary file (-q file:) and print it in any encoding,
but it cannot write raw bytes back to a file — so base64 -d > file.bin has no Jacksum equivalent.
Everything below uses -a none or -a read, so no hash value is ever calculated. The examples run
against this little tree:
myfile.dat 7 bytes
readme.txt 12 bytes
strings.txt 24 bytes
photos/a.jpg 1 byte
photos/2024/b.jpg 2 bytes
This is the one hack that has nothing to do with hashing at all: -a read reads every single byte
of every file and throws the bytes away. Anything that goes wrong on the way — a scratched DVD, a
dying USB stick, bit rot on an old backup drive, a network share that dropped out, a permission
problem — surfaces as a read error.
$ jacksum -a read -V summary,errors -r max . > /dev/null
Jacksum: total files read successfully: 5
Jacksum: total bytes read: 46
Jacksum: total bytes read (human readable): 46 bytes
Jacksum: total file read errors: 0
The per-file output goes to standard output (and is thrown away by > /dev/null), while errors and
the summary go to standard error. With one broken file in the tree:
$ jacksum -a read -V summary,errors -r max . > /dev/null
Jacksum: Error: ./bad.bin (Permission denied)
Jacksum: total files read successfully: 5
Jacksum: total bytes read: 46
Jacksum: total bytes read (human readable): 46 bytes
Jacksum: total file read errors: 1
$ echo $?
4
total file read errors and the exit code 4 make this scriptable. Use -u <file> to collect the
list of damaged files:
$ jacksum -a read -V summary,errors -u unreadable.log -r max /Volumes/BACKUP > /dev/null
Note that -a none will not find those files, because it never opens them:
$ jacksum -a none -F "#FILESIZE #FILENAME" bad.bin
1 bad.bin
That is exactly the difference: use -a none when you only want metadata, use -a read when you
want to know whether the data is still there.
find)--style names-only walks a directory tree and prints nothing but the paths.
$ jacksum --style names-only .
./myfile.dat
./readme.txt
./photos/2024/b.jpg
./photos/a.jpg
./strings.txt
-r <depth> limits the recursion depth:
$ jacksum --style names-only -r 1 .
Jacksum: Info: "./photos" is a directory, but the maximum number of allowed directory levels (1) has been reached.
./myfile.dat
./readme.txt
./strings.txt
-d and -f stop Jacksum from following symbolic links to directories resp. to files:
$ jacksum --style names-only -d -f .
Jacksum: Info: Ignoring "./photolink", because it is a symlink to a dir.
Jacksum: Info: Ignoring "./link.txt", because it is a symlink to a file.
./myfile.dat
./readme.txt
./photos/2024/b.jpg
./photos/a.jpg
./strings.txt
By default Jacksum only accepts regular files, and complains about everything else:
$ jacksum --style names-only .
Jacksum: Error: ./queue.fifo: is not a regular file.
./myfile.dat
./readme.txt
...
--scan-all-unix-file-types includes block devices, character devices, named pipes, sockets and
Solaris doors:
$ jacksum --style names-only --scan-all-unix-file-types .
./myfile.dat
./queue.fifo
./readme.txt
./photos/2024/b.jpg
./photos/a.jpg
./strings.txt
On Microsoft Windows, --scan-ntfs-ads additionally lists NTFS alternate data streams — a place
where things like to hide.
The resulting list can be fed straight back into Jacksum with --file-list.
stat, du, ls)Three ready-made styles produce hash-free lists. Do not combine them with -a, they bring their
own algorithm.
$ jacksum --style sizes-and-names .
7 ./myfile.dat
12 ./readme.txt
2 ./photos/2024/b.jpg
1 ./photos/a.jpg
24 ./strings.txt
$ jacksum --style timestamps-and-names -t iso .
2026-03-01T10:15:00.000+01:00 ./myfile.dat
2026-04-22T09:30:00.000+02:00 ./readme.txt
2026-01-05T07:45:00.000+01:00 ./photos/2024/b.jpg
2025-12-24T18:00:00.000+01:00 ./photos/a.jpg
2026-02-14T00:00:00.000+01:00 ./strings.txt
$ jacksum --style without-hashes --no-header .
2026-03-01T10:15:00.000+01:00 7 ./myfile.dat
2026-04-22T09:30:00.000+02:00 12 ./readme.txt
2026-01-05T07:45:00.000+01:00 2 ./photos/2024/b.jpg
2025-12-24T18:00:00.000+01:00 1 ./photos/a.jpg
2026-02-14T00:00:00.000+01:00 24 ./strings.txt
With -F you decide the layout yourself:
$ jacksum -a none -F "#FILESIZE #FILENAME" .
7 ./myfile.dat
12 ./readme.txt
2 ./photos/2024/b.jpg
1 ./photos/a.jpg
24 ./strings.txt
And -V summary counts files and bytes of a whole tree:
$ jacksum -a read -V summary -r max . > /dev/null
Jacksum: total files read successfully: 5
Jacksum: total bytes read: 46
Jacksum: total bytes read (human readable): 46 bytes
Jacksum: total file read errors: 0
--style without-hashes writes a list of timestamps, sizes and paths. Because it is a real check
list style, Jacksum can read it back with -c — you get a change detector without a single hash
value.
$ jacksum --style without-hashes --no-header . > ../snapshot.txt
Store the snapshot outside the tree you are snapshotting, otherwise it shows up in its own list.
Later, after readme.txt grew, notes.md appeared and photos/a.jpg was deleted:
$ jacksum --style without-hashes -c ../snapshot.txt --no-header -V nosummary,noinfo .
Jacksum: Error: ./photos/a.jpg: does not exist.
MISSING ./photos/a.jpg
OK ./myfile.dat
FAILED ./readme.txt
OK ./photos/2024/b.jpg
OK ./strings.txt
NEW ./notes.md
$ echo $?
4
At the default verbosity Jacksum also tells you why a file failed:
FAILED ./readme.txt
[filesize expected: 12, actual: 19]
--list-filter narrows the report down to what you care about:
$ jacksum --style without-hashes -c ../snapshot.txt --no-header --list-filter new -V nosummary,noinfo,noerrors .
NEW ./notes.md
$ jacksum --style without-hashes -c ../snapshot.txt --no-header --list-filter bad -V nosummary,noinfo .
Jacksum: Error: ./photos/a.jpg: does not exist.
MISSING ./photos/a.jpg
FAILED ./readme.txt
Valid filters are ok, failed, missing, new, and the shortcuts all, good
(none,ok,new), bad (none,failed,missing) and none.
If you only care whether the files are still there, use --style names-only instead — that list
carries nothing but paths:
$ jacksum --style names-only --no-header . > ../names.txt
$ jacksum --style names-only -c ../names.txt --no-header --list-filter bad -V nosummary,noinfo .
$ echo $?
0
Silence plus exit code 0 means "nothing is missing". As soon as something disappears:
$ jacksum --style names-only -c ../names.txt --no-header --list-filter bad -V nosummary,noinfo .
Jacksum: Error: ./photos/a.jpg: does not exist.
MISSING ./photos/a.jpg
$ echo $?
4
Add --check-strict if malformed lines in the list should turn into a nonzero exit code too.
realpath, dirname, basename, cygpath)$ jacksum -a none --path-absolute -F "#FILENAME" myfile.dat
/private/tmp/jacksum-hacks-demo/myfile.dat
$ jacksum -a none --path-relative-to /private/tmp -F "#FILENAME" .
jacksum-hacks-demo/myfile.dat
jacksum-hacks-demo/readme.txt
jacksum-hacks-demo/photos/2024/b.jpg
jacksum-hacks-demo/photos/a.jpg
jacksum-hacks-demo/strings.txt
#FILENAME{path} and #FILENAME{name} are dirname and basename:
$ jacksum -a none -F "#FILENAME{path} :: #FILENAME{name}" .
. :: myfile.dat
. :: readme.txt
./photos/2024 :: b.jpg
./photos :: a.jpg
. :: strings.txt
--no-path drops the directory completely:
$ jacksum -a none --no-path -F "#FILENAME" .
myfile.dat
readme.txt
b.jpg
a.jpg
strings.txt
-P <char> swaps the path separator — turn Unix paths into Windows paths and back, or produce
forward slashes for HTML on Windows:
$ jacksum -a none -P "\\" -F "#FILENAME" .
.\myfile.dat
.\readme.txt
.\photos\2024\b.jpg
.\photos\a.jpg
.\strings.txt
date -r)-t formats the last modification time of a file in any format you like.
$ jacksum -a none -t unixtime -F "#TIMESTAMP #FILENAME" .
1772356500 ./myfile.dat
1776843000 ./readme.txt
1767595500 ./photos/2024/b.jpg
1766595600 ./photos/a.jpg
1771023600 ./strings.txt
Predefined formats are default, default-utc, iso (iso8601), iso-utc (iso8601utc),
unixtime and unixtime-ms:
$ jacksum -a none -t iso-utc -F "#TIMESTAMP #FILENAME" myfile.dat
2026-03-01T09:15:00.000Z myfile.dat
$ jacksum -a none -t default -F "#TIMESTAMP #FILENAME" myfile.dat
20260301101500000 myfile.dat
$ jacksum -a none -t unixtime-ms -F "#TIMESTAMP #FILENAME" myfile.dat
1772356500000 myfile.dat
Anything Java's SimpleDateFormat understands works as well:
$ jacksum -a none -t "yyyy-MM-dd" -F "#TIMESTAMP #FILENAME" .
2026-03-01 ./myfile.dat
2026-04-22 ./readme.txt
2026-01-05 ./photos/2024/b.jpg
2025-12-24 ./photos/a.jpg
2026-02-14 ./strings.txt
-F is free text with a handful of tokens. Combined with -a none that makes Jacksum a small code
generator that walks a directory tree. #QUOTE inserts a ", #SEPARATOR inserts whatever -s
says.
An HTML link list:
$ jacksum -a none -P / -F "<li><a href=#QUOTE#FILENAME#QUOTE>#FILENAME{name}</a> — #FILESIZE bytes</li>" .
<li><a href="./myfile.dat">myfile.dat</a> — 7 bytes</li>
<li><a href="./readme.txt">readme.txt</a> — 12 bytes</li>
<li><a href="./photos/2024/b.jpg">b.jpg</a> — 2 bytes</li>
<li><a href="./photos/a.jpg">a.jpg</a> — 1 bytes</li>
<li><a href="./strings.txt">strings.txt</a> — 24 bytes</li>
JSON Lines, ready for jq:
$ jacksum -a none -t iso -F '{"path":"#FILENAME","size":#FILESIZE,"mtime":"#TIMESTAMP"}' .
{"path":"./myfile.dat","size":7,"mtime":"2026-03-01T10:15:00.000+01:00"}
{"path":"./readme.txt","size":12,"mtime":"2026-04-22T09:30:00.000+02:00"}
{"path":"./photos/2024/b.jpg","size":2,"mtime":"2026-01-05T07:45:00.000+01:00"}
{"path":"./photos/a.jpg","size":1,"mtime":"2025-12-24T18:00:00.000+01:00"}
{"path":"./strings.txt","size":24,"mtime":"2026-02-14T00:00:00.000+01:00"}
CSV, with the separator set by -s:
$ jacksum -a none -s ";" -F "#FILENAME#SEPARATOR#FILESIZE" .
./myfile.dat;7
./readme.txt;12
./photos/2024/b.jpg;2
./photos/a.jpg;1
./strings.txt;24
A shell script:
$ jacksum -a none -F "cp -p #QUOTE#FILENAME#QUOTE /backup/" .
cp -p "./myfile.dat" /backup/
cp -p "./readme.txt" /backup/
cp -p "./photos/2024/b.jpg" /backup/
cp -p "./photos/a.jpg" /backup/
cp -p "./strings.txt" /backup/
SQL:
$ jacksum -a none -F "INSERT INTO files (path, bytes) VALUES ('#FILENAME', #FILESIZE);" .
INSERT INTO files (path, bytes) VALUES ('./myfile.dat', 7);
INSERT INTO files (path, bytes) VALUES ('./readme.txt', 12);
INSERT INTO files (path, bytes) VALUES ('./photos/2024/b.jpg', 2);
INSERT INTO files (path, bytes) VALUES ('./photos/a.jpg', 1);
INSERT INTO files (path, bytes) VALUES ('./strings.txt', 24);
Use -o <file> (or -O <file> to overwrite) if the result should go to a file instead of the
terminal.
iconv)--string-list reads the strings, --charset-string-list says how they are encoded, and
--charset-stdout says how they should be written. #MESSAGE passes the string through unchanged
— so the only thing that happens is a character set conversion.
$ jacksum -a none --string-list strings.txt --charset-string-list UTF-8 --charset-stdout ISO-8859-1 -F "#MESSAGE" | xxd
00000000: 4865 6c6c 6f20 576f 726c 640a 666f 6f0a Hello World.foo.
00000010: 4772 fcdf 650a Gr..e.
Grüße arrives as 47 72 fc df 65 — five ISO-8859-1 bytes instead of seven UTF-8 bytes. Add
--bom if the target charset should get a byte order mark. Jacksum knows 170+ character sets;
--charset-output-file does the same for -o.
wc -c)- reads standard input, #LENGTH prints how many bytes came through.
$ printf 'Hello World' | jacksum -a read -F "#LENGTH" -
11
The manpage is built into the binary, and -h <word> prints just the section that matches. That
makes Jacksum a decent lookup tool even when you are not hashing anything.
$ jacksum -h -E # all 19 encodings, with their alphabets
$ jacksum -h --style # every style, with a feature matrix
$ jacksum -h -q # all input types for -q
$ jacksum -h algorithms # all 586 algorithms
$ jacksum -h examples # the whole EXAMPLES section
$ jacksum -h "exit status" # the exit codes
--exact restricts the match to one option:
$ jacksum --exact -h -g
-g <count>
--group-bytes <count>
Group the hex output for the checksum in <count> bytes for
better readability, only valid if encoding is hex or hexup.
...
If nothing matches, the exit code is 1 — so you can test for the existence of an option in a script:
$ jacksum --exact -h --nonexistent > /dev/null 2>&1 ; echo $?
1
--header prints a block of environment information in front of the actual output — JVM vendor and
version, operating system, architecture, the working directory, and the exact arguments Jacksum was
invoked with. Useful for reproducible reports and for bug reports.
$ jacksum --header -q txt:
#
# created by: Jacksum (https://jacksum.net, version: 4.0.0)
# invoked on JVM: OpenJDK 64-Bit Server VM (vendor: Eclipse Adoptium, version: 25.0.4+7-LTS)
# invoked on OS: Mac OS X (arch: aarch64, version: 26.6.1)
# invoked on date: 2026-08-16T22:35:01.152+02:00
#
# invoked from: /private/tmp/jacksum-hacks-demo
# invocation args: --header -q txt:
#___________________________________________________________________________________________
a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a