Problem running a program/script in the background from a script
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
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.
Problem running a program/script in the background from a script
Hi all,
I have a script that calls another program/script, xxx, to run in the background. Supposedly this program at most should finish within five (5) minutes so after five (5) minutes, I run some other steps to run the script into completion.
My problem is sometimes the program takes longer than five (5) minutes and this is causing problems when running the rest of the steps in the scripts. Can anyone suggest how to re-program my script.
At the moment, the KSH script, i.e. test.ksh, is doing as below:
test.ksh:
....
....
xxx/xxx.ksh <--- program/script called by the script
sleep 300
..... run the rest of the script ......
...... problem is sometimes xxx/xxx.ksh takes longer than 300 seconds ......
...... any way that I can monitor that xxx/xxx.ksh finishes before I run ......
...... the rest of the scripts ......
Any advise will be much appreciated. Thanks in advance.
Using a fixed time frame is, as you noticed, not the way to go. Using the child's PID and checking its existence might be what you are looking for.
Rough example:
Code:
# the child script:
$ cat foo
#/bin/bash
echo "foo: i'm alive..... I'll sleep for 15 seconds and exit"
sleep 15
echo "foo: Done. exiting now."
# the main script:
$ cat bar
#!/bin/bash
echo "bar: starting foo in background"
./foo &
fooPID="$!"
echo "child pid: $fooPID"
while [[ true ]]
do
if [[ "$(ps -ef | grep $fooPID | grep -v grep)" == "" ]]
then
echo "bar: foo has stopped"
break
else
echo "bar: foo is still running"
fi
sleep 2
done
echo "bar: do more stuff here that depends on stopped foo"
Code:
# example run:
$ ./bar
bar: starting foo in background
child pid: 17157
foo: i'm alive..... I'll sleep for 15 seconds and exit
bar: foo is still running
.
.
.
bar: foo is still running
foo: Done. exiting now.
bar: foo has stopped
bar: do more stuff here that depends on stopped foo
There are other ways as well: let foo create a temporary file, which foo removes as last step. bar checks if the file exists, if it does: foo is still running.
Hope this helps.
Last edited by druuna; 03-27-2011 at 09:44 AM.
Reason: Spelling/grammar
Wouldn't it make more sense to just run xxx in the foreground?
Hi,
It does make sense to just run xxx in the foreground but I also have cases where it just stalled/hanged which causes the rest of the script not to run.
Ideally, the best scenario would be to run xxx in the background but give it for example a maximum of 10 minutes for example and if it does not run to completion, I want to kill -9 it, but how to know what PID to kill if I let it run in the background. Should I Be doing as below:
... xxx &
while loop to check the PID of xxx (???) if it disappears, then xxx is finished, otherwise it is still running? But how to get the PID of xxx &
...
...
Using a fixed time frame is, as you noticed, not the way to go. Using the child's PID and checking its existence might be what you are looking for.
Rough example:
Code:
# the child script:
$ cat foo
#/bin/bash
echo "foo: i'm alive..... I'll sleep for 15 seconds and exit"
sleep 15
echo "foo: Done. exiting now."
# the main script:
$ cat bar
#!/bin/bash
echo "bar: starting foo in background"
./foo &
fooPID="$!"
echo "child pid: $fooPID"
while [[ true ]]
do
if [[ "$(ps -ef | grep $fooPID | grep -v grep)" == "" ]]
then
echo "bar: foo has stopped"
break
else
echo "bar: foo is still running"
fi
sleep 2
done
echo "bar: do more stuff here that depends on stopped foo"
Code:
# example run:
$ ./bar
bar: starting foo in background
child pid: 17157
foo: i'm alive..... I'll sleep for 15 seconds and exit
bar: foo is still running
.
.
.
bar: foo is still running
foo: Done. exiting now.
bar: foo has stopped
bar: do more stuff here that depends on stopped foo
There are other ways as well: let foo create a temporary file, which foo removes as last step. bar checks if the file exists, if it does: foo is still running.
Hope this helps.
Hi druuna,
I think this is what I wanted. I will test it out.
Here is timeout, a bash shell script which runs the given command with a timeout. I did note you use ksh, but I'm too rusty with it, sorry. You could of course run this as-is in your own ksh scripts; just put it somewhere along your PATH.
The script uses a subshell and Bash job control features to do the work, no temporary files or pipes are used. The main shell will sleep in one second intervals, until the command completes or the timeout expires. If the timeout expires, it will first try to terminate the command gracefully with a TERM signal, but if it does not terminate within five seconds, the command will be sent a KILL signal.
The timeout in seconds must be an integer, but you can use a Bash algebraic expression, e.g. '2*5-8'. Remember to quote the expression like I did if it has characters that are special to the shell.
Code:
#!/bin/bash
if [ $# -lt 2 ] || [ "$1" == "-h" ] || [ "$1" == "--help" ]; then
echo "" >&2
echo "Usage: $0 [ -h | --help ]" >&2
echo " $0 <seconds> command .." >&2
echo "" >&2
echo "This will run command in a Bash subshell." >&2
echo "If the timeout (integer <seconds>) expires before the command completes," >&2
echo "the command will be forcibly terminated (and exit status will be 127)." >&2
echo "Note that termination may take up to five seconds." >&2
echo "" >&2
fi
# Parse <seconds> without bash error messages.
exec 3>&1 4>&2 1>/dev/null 2>/dev/null
timeout=$[ $1 -0 ]
if [ $? -ne 0 ] || [ $timeout -lt 1 ]; then
echo "$1: Invalid timeout." >&4
exit 126
fi
exec 1>&3- 2>&4-
shift 1
# Run command in a subshell
( SECONDS=0
"$@" &
# Hide any possible "Terminated" output.
exec >/dev/null 2>/dev/null
while [ -n "`jobs -pr`" ] && [ $SECONDS -lt $timeout ]; do
sleep 1.0
done
pids=`jobs -pr`
if [ -n "$pids" ]; then
# Send the TERM signal. Give up to five seconds to respond.
kill -TERM $pids
SECONDS=0
while [ -n "`jobs -p`" ] && [ $SECONDS -lt 5 ]; do
sleep 0.25
done
# If that didn't terminate it, send the KILL signal.
pids=`jobs -p`
if [ -n "$pids" ]; then
kill -KILL $pids
fi
exit 127
else
wait `jobs -p`
exit $?
fi
)
exit $?
Usage is very simple. For example (in Bash or ksh):
./timeout 300 some-command-or-shell-scriptarguments...
result=$?
if [ $result -eq 127 ]; then
echo "Took more than five minutes, therefore killed."
elif [ $result -eq 0 ]; then
echo "No errors."
else
echo "Error $result"
fi
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.