3

So I've made myself a little script which monitors my served directories for any PHP files which have changed. It's designed to run every 5 mins from crontab and email me any changes so that I can check them.

There are lots of websites running on the machine and I want to be able to cast an eye over any new scripts to make sure that there is nothing there which I don't like the look of, if you know what I mean.

The problem is that the script runs 100% fine when I run it from the command line, but it does not run correctly from crontab. The script is included below:

rm /root/sec/email
find /var/www/ -name '*.php' -not -name '*.tpl.*' -type f -mtime -0.005 -exec ls -al {} \;  > /root/sec/email
if [[ -s /root/sec/email ]] ; then
        mail -s "PHP Change Alert on FSE4" matt@aroxo.com muji@aroxo.com < /root/sec/email
        echo "It ran" >> /root/sec/log
else
        echo "It did not run" >> /root/sec/log
fi ;

The issue is with the IF condition. Even if the file called "email" has a non-zero size, the wrong side of the if clause triggers (the else).

Any ideas what I'm doing wrong?

Cheers,

Matt.

Matt Rogers
  • 83
  • 1
  • 7

2 Answers2

7

The script has a bashism in it: [[

In other words, the script is using a non-standard extension to Bourne shell syntax which breaks the script when it's run by /bin/sh (I assume your distro uses a /bin/sh that doesn't have support for all of the non-POSIX bashisms in it).

To solve this issue, either

  1. Put #!/bin/bash in as the first line of the script
  2. Make the if condition look like this: if [ -s "/root/sec/email" ] ; then

Some more information about bashisms are here: http://mywiki.wooledge.org/Bashism

Dennis Williamson
  • 60,515
  • 14
  • 113
  • 148
samiam
  • 254
  • 1
  • 5
  • Absolutely superb. I don't pretend to full understand why without this clause it was working fine when I ran it manually, but not fine when it was launched by crontab, but the issue is fixed and my knowledge expanded - thanks! – Matt Rogers Jan 31 '14 at 19:29
  • 1
    @MattRogers The reason it works when run manually is that your shell is Bash, which has its own way of determining how to run a script if it's not a binary executable and doesn't start with a shebang (!#/path/to/whatever). So Bash was using Bash (with all the features enabled) to execute the script, but cron was just using `sh` (which may actually still be Bash, but with bash-isms disabled). (Note: you should **definitely** be using a shebang line in pretty much all of your scripts; they save you from incompatibilities like this and in general don't have many, if any, downsides.) – Kyle Strand Jan 31 '14 at 22:52
3

Crontab uses /bin/sh by default to run your commands.

Even though /bin/sh is a symlink to /bin/bash, bash disables bash-only features if it's run that way.

According to 'man 5 crontab', you can put 'SHELL=/bin/bash' on a new line in your crontab file and suddenly the bash features will work again, such as your "if [[ ... ]]" statement.

PFudd
  • 51
  • 4