Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I am trying to add following command to crontab:

I=1; for X in $(/bin/ls -r /var/tmp/*); do [ $((I++)) -le 28 ] && echo "lower" || echo "higher"; done

When executed on the command line (in bash), the command works fine. But when I add the line into crontab and when executed, cron complains:

/bin/sh: 1: arithmetic expression: expecting primary: "I++"

Do I need to use different syntax in cron ?

EDIT1: I have replaced sh with bash in my /etc/crontab:

SHELL=/bin/bash

I have restarted cron, but following cron line still does not execute:

(I=1; for X in $(/bin/ls -r /var/tmp/*); do [ $((I++)) -le 28 ] && echo "lower" || echo "higher"; done)

the error suggests, that it is still being interpreted with /bin/sh instead of /bin/bash:

/bin/sh: 1: arithmetic expression: expecting primary: "I++"
share|improve this question

3 Answers 3

up vote 3 down vote accepted

Cron, if I'm not mistaken, defaults to /bin/sh. Check /etc/crontab/ for the line SHELL=. It is likely set to /bin/sh (dash). I believe you can set SHELL=/bin/bash in your own user crontab file (the one edited by crontab -e). Or you can script it.

share|improve this answer
    
I have SHELL=/bin/sh in my /etc/crontab. Is there any reason, why I should want to use /bin/sh, instead of /bin/bash ? I am on Debian, and the system shell is bash. So why would they keep sh for cron. AFAIK, bash is compatible with sh, but not the other way around. –  Martin Vegter Sep 30 '13 at 7:38
    
Nope, there is no reason to keep it set to /bin/sh AFAIK. I think it is just a default setting. –  AGHz Sep 30 '13 at 11:35

Yes, you need to use sh syntax. You can find the specification for the portable standard sh syntax there.

In this case, you want [ "$((i+=1))" -le 29 ], or if your sh is based on an older version of ash that did not support the full set of standard arithmetic operators yet, use [ "$i" -le 28 ] ...; i=$(($i + 1)).

A note of warning: processing a world writeable directory like /var/tmp under cron is like opening a can of worm wrt security.

You've got to treat filenames and their type in there as untrusted and extremely dirty.

Your $(/bin/ls -r /var/tmp/*) in particular is bogus as it makes a lot of assumptions on what characters the filenames may contain and assumes none of them are directories or symlinks to directories.

share|improve this answer
    
when I use [ "$((I+=1))" -le 28 ], cron complains: /bin/sh: 1: Bad substitution –  Martin Vegter Sep 29 '13 at 19:41

To make this completely portable you can replace the $() syntax with:

I=1; for X in `/bin/ls -r /var/tmp/*`; do [ $I -le 28 ] && echo "lower" || echo "higher"; I=`expr $I + 1`; done

But beware of cron jobs and world writable directories.

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.