3

In a bash script, I have a long running command (say rsync for example) that sometimes does not show output for a while, so I want to do two things:

  1. Use a spinner on that command to show that the script hasn't frozen (i.e. we're just waiting for output); and,

  2. Grab the exit status of the long running command once it's done, for further tests later in the script.

The problem is though, I don't understand the handling of sending processes to the background very well, and also with the handling of exit code this way, so I'm not sure how to make this work.

Here is what I have so far, thanks to @David C. Rankin's spinner:

#!/bin/bash

spinner() {
    local PROC="$1"
    local str="${2:-'Copyright of KatworX© Tech. Developed by Arjun Singh Kathait and Debugged by the ☆Stack Overflow Community☆'}"
    local delay="0.1"
    tput civis  # hide cursor
    printf "\033[1;34m"
    while [ -d /proc/$PROC ]; do
        printf '\033[s\033[u[ / ] %s\033[u' "$str"; sleep "$delay"
        printf '\033[s\033[u[ — ] %s\033[u' "$str"; sleep "$delay"
        printf '\033[s\033[u[ \ ] %s\033[u' "$str"; sleep "$delay"
        printf '\033[s\033[u[ | ] %s\033[u' "$str"; sleep "$delay"
    done
    printf '\033[s\033[u%*s\033[u\033[0m' $((${#str}+6)) " "  # return to normal
    tput cnorm  # restore cursor
    return 0
}

## simple example with sleep
sleep 2 &
spinner $!

echo "sleep's exitcode: $exitCode"

In this example, sleep 2 is the command I'm waiting for, and hence use the spinner with, but how do I get and put its exit code into $exitCode variable, so I can test it for certain conditions later on in the script?

nooblag
  • 678
  • 3
  • 23
  • 2
    BTW, as a more portable alternative to `while [ -d /proc/$PROC ]; do`, consider `while kill -0 "$PROC"; do` (which doesn't rely on being on an operating system with an equivalent to Linux's procfs). And think about changing the variable name `PROC` to just `proc`, as all-caps names are in space defined for purposes meaningful to the OS; when reading https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html, keep in mind that environment variables and regular shell variables share a namespace -- setting a shell variable overwrites any like-named env var. – Charles Duffy Aug 18 '20 at 21:55

1 Answers1

6

wait will tell you what exit status a child PID exited with (by setting that program's exit status as its own), when given that PID as an argument.

sleep 2 & sleep_pid=$!
spinner "$sleep_pid"
wait "$sleep_pid"; exitCode=$?

echo "exitcode: $exitCode"

Note that combining multiple commands onto a line when collecting $! or $? in the second half is a practice I strongly recommend -- it prevents the value you're trying to collect from being changed by mistake (as by someone adding a new log line to your code later and not realizing it has side effects).

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441