Is there any variable that cron sets when it runs a program ? If the script is run by cron, I would like to skip some parts; otherwise invoke those parts.

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

  • 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

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 or soft 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.

  • 5
    +1 for RUN_BY_CRON=true – cas Aug 31 '12 at 9:50
  • the answer by cas is working very well and can be used for anything else too – Deian Jun 30 '16 at 15:01

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

Method 2: check is $PS1 is empty.

if [ -z "$PS1" ]; then

reference: http://techdoc.kvindesland.no/linux/gnubooks/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

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

  • 1
    Note that the $PS1 command does not work when checking if script is started by systemd or not. the $- one does – mveroone Nov 17 '15 at 10:08
  • 1
    Your Winnipeg University link is broken. – WinEunuuchs2Unix Dec 31 '16 at 4:07
  • 1
    @TimKennedy You're welcome.... from Edmonton :) – WinEunuuchs2Unix Jan 6 '17 at 4:20
  • 'case "$-" in' doesn't appear to work in bash scripts. – Hobadee May 17 '17 at 23:13
  • @Hobadee - every bash i have access to has $-, as do dash and ksh. even the restricted shells in Solaris have it. What platform are you trying to use it where it's not working? What does case "$-" in *i*) echo true ;; *) echo false ;; esac show you? – Tim Kennedy May 18 '17 at 15:51

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
CRONPID=$(ps ho %p -C cron)
while [ $CRON_IS_PARENT -ne 1 ] && [ $PPID -ne 1 ] ; do
  PPID=$(ps ho %P -p $PPID)

From Deian: This is a version tested on RedHat Linux

# start from current PID
# this might return a list of multiple PIDs
CRONPIDS=$(ps ho %p -C crond)

while [ $CRON_IS_PARENT -ne 1 ] && [ $CPID -ne 1 ] ; do
        CPID_STR=$(ps ho %P -p $CPID)
        # the ParentPID came up as a string with leading spaces
        # this will convert it to int
        # now loop the CRON PIDs and compare them with the CPID
        for CRONPID in $CRONPIDS ; do
                [ $CRONPID -eq $CPID ] && CRON_IS_PARENT=1
                # we could leave earlier but it's okay like that too

# now do whatever you want with the information
if [ "$CRON_IS_PARENT" == "1" ]; then

echo "CRON Call: ${CRON_CALL}"
  • 1
    On Solaris cron starts a shell and the shell runs the script, which itself starts another shell. So the parent pid in the script is not the pid of cron. – ceving Dec 15 '16 at 17:17

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

Now you can test anywhere in your script

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

Good luck!


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" ]
    echo "Called from cron"
    echo "Not called from cron"

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


A generic solution to the question "is my output a terminal or am I running from a script" is:

( : > /dev/tty) && dev_tty_good=y || dev_tty_good=n

A simple echo $TERM | mail me@domain.com in cron showed me that on both Linux and AIX, cron seems to set $TERM to 'dumb'.

Now theoretically there may still be actual dumb terminals around, but I suspect that for most occasions, that should suffice...


There is no authoritative answer, but the prompt ($PS1) and terminal ($TERM) variables are pretty decent here. Some systems set TERM=dumb while most leave it empty, so we'll just check for either:

if [ "${TERM:-dumb}$PS1" != "dumb" ]; then
  echo "This is not a cron job"

The above code substitutes the word "dumb" when there is no value for $TERM. Therefore, the conditional fires when there is no $TERM or $TERM is set to "dumb" or if the $PS1 variable is not empty.

I've tested this on Debian 9 (TERM=), CentOS 6.4 & 7.4 (TERM=dumb), and FreeBSD 7.3 (TERM=).

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.