[SOLVED] Timing a running process in bash script - having my cake and eating it too :-)
Linux - SoftwareThis forum is for Software issues.
Having a problem installing a new program? Want to know which application is best for the job? Post your question in this forum.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Timing a running process in bash script - having my cake and eating it too :-)
I need to call a process from a script. It may or may not complete in a reasonable amount of time. I would like to be able to "start the clock" on the process and then, if the process completes I would examine the return code and move on. If I reach my timeout limit I would take other actions. Here is a test script which I have written in an attempt to figure this out
Code:
#!/bin/bash
function my_function {
declare -i j=0
while [ $j -lt 5 ]
do
echo hello
j=$j+1
done
sleep 5
echo
return 27
}
SECONDS=0
running=0
elapsedseconds=0
while [ $elapsedseconds -lt 10 ]
do
if [ $running -eq 0 ]
then
running=1
my_function
else
sleep 1
fi
elapsedseconds=$SECONDS
echo $elapsedseconds
done
echo "time is up!"
echo $?
In this case "my_function" will launch and control will NOT return to the script until my_function completes. If I change the script to execute my_function& control returns to the calling script but I loose the return code from my_function. With my_function& and setting the sleep in the function to 15 illustrates part of what I wish to achieve.
In my actual script my_function will call an external script and I could, using my typical big hammer programming approach, simply wait for a reasonable time and the check to see if the process has completed satisfactorily. If not I will kill the process with my big hammer and move on to take remedial action. That would get the job done but it is rather crude. Any suggestions?
TIA,
Ken
p.s. Bonus question
Why do I have to declare j as an integer lest I get an error "integer expression expected" while I do NOT have to declare elapsedseconds?
there is a command timeout (see man page) to limit execution time and there is a command time (as bash builtin and external command too) to measure execution time. You do not need to [re]implement.
Quote:
Originally Posted by taylorkh
Why do I have to declare j as an integer lest I get an error "integer expression expected" while I do NOT have to declare elapsedseconds?
Because you made an arithmetic operation with that variable.
Probably would be better to use (( )) for that.
j=0
while [ $j -lt 5 ]; do
echo "$j"
j=$(($j + 1))
done
Code:
my_function() {
sleep 1000 & #simulate long process
p=$! #get pid
for j in {0..4}; do
echo "Running for "$((++j))" seconds."
sleep 1
done
echo "time is up, killing pid "$p""
kill "$p"
}
I do not need to kill the long running process. What I wish to do is:
1 - start the VPN connection process
2 - hope for the best
3 - wait for perhaps 30 seconds
4 - check to see if the VPN is connected
5 - based on what I see in the log take some remedial action
6 - try again to start the VPN
I have seen cases where the connection process stalls and never returns. Thus I need to run the clock in parallel with the connection process. On the other hand I do not want to check immediately after initiating the connection process. It needs time to work.
On third thought perhaps I will fire it off, sleep 30 and then begin checking. I have gotten myself confused in where and how I want to divide control logic and timing between my functions and the main script. Time for some pencil and paper I think.
Recent bash versions have an environment variable called SECONDS that contains exactly that - for how many seconds the script has been running.
So instead of defining your own SECONDS you could/should just use that, no?
I have been playing around with that. Looking at your reply again caused an idea to pop into mind. I write log entries from the various parts of my script. I might be able to launch the connection process in background and then have a loop in them main scrip which will periodically tail the log to look for a successful VPN connection. Better yet, what I have been working on yesterday, are some state variables which show if the VPN is connected and what sort of connection I want (no connection, a specific exit server, a random connection server from a preferred list or just the "fastest" server based on latency.) I could simply check one of those variables which would be adjusted by the connection function (if a background process can change a variable initialized in the calling script - need to check that.)
Thanks ondoho and teckk,
I have played around with SECONDS. As I described above I do not really need to know how long the connection process took. Rather I need to know when it completed or if it is taking too long I need to take remedial action. This script is definitely sufferomg from scope creep
Thanks to all the contributors to this thread. I think I have got it figured out now. Here are my test scripts. First my function which will reside in a separate file (two.sh in this test case) with a bunch more functions
Code:
#!/bin/bash
# this function will be called to connect the VPN
function something {
# start by disconnecting any current connection - also seems to clear a failed connection
echo `date` " Disconnecting VPN" >> /var/log/protonvpn.log
pvpn -d | tee -a /var/log/protonvpn.log
# now make the fresh connection
echo `date` " Connecting fastest VPN server" >> /var/log/protonvpn.log
pvpn --cc US | tee -a /var/log/protonvpn.log
# let us see what we are conected to
pvpn --status | tee -a /var/log/protonvpn.log
return
}
And then the calling script
Code:
#!/bin/bash
# bring in the various functions needed by the script (only 1 in this test case)
source two.sh
# vpnon is used for state tracking in the real script
vpnon=0
j=0
# call the function to connect the VPN
something&
# keen an eye on the log to see when (if) the VPN connects
while [ $j -le 60 ]
do
if tail /var/log/protonvpn.log | grep "Connected!" > /dev/null
then
j=61
vpnon=1
fi
(( j = $j +1 ))
echo "j = " $j
echo "vpnon = " $vpnon
sleep 1
done
if [ $vpnon -eq 1 ]
then
echo "VPN connected successfully"
else
echo "VPN connection failed :-( need to fix it"
fi
I have tested this process under various scenarios and it seems to work as desired. In addition, I observed the mysterious "[!] Error: There is an internet connection issue." error which sometimes hoses my current connection script. I think I will look for it in the log file from within the same loop rather than after the connection process completes. I will set a state variable to hold that information so that after the 60 second allotted time I can cycle the network connections on the Pi which from experience will fix things. Then the production loop will detect that the VPN is SUPPOSED to be running and that it is NOT running and it will then re-try the connection. I love it when a plan comes together
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.