1

I have a script to do a lot of stuff, for example:

echo -e " finding mp3 files"
find / *.mp3
Elapsed time: 0

Assume this took 10 seconds.

A function to copy them to some location (this only an example, not my actual script):

echo copying files;
cp *.mp3 /
elapsed time: 6

I need a way to calculate and show a running clock while find finds all files, and after that to reset and show a new running clock while cp copies the files.

I tried this:

Timing () {
SECONDS=0; while true do;
printf '\e[1;96mElapsed Time: %dm:%ds\e[0m\n' $(($SECONDS%3600/60)) $(($SECONDS%60))
done &
}

and then call this function when doing the command.

However, I can’t reset the time and I cannot exit this background while loop.

Here is the full script that I want to add the timing function to:

#!/bin/bash

#--------------------------------------------------------------------------------#
#                  Modify to Match your Environment                              #
#--------------------------------------------------------------------------------#

#enter managed servers names  STARTING ORDER  seperated by 'space'
#COMPNENTS Y or N in CAPS litters 

MANAGED_SERVERS_NAMES="WLS_FORMS WLS_REPORTS"
NODEMANAGER_SCRIPT_LOCATION="$WLS_HOME"/server/bin/startNodeManager.sh 
DOMAIN_ENV_LOCATION="$DOMAIN_HOME"/bin/setDomainEnv.sh
ADMINSERVER_SCRIPT_LOCATION="$DOMAIN_HOME"/bin/startWebLogic.sh
MANAGED_SERVERS_SCRIP_LOCATION="$DOMAIN_HOME"/bin/startManagedWebLogic.sh
OPMNCTL_COMPONENTS=Y
EMCTL_COMPONENT=Y


################################################################################
#--------------------------------------------------------------------------------#
#           This Script Is A CopyRight To KhaLiD Abo EL MaGd                     #
#                  Don't Modify Any Thing in This Section                        #
#                                                                                #
#--------------------------------------------------------------------------------#
set -e
clear
TFILE=starting.log
debug=$1
if [[ -n "$debug" ]]; then
cat /dev/null > ${TFILE}
gnome-terminal  -e  "tail -F $TFILE" &
fi

Check_Status_NM ()
{
tail -f ${TFILE} | while read LOGLINE
do
    if [[ "${LOGLINE}" == *"Secure socket listener started on port"* ]] 
    then
    echo -e "\e[92mNodeManager Started\e[0m"
    pkill -P $$ tail
    break
    elif [[ "${LOGLINE}" == *"Address already in use"*  ]]; then
    pkill -P $$ tail
    echo -e "Cannot Start NodeManager\nSee ${TFILE} for more info\n "
  printf '\e[1;96mElapsed Time: %dm:%ds\e[0m\n' $(($SECONDS%3600/60)) $(($SECONDS%60))
  echo ""
  echo "$SECONDS" > time
    exit 1
    nohup kill -9 `ps -ef | grep ${TFILE} | awk '{print $2}'`  > /dev/null 2>&1 &
    echo "Total Time: $(cat time |   paste -sd+ |  bc)s"
    rm -rf time
    fi
done
}
#----------------------------------------------------------------
Check_Status ()
{
sleep 2
tail -F ${TFILE} | while read LOGLINE
do
  if [[ "${LOGLINE}" == *"<Server state changed to STANDBY>"* ]]; then
    echo -e "\e[94mServer state changed to STANDBY\e[0m"
  elif  [[ "${LOGLINE}" == *"<Server state changed to >"* ]]; then
      echo -e "\e[94mServer state changed to ADMIN\e[0m"
  elif [[ "${LOGLINE}" == *"<Server state changed to RESUMING>"* ]]; then
     echo -e "\e[94mServer state changed to RESUMING\e[0m"
  elif  [[ "${LOGLINE}" == *"<Server state changed to STARTING>"* ]]; then
      echo -e "\e[94mServer state changed to STARTING\e[0m"


    elif [[ "${LOGLINE}" == *"The Network Adapter could not establish the connection"* ]] ; then
    echo -e "\e[5m\e[93mWARNING\e[0m Could not establish the connection\n\e[91mCheck Connection to Database\e[0m"
   elif  [[ "${LOGLINE}" == *"<Server state changed to STARTING>"* ]]; then
      echo -e "\e[94mServer state changed to RUNNING\e[0m"
    elif [[ "${LOGLINE}" == *"<Server started in RUNNING mode>"* ]] || [[ "${LOGLINE}" == *"<Demo trusted CA certificate is being used in production mode:"* ]];then
    echo -e "\e[92mServer Started\e[0m"
      pkill -P $$ tail
    cat /dev/null > ${TFILE}
    break
    elif [[ "${LOGLINE}" == *"<Server state changed to FORCE_SHUTTING_DOWN>"* ]]; then
      pkill -P $$ tail
     echo -e "\e[91mCannot Start Server\e[0m\nSee ${TFILE} for more info\n"
    printf '\e[1;96mElapsed Time: %dm:%ds\e[0m\n' $(($SECONDS%3600/60)) $(($SECONDS%60))
    echo ""
   echo "$SECONDS" >> time
    nohup kill -9 `ps -ef | grep ${TFILE} | awk '{print $2}'`  > /dev/null 2>&1 &
    echo "Total Time: $(cat time |   paste -sd+ |  bc)s"
    rm -rf time
    exit 1
    fi
done
}
#---------------------------------------------------------------------------------------
#Start NodeManager:
SECONDS=0
echo -e "Starting NodeManager..."
nohup "$NODEMANAGER_SCRIPT_LOCATION"  > ${TFILE}  2>&1 &
 Timing ******************
Check_Status_NM
printf '\e[1;96mElapsed Time: %dm:%ds\e[0m\n' $(($SECONDS%3600/60)) $(($SECONDS%60))
echo ""
echo "$SECONDS" >> time
#Start WebLogic AdminServer------------------------------------------------
SECONDS=0
echo -e "Starting AdminServer..." 
nohup "$DOMAIN_ENV_LOCATION" > ${TFILE}   2> /dev/null &
 Timing ********************
nohup  > ${TFILE} "$ADMINSERVER_SCRIPT_LOCATION"  2> /dev/null &
Check_Status
printf '\e[1;96mElapsed Time: %dm:%ds\e[0m\n' $(($SECONDS%3600/60)) $(($SECONDS%60))
echo ""
echo "$SECONDS" >> time
#----------- MANAGED SERVERS------------------------------
for i in ${MANAGED_SERVERS_NAMES}
do
SECONDS=0
echo "Starting $i Server..."
nohup ${MANAGED_SERVERS_SCRIP_LOCATION} $i  > ${TFILE}  2> /dev/null &
Check_Status
printf '\e[1;96mElapsed Time: %dm:%ds\e[0m\n' $(($SECONDS%3600/60)) $(($SECONDS%60))
echo ""
echo "$SECONDS" >> time
done
nohup kill -9 `ps -ef | grep ${TFILE} | awk '{print $2}'`  > /dev/null 2>&1 &

#--------------------- OPMNCTL------------------------
if [[ "${OPMNCTL_COMPONENTS}" == *"Y"* ]]; then
SECONDS=0
echo -e "Starting opmn components"
nohup opmnctl startall > /dev/null 2>&1 &
sleep 2
if ( opmnctl status |grep --quiet Init); then
echo -e "\e[94mWaiting For opmn components to Start\e[0m"
opmnctl status |grep -v --quiet Init
opm_pid=$!
while [ -d /proc/$opm_pid ]; do
    echo -n "."
    sleep 2
done
else
echo -e "\e[92mStarted\e[0m" 
fi
opmnctl status | grep -v Alive
printf '\e[1;96mElapsed Time: %dm:%ds\e[0m\n' $(($SECONDS%3600/60)) $(($SECONDS%60))
echo ""
echo "$SECONDS" >> time
fi
#---------------------EMCTL-----------------------------------
if [[ "${EMCTL_COMPONENT}" == *"Y"* ]]; then
SECONDS=0
emctl start agent
printf '\e[1;96mElapsed Time: %dm:%ds\e[0m\n' $(($SECONDS%3600/60)) $(($SECONDS%60))
echo ""
echo "$SECONDS" >> time
fi
#-----------------------------------------------------------
TIMEE=$(cat time |   paste -sd+ |  bc)
echo ""
printf '\e[1;96mTotal Time: %dm:%ds\e[0m\n'  $(($TIMEE%3600/60)) $(($TIMEE%60))
cat /dev/null > time
exit 0

i was able to mostly get what i want by doing this based on answers but i want to know how to kill the while loop in Check_Status function after it prints server started or Cannot Start Server

echo -e "Starting AdminServer..." 
nohup "$DOMAIN_ENV_LOCATION" > ${TFILE}   2> /dev/null &
START_TIME=$(date +%s)
nohup  > ${TFILE} "$ADMINSERVER_SCRIPT_LOCATION"  2> /dev/null &
Check_Status &
while [[ -d /proc/$! ]]; do
SECONDS=$(( $(date +%s)-START_TIME ))
 printf "\e[1;96mElapsed Time: %02dm:%02ds\e[0m\r" $(($SECONDS%3600/60))     $(($SECONDS%60))
