I have a java runnable jar which I need to run it if it not running or got killed for some reason so I decided to use crontab for this -

I need to run the crontab as "poppetapp" user so I am logged in as this user and created crontab like this -

*/5 * * * * pgrep -f test_java_10.jar || cd /home/poppetapp && /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out

And my shell script is like this which is in /home/poppetapp/ location -

/usr/home/java -jar /home/poppetapp/test_java_10.jar

My java runnable jar is in the home location for "poppetapp" user which is /home/poppetapp/.

So my question is - Does this look right? I just need to start my test_java_10.jar if it is not running or got killed for some reason so I created a crontab which will run every 5 minutes to check whether it is running or not. If it is not running it will execute my shell script to start the test_java_10.jar process.

But somehow when I make this crontab change, I am seeing lot of test_java_10.jar process is getting invoked. I think every 5 minutes it is launching another process for this.


If I modify my crontab like this -

*/5 * * * * pgrep -f test_java_10.jar || /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out

then I see below mail which doesn't say what's the problem or does it say anything?

& t 35
Message 35:
From poppetapp@machineA  Tue Mar 24 17:05:01 2015
X-Original-To: poppetapp
From: root@machineA (Cron Daemon)
To: poppetapp@machineA
Subject: Cron <poppetapp@machineA> pgrep -f test_java_10.jar || /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out
Content-Type: text/plain; charset=ANSI_X3.4-1968
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <HOME=/home/poppetapp>
X-Cron-Env: <PATH=/usr/bin:/bin>
X-Cron-Env: <LOGNAME=poppetapp>
Date: Tue, 24 Mar 2015 17:05:01 -0700 (GMT+7)
  • When you run that pgrep - what return code do you get? You should be able to echo $? right after running it. Does it return a different value if it does/doesn't match? (Because that's what the || is doing, it's not looking at the command output). Personally though, I'd be tempted to suggest a lock file rather than a ps test. – Sobrique Mar 24 '15 at 21:41
  • @Sobrique where do you want me to add echo $?? – david Mar 24 '15 at 21:43
  • Run your pgrep on the command line, echo $? after doing so. But I think I know the problem - pgrep returns 0 if the process is running (e.g. false). – Sobrique Mar 24 '15 at 21:48
  • The cron e-mail you show looks incomplete: it's just headers, with no body. Are you sure it's all there is? The next idea that comes to mind is that $PATH, in the cron environment, doesn't include what is needed to run Java programs. Perhaps append 2>&1 to your script call, so that the error output also ends up in the log file. Or wrap the entire command in parentheses, and append >/tmp/cron.command.log 2>&1 so we see the error output of the entire thing. – dhag Mar 25 '15 at 0:42
  • @dhag you mean to say like this pgrep -f test_java_10.jar || (/home/poppetapp/test_java.sh > /home/poppetapp/test_java.out) > /tmp/cron.command.log 2>&1 – david Mar 25 '15 at 0:48

The advantage of something like || is it allows you to run something based on a return code. E.g. if the left hand side is false then it evaluates the right hand side, but otherwise it doesn't bother.

Here's the problem though - look at the man page for pgrep:

The pgrep and pkill utilities return one of the following values upon exit: 0 One or more processes were matched. 1 No processes were matched.

So actually, it is 0 and thus false when it matches - so it'll actually only start your java process if it's already running :).

Switch your || to && and you should get the desired result. Although actually, I'd suggest probably putting this into a script so future readers don't have to figure out the same thing.

I would suggest - process grepping is inherently a bit unreliable. You may want to do it via a pid or lockfile instead.

  • I believe you have it backwards; false, for example, has exit status 1, which is interpreted as false by && (and run true ; echo $? to see true exit with status code 0). That's confusing, for sure, since in other, non-shell contexts 0 usually means false. – dhag Mar 24 '15 at 21:54
  • Hmm, ok. Makes sense. – Sobrique Mar 24 '15 at 22:05

I think this may be a grouping issue. I replaced your call to pgrep with a simple true or false:

  • If the process isn't running, pgrep will fail:

    $ false || echo cd && echo run
  • If the process is running, pgrep will be successful:

    $ true || echo cd && echo run

    In this case, you would want nothing at all to be executed! Running true || (echo cd && echo run) displays nothing, which is what we want.

I suggest trying pgrep -f test_java_10.jar || (cd /home/poppetapp && /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out).

  • Thanks for suggestion. I tried doing this but it doesn't work at all. I don't see any java process running if I do it like this but if I run it the way I was doing, it was launching multiple java processes every 5 minutes. – david Mar 24 '15 at 23:09
  • One thing to test would be: does pgrep -f test_java_10.jar ever return true? When your Java program is running, I would expect this command to print the java process PID, and echo $? to print 0. – dhag Mar 25 '15 at 0:28
  • If I am running my java program first, and then if I am running pgrep, yes I can see that printing out the PID. Also if I run like this on the command prompt, pgrep -f test_java_10.jar || /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out. I can see this is also working fine. But when I put this in crontab, then I don't see working – david Mar 25 '15 at 0:39
  • This could be caused by differences of environment between your shell and cron. I added a comment to your question regarding this possibility. – dhag Mar 25 '15 at 0:43

JosephR explained the logic better than I can.

I suggest removing the cd /home/poppetapp && and just use the following to get your desired result.

*/5 * * * * pgrep -f test_java_10.jar || /home/poppetapp/test_java.sh > /home/poppetapp/test_java.out
  • Thanks for suggestion. This is pretty strange. If I run it the way you are suggesting me, it doesn't work at all and I don't see any process being launched. But If I use it the way I am running, then it works fine but the only problem is it will launch multiple java processes after every 5 minutes. Pretty strange. – david Mar 24 '15 at 23:07
  • And with your suggestion, it always says this You have new mail in /var/mail/poppetapp and if I go and read it, it doesn't say any error may be I don't know how to read that. – david Mar 24 '15 at 23:50
  • To read the mail type mail followed by ENTER. Then type t XXX followed by ENTER where XXX is the newest entry number. To quit the mail program type q. – Timothy Martin Mar 24 '15 at 23:55
  • I have updated the question with mail details. It doesn't say much I guess. take a look and see whether it makes sense to you? – david Mar 25 '15 at 0:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.