Skip to content

Instantly share code, notes, and snippets.

@felixr
Last active March 28, 2025 21:43
Show Gist options
  • Save felixr/936d4b43e26502396a15f2b2f1a67178 to your computer and use it in GitHub Desktop.
Save felixr/936d4b43e26502396a15f2b2f1a67178 to your computer and use it in GitHub Desktop.
bash: run multiple commands and show last line of output
#!/bin/bash
TMPDIR="$(mktemp -d)"
cmd_status() {
local pid=$1
local cmd=$2
local log=$3
if ps h ${PIDS[$cmd_idx]} > /dev/null; then
echo -e "› \033[32m${cmd}\033[0m"
else
wait $pid
code=$?
echo -e "✔ [${code}] \033[90m${cmd}\033[0m"
fi
tail -n10 "${log}" 2>/dev/null
}
SPINNER=("( ● )" "( ● )" "( ● )" "( ● )" "( ●)" "( ● )"
"( ● )" "( ● )" "( ● )" "(● )")
spinner() {
local i=$1
i=$(( i % ${#SPINNER[@]} ))
echo -n "${SPINNER[$i]}"
}
CMDS=(
"ping -c 10 google.com"
"vmstat 1 5"
"find /usr -type f"
"exit 255"
)
PIDS=()
cleanup () {
tput cnorm;
# Kill background jobs
if [[ ${#PIDS[@]} -gt 0 ]]; then
kill -15 "${PIDS[@]}" > /dev/null 2>&1
sleep 0.5
kill -9 "${PIDS[@]}" > /dev/null 2>&1
echo "KILLED"
fi
rm -rf -- "$TMPDIR"
}
trap cleanup SIGINT SIGTERM
# Start the jobs
idx=0
for ((i = 0; i < ${#CMDS[@]}; i++)); do
${CMDS[$i]} &> ${TMPDIR}/cmd_${idx}.log & PIDS+=($!)
idx=$((idx+1))
done
update_loop() {
tput civis # cursor invisible
local num_lines=0
local cnt=0
local done=0;
while true; do
test ${num_lines} -gt 0 && tput cuu $num_lines
echo "Running ${idx} commands $(spinner $cnt)"
num_lines=1
cnt=$((cnt+1))
for cmd_idx in $(seq 0 $((idx -1))); do
logfile="${TMPDIR}/cmd_$cmd_idx.log"
output=$(cmd_status "${PIDS[cmd_idx]}" "${CMDS[cmd_idx]}" "${logfile}")
output_lines=$(echo "${output}" | wc -l)
while IFS= read -r line; do
tput cr; tput el #clear_line
echo -e "${line}"
done <<< "${output}"
num_lines=$((num_lines + output_lines))
done
[[ $done == 1 ]] && break
jobs | grep Run >/dev/null || done=1
sleep 0.2
done
tput cnorm # cursor normal = visible
}
update_loop
cleanup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment