Progress and Records
A loop tells you nothing until it ends. Parallel can narrate a run while it happens, and write down what it did so the run can be audited — or resumed — afterwards. Everything here was run for real in transcripts t04, t04b, t09 and t09b.
While it runs: --bar, --eta, --progress
--bar draws a progress bar on the
terminal that redraws itself as jobs
complete:
$ parallel --bar sleep 0.4 ::: 1 2 3 4 5 6 7 8 9 10 11 12
100% 12:0=44s 12
(the elapsed figure is this capture's
own truth — the lab machine was under
heavy load; transcript t04b explains).
--progress prints a plainer text
summary as it goes, and --eta adds an
estimate of the time remaining. All
three write to standard error, so they
never pollute output you are piping
somewhere.
Afterwards: the job log
--joblog FILE writes one line per job:
$ ls samples/*/*.txt | parallel --joblog jobs.log sha256sum {} > checksums.txt
$ head -3 jobs.log
Seq Host Starttime JobRuntime Send Receive Exitval Signal Command
1 : 1792888022.580 0.042 0 93 0 0 sha256sum samples/north/notes-01.txt
2 : 1792888022.603 0.060 0 93 0 0 sha256sum samples/north/notes-02.txt
The columns that matter day to day: Seq (the job's number), Exitval (0 means success — anything else is the command's failure code) and JobRuntime in seconds. Because the log is plain tab-separated text, the usual tools read it. From transcript t04, the total work across twelve checksum jobs:
$ awk "NR>1 {t+=$4} END {print \"total job time:\", t, \"seconds across\", NR-1, \"jobs\"}" jobs.log
total job time: 0.702 seconds across 12 jobs
0.702 seconds of job time in all — the jobs are quick; the log is how you can prove it afterwards instead of remembering it.
Every output, filed: --results
--results DIR saves each job's
standard output and standard error to
its own files:
$ parallel --results outdir/ echo processed {} ::: samples/north/notes-01.txt samples/south/notes-08.txt
$ find outdir -type f | sort
outdir/1/samples+znorth+znotes-01.txt/seq
outdir/1/samples+znorth+znotes-01.txt/stderr
outdir/1/samples+znorth+znotes-01.txt/stdout
outdir/1/samples+zsouth+znotes-08.txt/seq
outdir/1/samples+zsouth+znotes-08.txt/stderr
outdir/1/samples+zsouth+znotes-08.txt/stdout
The path is the input with its slashes
rewritten (/ becomes +z), under a
folder per input source. After a
five-hundred-job run, this is how you
find the one job that complained without
scrolling a terminal.
Picking up after failure
The job log is also the resume ticket. Two different continuations exist, and transcript t09 keeps them straight:
--resume --joblog FILE— for a run that was interrupted. Jobs already in the log are skipped, the rest of the list runs. (In the lab's finished test run every job was in the log, so--resumeran nothing and exited 0.)--retry-failed --joblog FILE— for a run that finished with failures. Only the jobs whose Exitval was not 0 run again:
$ parallel --joblog resume.log 'echo ran {} >> ran.txt; test -f {}' ::: present-a absent present-b
parallel exit: 1
$ touch absent
$ parallel --retry-failed --joblog resume.log 'echo ran {} >> ran.txt; test -f {}' ::: present-a absent present-b
parallel exit: 0
$ cat ran.txt
ran present-a
ran absent
ran present-b
ran absent
absent ran twice — once failing, once
after the fix — and nothing else
repeated. Fix the cause, re-run the
failures, leave the successes alone:
that is the whole workflow, and it is
the strongest reason to give every
serious run a job log.