Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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.

share|improve this question
    
You're trying to do it yourself instead of running maldet? –  Michael Hampton Jan 31 at 15:54
    
See the "Debugging cron commands" section here. –  Dennis Williamson Jan 31 at 16:20
    
Are you executing this script with "sh" or "bash"? –  glenn jackman Jan 31 at 17:46
    
Always check the error messages! Look at the email that cron sent you to signal that your job failed and produced some output. You'll see the error message sh: 3: [[: not found (or something like it), for the reason samiam explained. –  Gilles Jan 31 at 18:53

2 Answers 2

up vote 6 down vote accepted

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

share|improve this answer
    
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 at 19:29
    
@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 at 22:52
    
Got it - thanks! –  Matt Rogers Feb 1 at 8:22

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.

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.