Can this script wait for an external process to complete? - bash

I have written this shell script as wrapper to a JAR file. The script launches the JAR without problem but completes without waiting for the JAR to finish its job.
#!/bin/bash
export WORK=/opt/conversion
export LOG=$WORK
export XMAIL=me#email.com
export JAVA_BASE=/usr/java/jdk1.6.0_06
export JAVA_HOME=/usr/java/jdk1.6.0_06/bin
export JAR=$WORK/conversion.jar
export CLASSPATH=$JAVA_BASE/lib/tools.jar
export CLASSPATH=$CLASSPATH:$WORK/lib/ojdbc14.jar
export CLASSPATH=$CLASSPATH:$JAR
$JAVA_HOME/java -Xms256M -Xmx512M -classpath $CLASSPATH com.myapp.cam.conversion >>$WORK/job.out 2>&1 &
echo $! > $WORK/job.pid
mail -s "Conversion" $XMAIL < $WORK/user_message
exit 0
Is there a way to have the script wait on my JAR file to complete?
Thanks for your input.

As others have said, remove the & and bash will wait till the command finishes. If you insist on running your process in the background, here is what you could do:
pid=`pidof java`
if [ "$pid" ]; then
while kill -0 "$pid"; do
sleep 1
done
fi
The kill command is normally used to send signals to a particular process, but by using 0 as a signal you are only checking whether a process with such a pid exists without sending a signal.

You have a & at the end of the command:
$JAVA_HOME/java -Xms256M -Xmx512M -classpath $CLASSPATH com.myapp.cam.conversion >>$WORK/job.out 2>&1 &
which makes it run in background.
Remove the & to wait for the java process to complete before you proceed in the script.

If you want to run it in the background, add a wait command at the end of the script.

Don't run the conversion Java application in the background. Or, run ps repeatedly until you don't see the pid. This will allow you to do stuff while waiting.

Related

How to capture a process Id and also add a trigger when that process finishes in a bash script?

I am trying to make a bash script to start a jar file and do it in the background. For that reason I'm using nohup. Right now I can capture the pid of the java process but I also need to be able to execute a command when the process finishes.
This is how I started
nohup java -jar jarfile.jar & echo $! > conf/pid
I also know from this answer that using ; will make a command execute after the first one finishes.
nohup java -jar jarfile.jar; echo "done"
echo "done" is just an example. My problem now is that I don't know how to combine them both. If I run echo $! first then echo "done" executes immediately. While if echo "done" goes first then echo $! will capture the PID of echo "done" instead of the one of the jarfile.
I know that I could achieve the desire functionality by polling until I don't see the PID running anymore. But I would like to avoid that as much as possible.
You can use the bash util wait once you start the process using nohup
nohup java -jar jarfile.jar &
pid=$! # Getting the process id of the last command executed
wait $pid # Waits until the process mentioned by the pid is complete
echo "Done, execute the new command"
I don't think you're going to get around "polling until you don't see the pid running anymore." wait is a bash builtin; it's what you want and I'm certain that's exactly what it does behind the scenes. But since Inian beat me to it, here's a friendly function for you anyway (in case you want to get a few things running in parallel).
alert_when_finished () {
declare cmd="${#}";
${cmd} &
declare pid="${!}";
while [[ -d "/proc/${pid}/" ]]; do :; done; #equivalent to wait
echo "[${pid}] Finished running: ${cmd}";
}
Running a command like this will give the desired effect and suppress unneeded job output:
( alert_when_finished 'sleep 5' & )

Start a process in background, do a task, then kill the process in the background

I have a script that looks like this:
pushd .
nohup java -jar test/selenium-server.jar > /dev/null 2>&1 &
cd web/code/protected/tests/
phpunit functional/
popd
The selenium servers needs to be running for the tests, however after the phpunit command finishes I'd like to kill the selenium-server that was running.
How can I do this?
You can probably save the PID of the process in a variable, then use the kill command to kill it.
pushd .
nohup java -jar test/selenium-server.jar > /dev/null 2>&1 &
serverPID=$!
cd web/code/protected/tests/
phpunit functional/
kill $serverPID
popd
I haven't tested it myself, I'd like to write it on a comment, but not enough reputation yet :)
When the script is excecuted a new shell instance is created. Which means that the jobs in the new script would not list any jobs running in the parent shell.
Since the selenium-server server is the only background process that is created in the new script it can be killed using
#The first job
kill %1
Or
#The last job Same as the first one
kill %-
As long as you don't launch any other process in the background - which you don't - you can use $! directly:
pushd .
nohup java -jar test/selenium-server.jar > /dev/null 2>&1 &
cd web/code/protected/tests/
phpunit functional/
kill $!
popd

