0

I wrote this, using an awk command I found:

RUNS=10
CUR=1
PREFIX=" 1/10 ($((${CUR} * 100 / ${RUNS}))%)"
echo "" | awk '{printf("%'+`expr 2 + ${RUNS} + ${#PREFIX}`+'s\r[", "]'${PREFIX}'")}' ;
for CUR in {1..`expr $RUNS`..1}; do
    echo -n '▒'
    sleep .1
done
echo ""

output:

[▒▒▒▒▒▒▒▒▒▒] 1/10 (10%)

I understand, that the progress bar update make use of the carriage return from the echo command and just overwrites the blanks. Sadly I'm not familiar with awk (nor sed for that matter).

However I wonder, if I can update CUR and the % in PREFIX as well as the current length of the PREFIX string in order to update the awk output (during runtime of cause).

My Cnf is:

$ sw_vers && awk --version && bash --version | grep bash && brew info zsh | grep zsh:
ProductName:    Mac OS X
ProductVersion: 10.15.4
BuildVersion:   19E287
awk version 20070501
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin19)
zsh: stable 5.8 (bottled), HEAD

(even if I'm using zsh, I'd prefer a bash or pure POSIX approach)

matt
  • 105
  • 10
  • Isn't this enough? https://stackoverflow.com/questions/238073/how-to-add-a-progress-bar-to-a-shell-script There are almost 40 answers there. – thanasisp Sep 18 '20 at 13:11
  • ihm afraid not. you're right - there are plenty solutions, how to implement a progress bar in bash (in fact I found this thread, too), what's happened to be what I intend to do. however - none of these solution seems to cover the problem, I ask here for (as far as I saw, the closest to my implementation are stacked loops). But they all make use of `\r` to overwrite the existing text. my question was, if it is possible to simply update a variable (without having to care about how the shell handles the output). (therefore I didn't mentioned the progress bar in the title ;) ) – matt Sep 18 '20 at 14:31
  • 3
    this code is insane. also, when i run it, i get awk: cmd. line:1: {printf("%+23+s\r[", "] awk: cmd. line:1: ^ unterminated string awk: cmd. line:1: {printf("%+23+s\r[", "] awk: cmd. line:1: ^ syntax error – webb Sep 18 '20 at 18:55
  • using `awk` to calculate the `printf` format is a bit excessive; you could do the calculations in `bash` and also call `printf` from `bash`; alternatively ... 1) go back and review those answers/examples from the link @thanasisp provided or 2) take a look at `tput` (eg, [here's a status bar using tput](https://stackoverflow.com/a/59554645/7366100) – markp-fuso Sep 18 '20 at 19:24
  • @markp-fuso thx. also not really an answer to my question but I think I'll go with tput. – matt Sep 24 '20 at 08:19
  • @webb i assume you did't use zsh. with the given config I get the mentioned output – matt Sep 24 '20 at 08:23
  • i do use zsh as my shell, but i'm running your code in bash 5.0 on a mac and getting the aforementioned error. try copying the code you have above, pasting it, saving, and running. sometimes some characters get screwed up when pasting into stackoverflow. – webb Sep 25 '20 at 09:21
  • on a side note, I use that char a lot in my scripts and often it doesn't work as expected. It is intended for shading boxes, so it will render in a funny way in certain conditions. Take the opportunity to think of a different symbol to represent the progress bar – Daemon Painter Sep 25 '20 at 10:32
  • @webb I did that before responding. still.. works for me, using zsh. have you tried running it in zsh? with bash (3.x..) I got an error, too – matt Sep 26 '20 at 07:41
  • @DaemonPainter thx for the tip, I'll consider it. nevertheless - funny you state your problems with it in the same sentence you admit using it yourself a lot :D (that said - my question is, if there is any reason for that) – matt Sep 26 '20 at 07:44
  • Yeah, you are right. I am not in the position to change them all due to time budget and I suffer everytime they go wrong – Daemon Painter Sep 26 '20 at 10:24

1 Answers1

0

Here is perhaps a simpler way to achieve what you need:

RUNS=10
for i in `seq 1 $RUNS`; do
  # overwrite previous line
  printf '\r['
  # print some filled squares
  for j in `seq 1 $i`; do
    printf '▒'
  done
  # print any required empty squares
  if [ $j -lt $RUNS ]; then
    let j=j+1
    for k in `seq $j $RUNS`; do
      printf ' '
    done
  fi
  # print the numeric output
  let percent="100 * $i / $RUNS"
  printf '] %d/%d %d%%' $i $RUNS $percent
  sleep .1
done
# finish with a newline
echo ''

Here is the output (but in practice, each update overwrites the previous output line):

[▒         ] 1/10 (10%)
[▒▒        ] 2/10 (20%)
[▒▒▒       ] 3/10 (30%)
[▒▒▒▒      ] 4/10 (40%)
[▒▒▒▒▒     ] 5/10 (50%)
[▒▒▒▒▒▒    ] 6/10 (60%)
[▒▒▒▒▒▒▒   ] 7/10 (70%)
[▒▒▒▒▒▒▒▒  ] 8/10 (80%)
[▒▒▒▒▒▒▒▒▒ ] 9/10 (90%)
[▒▒▒▒▒▒▒▒▒▒] 10/10 (100%)

PS: To start at 0% not 10%, change both seq 1 to seq 0.

webb
  • 4,180
  • 1
  • 17
  • 26
  • 1
    simple enough, thx. however I've to add a check for the k-loop, to only run, `if [ $j -le $RUNS ]` 'cause otherwise `seq` will run down from 11 to 10 and print two unnecessary blanks (so that the final output would be `[▒▒▒▒▒▒▒▒▒▒ ] 10/10 100%`) - maybe `seq` operates differently in your setting? besides - it there a reason to use `seq` over the `{n..m}` notation (compatibility? best practice? ambiguity in different shells?) – matt Sep 26 '20 at 07:53
  • added suggestion. also, {n..m} doesn't work for me in bash 5.0 with a variable, e.g., zsh: `x=3; echo {1..$x}`: `1 2 3` vs bash 5.0: `echo {1..$x}`: `{1..3}`. whereas `seq` always works, so... – webb Sep 26 '20 at 19:57
  • my research ended up with this: since variable expansion seems to be happened after brace expansion, that won't work in bash. to make it work POSIX conform, you can use `eval`. try this: `x=3; eval 'echo {1..'$x'};'` (doesn't look very maintainable to me so I stick with `seq`) – matt Sep 27 '20 at 02:03