Bash: while loop to print message as long as command runs

Viewed 37

A while ago, we upgraded to the latest version of Laravel Mix. This has a much more visual output when running commands like yarn mix --production, but it creates an issue for us on tools like Forge and Ploi, since the progress bar is not seen by these tools, and our deployment return an error, since Forge and Ploi think that the command is stuck, as it runs for 5 - 15 minutes due to the huge amount of code it needs to compile.

While we are working on optimizing our code to reduce compilation time, I am looking for a way to get the current code compiled in Forge or Ploi. I came up with the following idea:

If the progress bar is not seen, maybe I can echo a line of text as long as the command runs, which hopefully will prevent the timeout. To achieve this, I created the following script:

COUNTER=0;
while yarn mix --production &> /dev/null;
do
  echo "Running for" $COUNTER "seconds";
  sleep 10;
  let "COUNTER += 10";
done

... but this doesn't seem to do the trick as nothing is printed after 10 seconds. I'm a noob with bash, so maybe someone can help me point out what I'm doing wrong?

PS: I'm doing &> /dev/null to avoid having both the counter and the progress bar, as the --no-progress flag doesn't seem to do that.

2 Answers

Well, you need to run your command in the background if you want to be able to do something else while it runs. Otherwise, while condition will be evaluated only when yarn is finished

You need something like :

yarn mix --production < /dev/null 1> /dev/null &
pid=$!
COUNTER=0;
while kill -0 $pid &> /dev/null
do
  echo "Running for" $COUNTER "seconds";
  sleep 10;
  let "COUNTER += 10";
done

Edit: replaced jobs -p | grep -q $pid by kill -0 $pid &> /dev/null after Jetchisel's comment. It's better than piping the output of jobs and feeding it to a grep subprocess...

Here is how I did waiting animation in my sshto and kube-dialog projects:

Waiting(animation) function:

   x=$[COLUMNS/2-3]
   y=$[  LINES/2-3]
sand=( ⠁  ⠂  ⠄  ' ' )
#  {   small digits    }
sd=(₀ ₁ ₂ ₃ ₄ ₅ ₆ ₇ ₈ ₉)
bs='⠴⠷⠦' # bottom sand pile
ts='⠖'    #  top  sand pile
WAIT(){
    clear; cursor off; i=0; start=$SECONDS
    XY $[x-1]  $y    $UND$BLD$RED'       '$DEF                     # _______
    XY $[x-1] $[y+1]         $RED'╲'$DIM$UND'     '$DEF$red'╱'$DEF # ╲_____╱
    XY  $x    $[y+2]         $BLU'(  '$BLD$WHT'•'$BLD$BLU')'$DEF   #  (  •)
    XY  $x    $[y+3]         $BLU' ╲'$YLW"$ts"$BLD$BLU'╱'$DEF      #   ╲⠖╱
    XY  $x    $[y+4]         $BLU" ╱$YLW${sand[$i]}$BLD$BLU╲"$DEF  #   ╱⠂╲
    XY  $x    $[y+5]         $BLU'('$YLW"$bs"$BLD$BLU')'$DEF       #  (⠴⠷⠦)
    XY $[x-1] $[y+6]         $RED'╱'$RED'‾‾‾‾‾'$BLD$RED'╲'$DEF     # ╱‾‾‾‾‾╲
    XY $[x-1] $[y+7]     $DIM$RED'‾‾‾‾‾‾‾'$DEF                     # ‾‾‾‾‾‾‾
    ( while true; do sleep 0.07
        printf -v counter "%03d" $[SECONDS-start]
        small="${sd[${counter:0:1}]}${sd[${counter:1:1}]}${sd[${counter:2:1}]}"
        XY $[x-1] $[y+1] $RED'╲'$DIM$UND" $small "$DEF$red'╱'$DEF
        XY  $x    $[y+4] $BLU" ╱$YLW${sand[$i]}$BLD$BLU╲"$DEF
#       XY $[x+1] $[y+8] $DEF$BLD"$counter"$DEF
        ((i++)); (($i==${#sand[@]})) && i=0;
    done ) & waiter=$!
}

Color vars, 'XY' and 'cursor' functions are from here.

Stop animation function:

GO() { [[ -e /proc/$waiter ]] && kill $waiter; cursor on; clear; }

And here is how to start some command using it:

WAIT; some_command &> /dev/null; GO

The trick is not the main command gone to background but 'waiter'. This way you can wait for not only one command but many:

WAIT
cmd1 &> /dev/null
cmd2 &> /dev/null
cmd3 &> /dev/null
GO

The animation:

waiting animation

p.s. another example with cp animation here.

Related