开发者

Can a bash script tell if it's being run via cron?

开发者 https://www.devze.com 2023-01-06 03:32 出处:网络
Not having much luck Googling this question and I thought about posting it on SF, but it actually seems like a development question. If not, please feel free to migrate.

Not having much luck Googling this question and I thought about posting it on SF, but it actually seems like a development question. If not, please feel free to migrate.

So, I have a script that runs via cron every morning at about 3 am. I also run the same scripts manually sometimes. The problem is that every time I run my script manually and it fails, it sends me an e-mail; even though I can look at the output a开发者_如何学Pythonnd view the error in the console.

Is there a way for the bash script to tell that it's being run through cron (perhaps by using whoami) and only send the e-mail if so? I'd love to stop receiving emails when I'm doing my testing...


you can try "tty" to see if it's run by a terminal or not. that won't tell you that it's specifically run by cron, but you can tell if its "not a user as a prompt".

you can also get your parent-pid and follow it up the tree to look for cron, though that's a little heavy-handed.


I had a similar issue. I solved it with checking if stdout was a TTY. This is a check to see if you script runs in interactive mode:

if [ -t 1 ] ; then 
    echo "interacive mode";
else
    #send mail
fi

I got this from: How to detect if my shell script is running through a pipe?

The -t test return true if file descriptor is open and refers to a terminal. '1' is stdout.


Here's two different options for you:

  • Take the emailing out of your script/program and let cron handle it. If you set the MAILTO variable in your crontab, cron will send anything printed out to that email address. eg:

    MAILTO=youremail@example.com
    # run five minutes after midnight, every day
    5 0 * * *       $HOME/bin/daily.job
    
  • Set an environment variable in your crontab that is used to determine if running under cron. eg:

    THIS_IS_CRON=1
    # run five minutes after midnight, every day
    5 0 * * *       $HOME/bin/daily.job
    

    and in your script something like

    if [ -n "$THIS_IS_CRON" ]; then echo "I'm running in cron"; else echo "I'm not running in cron"; fi
    


Why not have a command line argument that is -t for testing or -c for cron.

Or better yet:

-e=email@address.com

If it's not specified, don't send an email.


I know the question is old, but I just came across the same problem. This was my solution:

CRON=$(pstree -s $$ | grep -q cron && echo true || echo false)

then test with

if $CRON
then
    echo "Being run by cron"
else
    echo "Not being run by cron"
fi

same idea as the one that @eruciform mentioned - follows your PID up the process tree checking for cron.

Note: This solution only works specifically for cron, unlike some of the other solutions, which work anytime the script is being run non-interactively.


What works for me is to check $TERM. Under cron it's "dumb" but under a shell it's something else. Use the set command in your terminal, then in a cron-script and check it out

if [ "dumb" == "$TERM" ]
then
    echo "cron"
else
    echo "term"
fi


I'd like to suggest a new answer to this highly-voted question. This works only on systemd systems with loginctl (e.g. Ubuntu 14.10+, RHEL/CentOS 7+) but is able to give a much more authoritative answer than previously presented solutions.

service=$(loginctl --property=Service show-session $(</proc/self/sessionid))
if [[ ${service#*=} == 'crond' ]]; then
   echo "running in cron"
fi

To summarize: when used with systemd, crond (like sshd and others) creates a new session when it starts a job for a user. This session has an ID that is unique for the entire uptime of the machine. Each session has some properties, one of which is the name of the service that started it. loginctl can tell us the value of this property, which will be "crond" if and only if the session was actually started by crond.


Advantages over using environment variables:

  • No need to modify cron entries to add special invocations or environment variables
  • No possibility of an intermediate process modifying environment variables to create a false positive or false negative

Advantages over testing for tty:

  • No false positives in pipelines, startup scripts, etc

Advantages over checking the process tree:

  • No false positives from processes that also have crond in their name
  • No false negatives if the script is disowned


Many of the commands used in prior posts are not available on every system (pstree, loginctl, tty). This was the only thing that worked for me on a ten years old BusyBox/OpenWrt router that I'm currently using as a blacklist DNS server. It runs a script with an auto-update feature. Running from crontab, it sends an email out.

[ -z "$TERM" ] || [ "$TERM" = "dumb" ] && echo 'Crontab' || echo 'Interactive'

In an interactive shell the $TERM-variable returns the value vt102 for me. I included the check for "dumb" since @edoceo mentioned it worked for him. I didn't use '==' since it's not completely portable.


I also liked the idea from Tal, but also see the risk of having undefined returns. I ended up with a slightly modified version, which seems to work very smooth in my opinion:

CRON="$( pstree -s $$ | grep -c cron )"

So you can check for $CRON being 1 or 0 at any time.

0

精彩评论

暂无评论...
验证码 换一张
取 消