done
printf "\e[1;96mElapsed Time: %dm:%ds\e[0m\n" $(($SECONDS%3600/60))    $(($SECONDS%60))
echo "$SECONDS" >> time
9
  • 2
    What's wrong with time? E.g. time sleep 3 should show the elapsed time, along with other values.
    – thrig
    Aug 23, 2016 at 19:10
  • i don't need a sleep time ..as the main script go to search for some words in log files and if it found exact word it gives my the status of the server Aug 23, 2016 at 19:12
  • also i cannot kill the background loop Aug 23, 2016 at 19:13
  • I understand you want bash for this, but just as a suggestion, you might wanna look at some languages that might make it easier. For example, Perl : my $sttime = time; sleep(60); print "Elapsed time : ", time - $sttime;
    – schaiba
    Aug 23, 2016 at 19:14
  • 1
    Could you please edit the question to clarify what you want to output, exactly? The time taken by a single command (or a set of commands) after it finishes? Times for single commands plus a total? A counter running up every second? You may want to consider making the example code a bit shorter and to the point.
    – ilkkachu
    Aug 24, 2016 at 4:46

2 Answers 2

4

This one shows the time when it is done:

#! /bin/bash
START_TIME=$(date +%s)
echo -n Finding mp3 files
sleep 3 # some time consuming command
echo .\ Elapsed time: $(( $(date +%s)-START_TIME ))

It will respond:

Finding mp3 files

and then

Finding mp3 files. Elapsed time: 3

If you want to see the time counting up while waiting, the time consuming command must not echo anything (of course).

#! /bin/bash
START_TIME=$( date +%s )
echo Finding mp3 files
sleep 3 & # some time consuming command
while [[ -d /proc/$! ]]; do
    echo -en \\rElapsed time: $(( $(date +%s)-START_TIME ))
    sleep 0.1
done
echo .

Explanation: When the command goes in the background with & it leaves the process id number in $!. This process is represented by a (virtual) directory in /proc/$!. As long as this directory exists, the command is running and we are counting up the time.


Third example; more like the question. Replace sleep 3 with the time consuming command.

#! /bin/bash
echo "Starting NodeManager..."
START_TIME=$(date +%s)
nohup sleep 3 &
while ps -p $! > /dev/null ; do
    SECONDS=$(( $(date +%s)-START_TIME ))
    printf "\r\e[1;96mElapsed Time: %02dm:%02ds\e[0m" $(($SECONDS%3600/60)) $(($SECONDS%60))
done
Echo

Edit: The third example now show the right way to test for a process is still running. (but it has to launch a process ps and thus it is slower - your choice)

10
  • thank you ...but the command echo some information about the status of the server which it take it from the log.... i need something like wget or scp it echo data and gives elapsed time Aug 23, 2016 at 21:22
  • That is what the first example shows.
    – hschou
    Aug 23, 2016 at 21:25
  • i tried it but it just echo one time as i put it as a function and call it .. here is the code Timing () { START_TIME=$(date +%s) sleep 1 echo .\ Elapsed time: $(( $(date +%s)-START_TIME )) } #Start NodeManager: echo -e "Starting NodeManager..." nohup "$NODEMANAGER_SCRIPT_LOCATION" > ${TFILE} 2>&1 & Timing Check_Status_NM printf "\e[1;96mElapsed Time: %dm:%ds\e[0m\n" $(($SECONDS%3600/60)) $(($SECONDS%60)) echo "$SECONDS" >> time Starting NodeManager... . Elapsed time: 1 NodeManager Started Elapsed Time: 0m:3s Aug 23, 2016 at 21:45
  • i also tried to put it as you showed but its not counting Aug 23, 2016 at 21:49
  • Thank you again...but it doesn't work ..as it in first place i can't use sleep as the main function of the script is to go to the logs and find the stat of the server ..when it changes to running it go to the next server and start it ...in you example you missed the function (Check_Status_NM) that is do all the job of checking the status of the server till it become running ...again thank you very much Aug 24, 2016 at 8:02
2

You can use pv:

sleep 10 | pv -t

find / -name '*.mp3' | pv -t

pv is a pass-through like cat (sometimes even more efficient as it uses system calls like splice() where possible), that writes the timing information on stderr.

If you want to display Elapsed time: as well:

pv -N 'Elapsed time' -t

or (with newer versions):

pv -F 'Elapsed time: %t'

If using zsh, ksh or bash, you may want want to set the pipefail option to not lose the exit status of the command being monitored:

timewatch() (
  set -o pipefail
  "$@" | pv -tN 'Elapsed time'
)

timewatch find / -name '*.mp3' || handle_error

Not the answer you're looking for? Browse other questions tagged .