Parallel xargs with an actual progress indicator
xargs -P 8 is most of what I need from parallel, minus the progress indicator. Adding one is not hard if you accept that you need a counter in a separate process. I use a FIFO and a tiny awk consumer.
#!/usr/bin/env bash
set -euo pipefail
jobs=()
while IFS= read -r line; do jobs+=("$line"); done
total=${#jobs[@]}
fifo="$(mktemp -u)"
mkfifo "$fifo"
trap 'rm -f "$fifo"' EXIT
# Background counter: reads one line per completed job.
(
awk -v total="$total" '
{ i++; printf "\r %d / %d done", i, total > "/dev/stderr" }
END { print "" > "/dev/stderr" }
' < "$fifo"
) &
printf '%s\n' "${jobs[@]}" | \
xargs -P 8 -I {} bash -c '
if output=$("$0" "$1" 2>&1); then
printf "ok\n" > "$2"
else
printf "ok\n" > "$2"
printf "FAIL %s\n%s\n" "$1" "$output" >&2
fi
' my_worker.sh {} "$fifo"
wait
The subshell writes “ok” to the FIFO when a job finishes (success or failure). The awk consumer increments a counter and redraws the line. Progress stays on stderr so the stdout pipe is unaffected. The FIFO closes automatically when xargs is done.
See also /snippets/bash-trap-cleanup-tmpdir/.