2

I am just learning Linux, so please bear with me, as might have overlooked something obvious here. I am currently trying to setup a cron job to run a custom shell script. This script is running fine from the terminal but not via cron. Below are the details. I will appreciate any insights from the experienced users.

System Info

RELEASE=17.3
CODENAME=rosa
EDITION="Cinnamon 64-bit"
DESCRIPTION="Linux Mint 17.3 Rosa"
DESKTOP=Gnome
TOOLKIT=GTK
NEW_FEATURES_URL=http://www.linuxmint.com/rel_rosa_cinnamon_whatsnew.php
RELEASE_NOTES_URL=http://www.linuxmint.com/rel_rosa_cinnamon.php
USER_GUIDE_URL=help:linuxmint
GRUB_TITLE=Linux Mint 17.3 Cinnamon 64-bit

Custom shell script

Location: /usr/local/bin/make_ls_files.sh

Contents:

#!/bin/bash

# test script to echo ls stout to files
# (learning cron jobs)
  
# tilde path not working in cron, trying full path
# ls > ~/ls_file_$(date +%F_%H-%M-%S).log
ls > /home/zion/ls_file_$(date +%F_%H-%M-%S).log

The script runs fine from terminal (from any cwd), it outputs a file /home/zion/ls_file_2016-11-17_17-38-37.log with output of ls in it.

Now, I have setup a cron job via crontab -e:

# create text files every minute:
PATH=/usr:/usr/bin:/usr/local/bin
* * * * * make_ls_files.sh >> /usr/local/bin/make_ls_files_log.log 2>&1

I see in the syslog that it is in fact running, but no output or log entry is created. syslog shows this:

...
Nov 17 17:42:01 zion-VirtualBox CRON[4845]: (zion) CMD (make_ls_files.sh >> /usr/local/bin/make_ls_files_log.log 2>&1)
Nov 17 17:42:01 zion-VirtualBox CRON[4844]: (CRON) info (No MTA installed,  discarding output)
Nov 17 17:43:02 zion-VirtualBox CRON[4850]: (zion) CMD (make_ls_files.sh >> /usr/local/bin/make_ls_files_log.log 2>&1)
Nov 17 17:43:02 zion-VirtualBox CRON[4849]: (CRON) info (No MTA installed, discarding output)

Any ideas as to why it isn't working and how to debug?

EDIT 01:

I changed the cron job to:

* * * * * make_ls_files.sh 2>>$HOME/crontab.log

Now I am getting somewhere, the log file is created in /home/zion/crontab.log, containing:

/usr/local/bin/make_ls_files.sh: line 6: date: command not found
/usr/local/bin/make_ls_files.sh: line 6: ls: command not found

Why ls and date are not recognized?

EDIT 02

Thanks to all, I learned a few things here. As Ruslan pointend out I had 2 issues:

  • insufficient permission for log file location
  • insufficient path definitions

Everything is working now, the final cronjob below:

# create text files every minute:
PATH=/bin:/usr:/usr/bin:/usr/local/bin
# * * * * * make_ls_files.sh >> /usr/local/bin/make_ls_files_log.log 2>&1
* * * * * make_ls_files.sh 2 >> $HOME/crontab.log
Community
  • 1
  • 1
