1

I'm trying to use the DreamHost API (see here) to update a DNS entry using crontab. I have written the following bash script:

#!/bin/bash
dh_api_key=<my api key>
dh_domain=<my fq subdomain>

dh_url="https://api.dreamhost.com/?key=$dh_api_key&record=$dh_domain&type=A"

ip_addr=`ifconfig eth0 | grep "inet addr" | 
    grep -o "\([0-9]\{1,3\}\.\?\)\{4\}" | head -n 1`

old_ip_addr=`wget -q -O - ""$dh_url&cmd=dns-list_records"" | 
    grep $dh_domain | grep -o "\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}"`

dh_url="https://api.dreamhost.com/?key=$dh_api_key&record=$dh_domain&type=A"
dh_url_add="$dh_url&cmd=dns-add_record&value=$ip_addr"
dh_url_del="$dh_url&cmd=dns-remove_record&value=$old_ip_addr"

echo $ip_addr
echo $old_ip_addr

if [ "$ip_addr" == "$old_ip_addr" ]
then
    echo SAME
else
    echo DIFFERENT; UPDATING
    wget -q -O - "$dh_url_del"
    wget -q -O - "$dh_url_add"
fi

My crontab entry looks like this:

0,15,30,45 * * * * /home/<username>/dreamhost_api/dns_update_script > /home/<username>/dreamhost_api/dns_update_script.out # <-- note the redirection

If I run the script manually, I get the following output:

<old ip address>
<new ip address>
DIFFERENT; UPDATING

... and everything updates as it should. If I let crontab run the job instead, the update never happens. When I look at the dns_update_script.out file, I see:

<blank line>
<blank line>
SAME

So the script seems to have nothing for the ip_addr and old_ip_addr variables when the script is run by crontab (which of course means the update never happens). Any idea why? Does piping not work (or have some caveats?) when used in crontab?

Henk Langeveld
  • 8,088
  • 1
  • 43
  • 57
loneboat
  • 2,845
  • 5
  • 28
  • 40

2 Answers2

3

When crond runs a script on behalf of a user, the script will NOT have the same environment variables that the user had from the command line. The script will often fail. These are variables like PATH and LD_LIBRARY_PATH, and so on.

Add lines to your script file to the script to have it source your logon scripts: /etc/profile, plus any others.

Create this crontab entry:

* * * * *  set > /tmp/mycronenv.txt

Save the changes to crontab. Wait a minute or two. Go back and get rid of that entry. Finally:

set > myenv.txt
diff myenv.txt /tmp/mycronenv.txt

This will show you what I mean. How to correct it is up to you. The two outputs have to be identical for your script to run.

jim mcnamara
  • 16,005
  • 2
  • 34
  • 51
  • Thanks for the idea! But I'm not sure what variables I would need. All of my paths are explicit paths, and don't rely on environment variables. :-\ – loneboat Feb 21 '13 at 01:36
  • UNIX commands need PATH to work. Just unset PATH and type awk. You will see what I mean. At the command line type the command set. You'll get a bunch of environment variables. To get cron to work you have to make the environment there just like your command environment. – jim mcnamara Feb 21 '13 at 01:39
  • I added some changes to the answer to let you find what you need to add to your cron environment. – jim mcnamara Feb 21 '13 at 01:44
  • 1
    @loneboat - As I recently [commented](http://stackoverflow.com/questions/14612444/bash-script-runs-manually-but-fails-on-crontab/14612507#comment20479537_14612507) on a nearly identical question, you should set the minimum exact environment you need; sourcing in `profile` is overkill and likely opens up security holes in your cron script by having unnecessary things in it. You *could* use explicit paths, so `/sbin/ifconfig` instead of plain `ifconfig` -- `/usr/bin/wget` etc. and not need a PATH. – Stephen P Feb 21 '13 at 01:59
  • A script without an explicit PATH set is an unpredictable script. Add a PATH=/usr/bin line at the top of your script. If that doesn't work, experiment with different settings. Very likely cron is picking up a different `grep` than the login shell. – Henk Langeveld Feb 21 '13 at 02:10
  • @Stephen P you are correct, but the OP appears to be confused about some basic aspects of this. Consider your comment applicable to the final product, not the 'just make it work' part of things. – jim mcnamara Feb 21 '13 at 02:11
1

since both $ip_addr and $old_ip_addr are ending up blank when it runs from cron, perhaps turning on xtrace and then examining the resulting output from the cron invocation could give you the clue on what's not working.

putting

set -x

before the ip_addr= line should do the trick. then let cron run and you should get a bunch of output in the resulting email (or you could redirect the output as another user mentioned. bearing in mind that xtrace emits to stderr, so use something like

* * * * * script >/tmp/outputfile 2>&1
jrrs
  • 98
  • 4