Skip to content

Instantly share code, notes, and snippets.

@jan-swiecki
Last active March 30, 2023 17:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jan-swiecki/83873511281d5e7648f1bc06c50d278f to your computer and use it in GitHub Desktop.
Save jan-swiecki/83873511281d5e7648f1bc06c50d278f to your computer and use it in GitHub Desktop.
#!/bin/bash
# This script doesn't work with apt-get update (even with -q). Kill -0 exits immediately.
print_empty_lines() {
for x in $(seq "$1"); do
tput el
echo
done
}
loading="/"
rotate_loading() {
case "$loading" in
"|") loading="/" ;;
"/") loading="-" ;;
"-") loading="\\" ;;
"\\") loading="|" ;;
esac
}
# stream_log_exec () {
DISPLAY_LINES=10
ERR_DISPLAY_LINES=20
COLOR='\033[0;34m'
RESET='\033[0m'
logfile=$(mktemp --suffix .log)
echo ">>> running: $*" >&2
echo -en "\033[6n"; IFS=';' read -sdR -a pos; init_row="${pos[0]#*[}"; init_row=$((init_row-1))
lines=$(tput lines)
diff_lines=$((lines-init_row))
if [[ $diff_lines -le "$DISPLAY_LINES" ]]; then
init_row=$((lines - DISPLAY_LINES - 1))
if [[ $init_row -lt 0 ]]; then
echo "error: init_row<0 ($init_row)" >&2
exit 1
fi
fi
print_empty_lines "$DISPLAY_LINES"
tput el1
tput cup "$init_row" 0
cleanup_pid () {
tput cnorm
if kill -0 "$1" &>/dev/null; then
kill "$1"
fi
if kill -0 "$1" &>/dev/null; then
echo "Couldn't kill $1 - sending SIGKILL (logfile: $logfile)" >&2
kill -9 "$1"
fi
}
goto_row () {
tput el
tput cup "${1:-$init_row}" 0
}
tail_stream () {
goto_row "$init_row"
cols=$(tput cols)
echo -ne "$COLOR"
sed_prefix=">> "
sed_prefix_len="${#sed_prefix}"
truncate=${1:-$DISPLAY_LINES}
truncate=$((truncate-1)) # because of loading indicator below
tail -n "$truncate" "$logfile" | fold "-w$((cols-sed_prefix_len))" | tail -n "$truncate" | sed -E 's/^/>> /g' | while read -r line; do
tput el
echo "$line"
done
echo "$loading"
rotate_loading
echo -ne "$RESET"
}
# Function to handle command execution and dynamic output
run_command() (
# Execute the command and pipe the output to a temporary file
"$@" > "$logfile" 2>&1 &
# Get the process ID of the last background command
local cmd_pid=$!
tput civis
trap "cleanup_pid '$cmd_pid'" EXIT
# echo -ne "$COLOR"
tail_stream
# Continuously display the last N lines of the output
while kill -0 $cmd_pid 2>/dev/null; do
tail_stream
sleep 0.1
done
tail_stream
num_output_lines=$(<"$logfile" wc -l)
if [[ "$num_output_lines" -eq 0 ]]; then
echo ">> (No output)" >&2
fi
echo -en "\033[6n"; IFS=';' read -sdR -a pos; curr_row="${pos[0]#*[}"; #curr_row=$((curr_row-1))
if [[ $num_output_lines -lt "$DISPLAY_LINES" ]]; then
# +2 if loader is enabled (probably), otherwise +1
go_up_by=$((num_output_lines+2))
else
go_up_by=$((DISPLAY_LINES+1))
fi
set +eo pipefail
wait "$cmd_pid"
exit_code=$?
goto_row "$((curr_row-go_up_by))"
if [[ $exit_code -gt 0 ]]; then
tail_stream "$ERR_DISPLAY_LINES"
else
print_empty_lines "$DISPLAY_LINES"
goto_row "$((curr_row-go_up_by-1))"
fi
# echo -ne "$RESET"
if [[ $exit_code -gt 0 ]]; then
# echo ">>> running: $* (command exited with status $exit_code, full log available at: $logfile))" >&2
echo ">>> command exited with status $exit_code (full log available at: $logfile)" >&2
return "$exit_code"
else
echo ">>> success: $* (full log available at: $logfile)" >&2
# echo ">>> command finished successfully (full log available at: $logfile)" >&2
fi
)
run_command "$@"
# }
# stream_log_exec "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment