Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Is there any variable that cron set when it's running a program ? If the script is running by cron, I'll skip some parts; otherwise invoke those parts.

How can I know if the bash script is started by cron ?

share|improve this question
    
Why don't you just us ps? –  terdon Aug 31 '12 at 9:20
    
see: serverfault.com/questions/146745/… –  Tim Kennedy Aug 31 '12 at 11:25
    
@terdon: probably because ps is fairly badly documented (especially Linux's version which supports several different syntax styles) and the man page is even more dense and cryptic than most tools. I suspect most people don't even realise just how useful and versatile a tool ps can be. –  cas Aug 31 '12 at 12:55

5 Answers 5

up vote 7 down vote accepted

I'm not aware that cron does anything to its environment by default that can be of use here, but there are a couple of things you could do to get the desired effect.

1) Make a hard link to the script file, so that, for example, myscript and myscript_via_cron point to the same file. You can then test the value of $0 inside the script when you want to conditionally run or omit certain parts of the code. Put the appropriate name in your crontab, and you're set.

2) Add an option to the script, and set that option in the crontab invocation. For example, add an option -c, which tells the script to run or omit the appropriate parts of the code, and add -c to the command name in your crontab.

And of course, cron can set arbitrary environment variables, so you could just put a line like RUN_BY_CRON="TRUE" in your crontab, and check its value in your script.

share|improve this answer
    
+1 for RUN_BY_CRON=true –  cas Aug 31 '12 at 9:50

First, get cron's PID, then get the current process's parent PID (PPID), and compare them:

CRONPID=$(ps ho %p -C cron)
PPID=$(ps ho %P -p $$)
if [ $CRONPID -eq $PPID ] ; then echo Cron is our parent. ; fi

If your script is started by another process that might have been started by cron, then you can walk your way back up the parent PIDs until you get to either $CRONPID or 1 (init's PID).

something like this, maybe (Untested-But-It-Might-Work<TM>):

PPID=$$   # start from current PID
CRON_IS_PARENT=0
CRONPID=$(ps ho %p -C cron)
while [ $CRON_IS_PARENT -ne 1 ] && [ $PPID -ne 1 ] ; do
  PPID=$(ps ho %P -p $PPID)
  [ $CRONPID -eq $PPID ] && CRON_IS_PARENT=1
done
share|improve this answer

Scripts run from cron are not run in interactive shells. Neither are startup scripts. The differentiation is that interactive shells have STDIN and STDOUT attached to a tty.

Method 1: check if $- includes the i flag. i is set for interactive shells.

case "$-" in
    *i*)
        interactive=1
        ;;
    *)
        not_interactive=1
        ;;
esac

Method 2: check is $PS1 is empty.

if [ -z "$PS1" ]; then
    not_interactive=1 
else
    interactive=1
fi

reference: http://theory.uwinnipeg.ca/localfiles/infofiles/bash/bashref_54.html

Method 3: test your tty. it's not as reliable, but for simple cron jobs you should be ok, as cron does not by default allocate a tty to a script.

if [ -t 0 ]; then
    interactive=1
else
    non_interactive=1
fi

Keep in mind that you can however force an interactive shell using -i, but you'd probably be aware if you were doing this...

share|improve this answer

Works on FreeBSD or on Linux:

if [ "Z$(ps o comm="" -p $(ps o ppid="" -p $$))" == "Zcron" -o \
     "Z$(ps o comm="" -p $(ps o ppid="" -p $(ps o ppid="" -p $$)))" == "Zcron" ]
then
    echo "Called from cron"
else
    echo "Not called from cron"
fi

You can go as far up the process tree as you wish.

share|improve this answer

If your script file is invoked by cron and it contains a shell in the first line like #!/bin/bash you need to find the parent-parent name for your purpose.

1) cron is invoked at the given time in your crontab, executing a shell 2) shell executes your script 3) your script is running

The parent PID is available in bash as variable $PPID. The ps command to get the parent PID of the parent PID is:

PPPID=`ps h -o ppid= $PPID`

but we need the name of the command, not the pid, so we call

P_COMMAND=`ps h -o %c $PPPID`

now we just need to test the result for "cron"

if [ "$P_COMMAND" == "cron" ]; then
  RUNNING_FROM_CRON=1
fi

Now you can test anywhere in your script

if [ "$RUNNING_FROM_CRON" == "1" ]; then
  ## do something when running from cron
else
  ## do something when running from shell
fi

Good luck!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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