rafa
rafa

Reputation: 795

Show elapsed time every second running a bash script

I'm running a shell script in Linux Mint that calls some processes taking few minutes. For each process I want to echo a message like this:

echo "Cleaning temporary files... X seconds."
myprocess

where X is the current elapsed time and I would like it to change every second, but not printing a new line.

Is there a good way to do that? I only found ways to print the total time in the end, but not the elapsed time while running the process.

Upvotes: 7

Views: 4442

Answers (4)

Spencer Rathbun
Spencer Rathbun

Reputation: 14900

You'll have to run the process in the background with &, otherwise the rest of the script will wait until it finishes. Use backspaces to overwrite your current line, so make sure you don't use newlines.

So, to do what you want:

myproc &
myPid=$!  # save process id
tmp=""
while true; do
    if kill -0 "$myPid"; then  # if the process accepts a signal, keep waiting
         for i in {0..${#tmp}..1}; do
             printf "%b" "\b" # print backspaces until we have cleared the previous line
         done
         tmp=$( printf "Cleaning temp files... %t seconds." )
         printf "%s" "$tmp"
     else
         break # drop out of the while loop
     fi
     sleep 1
done

Upvotes: 1

abasu
abasu

Reputation: 2524

Use this at the beginning of your script, this creates a subprocess which runs in background and keeps on updating the status.

file=$(mktemp)
progress() {
  pc=0;
  while [ -e $file ]
    do
      echo -ne "$pc sec\033[0K\r"
      sleep 1
      ((pc++))
    done
}
progress &
#Do all the necessary staff

#now when everything is done
rm -f $file

Upvotes: 10

Olivier Dulac
Olivier Dulac

Reputation: 3791

Here is a way to have awk print on STDERR every seconds. You should just add:

  • when myprocess is over, create a file /tmp/SOMETHING
  • have awk include a test : it exits when /tmp/SOMETHING appears

The loop part (without the termination test... so "infinite loop" until CTRL-C) is:

 ping 127.0.0.1 | awk '
     BEGIN{cmd="date +%s"; cmd|getline startup ; close (cmd) } 
     /bytes from/ { cmd | getline D ; close (cmd) ; 
                    print D-startup | "cat >&2" }'

now you just need to use "printf" and ansi escape sequence to print without a newline, have the ansi-escape go back until the beginning of the number, and flush the output (all descriptors) by invoking system:

 ping 127.0.0.1 | awk -v getback4char="$(printf '\033[4D')"  '
 BEGIN{cmd="date +%s"; cmd|getline startup ; close (cmd) ; printf "Elapsed time: ";}
 /bytes from/ { cmd | getline D ; close (cmd) ;
                printf "%4d%s" ,(D-startup) , getback4char | "cat >&2"
                system("") }'

note: this is compatible with all version of awk I know of, even ANCIENT ones (ie, not gawk/nawk only, but also the venerable awk.)

Upvotes: 0

Claudio
Claudio

Reputation: 10947

You can run each command with time:

time <command>

and then use sed/awk to exctract the elapsed time.

Upvotes: 0

Related Questions