shell script running infinitely

i have a shell script run.sh.
cd elasticsearch-1.1.0/
./bin/elasticsearch
cd
cd RBlogs/DataFetcher/
mvn clean install assembly:single;
cd target/
java -jar DataFetcher-0.0.1-SNAPSHOT-jar-with-dependencies.jar
Here if second line(./bin/elasticsearch) executes it runs infinite time, so the next lines will not execute. So what i need is to perform the next lines after 10 seconds. But
cd elasticsearch-1.1.0/
./bin/elasticsearch
sleep 10
cd
cd RBlogs/DataFetcher/
mvn clean install assembly:single;
cd target/
java -jar DataFetcher-0.0.1-SNAPSHOT-jar-with-dependencies.jar
This also will not execute next lines because ./bin/elasticsearch will not complete its execution in 10seconds. So how can i solve this problem? Please help.
Adding & at the end of ./bin/elasticsearch will cause the process to run in a subshell, freeing the current shell up for the next commands.
./bin/elasticsearch &
Change this in your second version of the script and things should run like you want them too.
More information can be found from man bash
If a command is terminated by the control operator &, the shell
executes the command in the background in a subshell.
The shell does not wait for the command to finish, and the return status is 0.
you may try to put it in background
& can do this for you
./bin/elasticsearch &
If you simply want elasticsearch to run in the background while the rest of the script progresses, just use &:
cd elasticsearch-1.1.0/
./bin/elasticsearch &
sleep 10
cd
cd RBlogs/DataFetcher/
However, if you want to run elasticsearch for at most 10 seconds, killing it if necessary, then proceeding with the rest of the script, you need something a little more complicated:
cd elasticsearch-1.1.0/
./bin/elasticsearch &
pid=$!
sleep 10
kill -0 $pid && kill $pid
cd
cd RBlogs/DataFetcher/
As other answers mentioned, you can
use ./bin/elasticsearch & to run the command in
background.
record the process id of the
command run in background by using child_pid=$! and then stop the
process by using kill $child_pid after some time to implement a
timeout mechanism.
Meanwhile, you also can synchronize another operation with the command run in background by using wait command. An example bellow:
./bin/elasticsearch &
# do something asynchronously here
wait # wait for accomplishment of ./bin/elasticsearch
# do something synchronously here

BASH script suspend/continue a process within script

In my bash script I am writing, I am trying to start a process (sleep) in the background and then suspend it. Finally, the process with be finished. For some reason through, when I send the kill command with the stop signal, it just keeps running as if it received nothing. I can do this from the command line, but the bash script is not working as intended.
sleep 15&
pid=$!
kill -s STOP $pid
jobs
kill -s CONT $pid
You can make it work by enabling 'monitor mode' in your script: set -m
Please see why-cant-i-use-job-control-in-a-bash-script for further information

How do I write a watchdog daemon in bash?

I want a way to write a daemon in a shell script, which runs another application in a loop, restarting it if it dies.
When run using ./myscript.sh from an SSH session, it shall launch a new instance of the daemon, except if the daemon is already running.
When the SSH session ends, the daemon shall persist.
There shall be a parameter (./myscript -stop) that kills any existing daemon.
(Notes on edit - The original question specified that nohup and similar tools may not be used. This artificial requirement was an "XY question", and the accepted answer in fact uses all the tools the OP claimed were not possible to use.)
Based on clarifications in comments, what you actually want is a daemon process that keeps a child running, relaunching it whenever it exits. You want a way to type "./myscript.sh" in an ssh session and have the daemon started.
#!/usr/bin/env bash
PIDFILE=~/.mydaemon.pid
if [ x"$1" = x-daemon ]; then
if test -f "$PIDFILE"; then exit; fi
echo $$ > "$PIDFILE"
trap "rm '$PIDFILE'" EXIT SIGTERM
while true; do
#launch your app here
/usr/bin/server-or-whatever &
wait # needed for trap to work
done
elif [ x"$1" = x-stop ]; then
kill `cat "$PIDFILE"`
else
nohup "$0" -daemon
fi
Run the script: it will launch the daemon process for you with nohup. The daemon process is a loop that watches for the child to exit, and relaunches it when it does.
To control the daemon, there's a -stop argument the script can take that will kill the daemon. Look at examples in your system's init scripts for more complete examples with better error checking.
The pid of the most recently "backgrounded" process is stored in $!
$ cat &
[1] 7057
$ echo $!
7057
I am unaware of a fork command in bash. Are you sure bash is the right tool for this job?

Resources