2

I have a bash script that I've written to identify if a certain string exists in a file or not and then output the file name to "hasString.txt" of "noString.txt". I'm using ack -i 'mystring' 'searchDir' to find what I'm looking for.

The weird thing is that when I manually call the script through terminal it works perfectly, but when cron calls the script I get the following error message output:

~/sourceDir/script.sh: line 30: ack: command not found.

Why would it work when manually called but not be able to find the ack command when called by cron?


edit: adding relevant code and cron file

Lookout script - Determines if there are any files to process.

    if [[ $(ls -A ${PWD}/*.zip) ]]; then
        while [ $different -eq 1 ]; do
            du -h 1> $compare1
            ls -laR >> $compare1 
            sleep 25s
            du -h 1> $compare2
            ls -laR >> $compare2

            if cmp $compare1 $compare2 ; then   
                mkdir -p $LOGAREA
                mkdir -p $workarea/zip/unzip
                touch $LOG
                touch $ERRORLOG
                sleep 2s
                source ~/Desktop/Scripts/readfolderfiles.sh $drop
                mv *epub $workarea
                rm $compare1
                rm $compare2
                bash ~/Desktop/Scripts/Page_Label/script/searchString.sh
                different=0
            else
                echo
            fi
        done 1> $LOG 2> $ERRORLOG
    else
    rm ~/Desktop/page_labels.running
    rm $drop/page_labels.running
    fi 

Identify and report script - Generates the output mentioned at top

for files in *.zip; do
    #move and unzip the files
    mv $workarea/$files $workarea/zip/unzip/${files%.epub}.zip
    sleep 2s
    unzip zip/unzip/*.zip -d zip/unzip/${files%.epub}
    mv zip/unzip/*.zip zip
    sleep 2s
    cd $workarea/zip/unzip
    for dir in *; do
        # Search the files for the searchString
        if ack --ignore-case 'searchString' $dir; then
            echo $dir >> $drop/Has_searchString.txt
            echo
            rm -r $dir
            sleep 5s
        else
            echo $dir >> $drop/No_searchString.txt
            echo
            rm -r $dir
            sleep 5s
        fi
    done
    cd $workarea
done

Cron doc

#!/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

#### Backup Files
* * * * 1,2,3,4,5 bash  ~/Desktop/Scripts/searchScript.sh &> /dev/null;
I Dabble
  • 321
  • 2
  • 11
  • 1
    The environment of cron is quite limited and the path of `ack` may be unknown for it. Thus, you can add the full path in your script (`/bin/ack -i 'mystring' 'searchDir'` or whatever you get from `which ack`). – fedorqui Oct 27 '14 at 13:53
  • @fedorqui I tried that. No dice. Still only works when called manually – I Dabble Oct 27 '14 at 14:56
  • OK then post the relevant parts of your code together with your cronjob syntax. – fedorqui Oct 27 '14 at 15:02
  • 1
    The problem (or at least one of them) is that you are using `~` to work with the home directory. Crontab does not know it, so you need to use the full path instead. – fedorqui Oct 27 '14 at 15:22
  • @fedorqui I'll give that a shot, but it doesn't have an issue with calling the script. It just can't find ack when it's called from inside the script (about halfway down the second code block) – I Dabble Oct 27 '14 at 15:24
  • Where is `ack` actually installed? `which ack` may tell you. If it shows a directory that is in the PATH you set in the `crontab` file, it is puzzling — there'll be a reason, but we haven't hit on it yet. If it shows a directory that's not on the PATH you set, there's an answer. Did you resubmit the `crontab` after making the changes to the file? – Jonathan Leffler Oct 28 '14 at 02:06
  • @JonathanLeffler ack is at `/usr/local/bin/ack`. The only thing different in my cron as of now is I substituted in the hard path instead of the `~` shortcut. – I Dabble Oct 28 '14 at 14:32
  • 1
    The line `mv $workarea/$files` probably doesn't do anything useful; `mv` requires two arguments and you only appear to give it one. You should run your script with the output going to a log file rather than `/dev/null`; this will allow you to see what's going wrong more easily. You should also modify the script to print its environment (temporarily), so that you can see what the actual value of `PATH` is when the script is run by `cron`. Are any of the other programs that you use in these scripts also in `/usr/local/bin`? Your main script writes to `$ERRORLOG`. Is there any useful info there? – Jonathan Leffler Oct 28 '14 at 14:47
  • Together with the very helpful indication from Jonathan Leffler , I would also say: quote. `mv "$workarea/$files" "something_else"`. This way, you prevent problems if file names contain spaces or other complicated characters. – fedorqui Oct 29 '14 at 09:09
  • @JonathanLeffler My bad. I missed copying over the destination somehow. I promise it was there in my script. I've added it above. @fedorqui The file names will never have spaces in them. The system they're stored in doesn't allow white space. Since we're having so much trouble with `ack`, I suppose I ought to ask if I can accomplish the same thing with `grep`. I haven't been able to get `grep` to do what `ack` is doing above, but maybe someone else is smarter with `grep` than I am. – I Dabble Oct 29 '14 at 11:25

2 Answers2

3

You need to set PATH enviroment variable in your cron job. So add this on the top of the cron file:

 #!/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

Note: also add #!/bin/bash, so you don't have to add shell enviroment variable too.

eax_rabb1t
  • 27
  • 1
  • 7
  • I tried adding that into my cron settings, but no dice. `#!/bin/bash` `PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin` `* * * * * bash ~/script &> /dev/null;` – I Dabble Oct 27 '14 at 14:52
3

It is because search path is not defined.

Use either full path in your script or define path

Option 1:

/path/to/ack -i 'mystring' 'searchdir'

Option 2:

PATH=/path/to/ackdir:$PATH
export PATH

ack -i 'mystring' 'searchdir'
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Arunas V.
  • 74
  • 3
  • I tried adding the full path to ack in the shell `/usr/local/bin/ack`, but it still didn't work. I also tried adding option 2 to my cron file, but no luck there either. – I Dabble Oct 27 '14 at 14:43
  • Looking at script and cronjob you provided in your question. Please ensure you avoid using home shortcut ~/ this is because you can write script in your user home folder which is /home/user, but cronjobs run under root user, so the meaning of ~/ will be different in this case. Unless you deine cronjob under the same user. – Arunas V. Oct 28 '14 at 08:37
  • I did remove the `~` shortcut and replace it with hard paths yesterday. Didn't change the outcome. – I Dabble Oct 28 '14 at 14:33
  • 1
    @ArunasV.: No, a cron job runs under the user who executed the `crontab` command to install it. Running cron jobs as root would be a *terrible* security hole. – Keith Thompson Oct 28 '14 at 14:49