B-and-P
  • 1,693
  • 10
  • 26
  • 1
    you should use full path to `make_ls_files.sh` in crontab `* * * * * /usr/local/bin/make_ls_files.sh >> /usr/local/bin/make_ls_files_log.log 2>&1` – bansi Nov 17 '16 at 10:03
  • @bansi, it is not necessary, if `/usr/local/bin/` is in `$PATH` – Ruslan Osmanov Nov 17 '16 at 10:04
  • @RuslanOsmanov, Cron's default path is implementation-dependent and cannot be reliable across distros. So always better to be on the safer side. – bansi Nov 17 '16 at 10:08
  • also `make_ls_files.sh` must not be executable or writable for anyone else but the owner. unless overridden by using the -p option on the crond command line. – bansi Nov 17 '16 at 10:15
  • @bansi, he should check if his cron implementation supports specifying `PATH` in `crontab` (and the popuplar implementations do). If it supports, he should adjust `PATH` in `crontab`. It is not necessary to use full paths for all executables in crontab, as it is not necessary to specify full paths for commands in a terminal. Another option to write a wrapper for `SHELL`. But the OPs issue is most likely not a "command not found" error :) – Ruslan Osmanov Nov 17 '16 at 10:21
  • @RuslanOsmanov commands in a terminal and in cron behave differently since `$PATH` is different (quite smaller in cron). I agree with bansi that it is a good practice to use full paths to make things clearer and to be on the safer side. – fedorqui Nov 17 '16 at 10:27
  • @fedorqui, `PATH` is not something from the God. It is specified in the configuration files such as `/etc/profile`, `~/.profile`, `~/.bashrc`, etc. Similarly, `PATH` can be specified in `crontab`, if the cron implementation supports it. – Ruslan Osmanov Nov 17 '16 at 10:29
  • @RuslanOsmanov I know how PATH is set... As you can see from the edit the OP just made, messing around with `$PATH` can have side effects. So it is safer to just use full paths. – fedorqui Nov 17 '16 at 10:31
  • 1
    The problem now is that you have a limited PATH that do not contain the path to `date` and other commands. If you want to add paths into `PATH`, do use `PATH=$PATH:/usr/bin` etc, so that current ones are not lost. – fedorqui Nov 17 '16 at 10:32
  • 1
    @fedorqui, the real issue (except the permissions) is that he _overwrites_ the original `PATH`. If he had _appended_ them, he wouldn't have got this issue. Ah, you even mentioned that. So it is still a good idea to specify required paths in `crontab`, and use commands normally, just `ls`, `tar`, etc. instead of the suggested `/bin/ls`, or `/bin/tar` – Ruslan Osmanov Nov 17 '16 at 10:40
  • Thank you all for valuable input, side question: what is number 2 before output redirect `2>>`? – B-and-P Nov 17 '16 at 10:45
  • @B-and-P see [How to pipe stderr, and not stdout?](http://stackoverflow.com/a/2342841/1983854). It is stderr. – fedorqui Nov 17 '16 at 10:47
  • @RuslanOsmanov sorry I did not see you edited your comments. Exactly, I meant full paths for files, not for commands. So if you want to touch a file in the home directory, it is best to say `$HOME/file` instead of just `file` because it can happen that it then tries to find `/file` and not `/home//file`, etc. Regarding the paths for `ls` and other like these, they are in the "small" PATH that cron knows about, so there is no need to use the full path (plus it would be misleading). – fedorqui Nov 17 '16 at 14:47

1 Answers1

2

Most likely you don't have sufficient permissions to write to /usr/local/bin directory. It is easily verified by running touch /usr/local/bin/myfile in a terminal.

You should redirect the errors to a log file in order to find out the exact reason.

Make sure that all executables in the script are available through PATH, i.e. the directories into the PATH list.

Example

PATH=$PATH:/bin:/usr:/usr/bin:/usr/local/bin
* * * * * make_ls_files.sh >> /tmp/make_ls_files_log.log 2>>$HOME/crontab.log

Note, you need at least write (w) and execution (x) permissions for the log file directories!

Also note, that your Cron implementation should support overriding PATH environment variable via crontab. Otherwise, you should specify absolute paths for all executables. You can also adjust PATH in the shell script as follows

export PATH=$PATH:/bin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin

(just before using the commands).

P.S.: use which command in a terminal to detect location of a command, e.g. which ls.

Ruslan Osmanov
  • 20,486
  • 7
  • 46
  • 60
  • You are right, I suppose I didn't have permission to write to `/usr/local/bin`, changed the log file path and now getting output. See my edit above. – B-and-P Nov 17 '16 at 10:31
  • @B-and-P, include `/bin` to `PATH`. Use `which` command in a terminal to check where it is located, e.g. `which ls` – Ruslan Osmanov Nov 17 '16 at 10:33
  • Aha! excellent, thanks! So, aren't paths defined in crontab added to the system wide paths, but overriden? – B-and-P Nov 17 '16 at 10:36
  • 1
    @B-and-P, if you write `PATH=your-paths`, you overwrite the original value. If you write `PATH=$PATH:/your/path`, you append your paths to the original value – Ruslan Osmanov Nov 17 '16 at 10:37