Crontab not processing parameters sent to script.

Hello All,

I'm running Debian on a ThinkPad X1/2G and all seems to be running well.

However, it's got a SSD that needs the trim command run at regular intervals.
I'm implementing this using cron and a shell script, as recommended.

The cron job entries are as follow:

0 * * * * /etc/cron.hourly/trim /
* 0 * * * /etc/cron.hourly/trim /home

And the script is:

LOG="/TRIM.LOG"
echo "$(date) Started... $1" >> $LOG

if [ -z "$1" ];
then echo "No parameters" >> $LOG
else echo "Trimming $(fstrim -v $1)" >> $LOG
    fi

I seem to be having a problem getting the parameters from cron
to be recognised by fstrim as parameters in the shell script even though bash
seems to recognise the parameters.

If I run the script './trim /' as root at the command line it works as expected with
bash and fstrim recognising the variables.

Other things tried...
Hard-coding the parameters seems to work.
Checked permissions on script 0755.

Any ideas?

Did you create the normal user's environment for the cron job? cron per default has a very limited environment.

I created a root user file with the 'crontab -e' command line.
The schedule seems to be executing at the right time and
passing the expected arguments to bash successfully.

Is it possible cron is adding invisible formatting to the argument
that bash interprets as normal but fstrim interprets as an error?

Look at your log file. The 2nd line your script:

"$(date) Started... $1" >> $LOG

includes the argument passed to your script by cron when it writes to the log file.

If you add the line:

echo "SHELL is $SHELL" >> $LOG

right after the above line in your script, what does it add to your log file when you run your script manually and what does it add to your log file when you run it from cron ?

What output are you seeing in your log file from the line:

else echo "Trimming $(fstrim -v $1)" >> $LOG

What operating system are you using?

You say *If I run the script './trim /' as root at the command line it works as expected with bash and fstrim recognising the variables."

Are these cron jobs in the root crontab? Or running as some other user?

I assume it still runs interactively if you:

/etc/cron.hourly/trim /

using the full path?

Sorry for the late reply.

hicksd8
-----------
I created the jobs when logged in as root with the 'crontab -e' command. I do get the message that the jobs have been updated and the schedule and script do execute as you would expect.

Running the command with an absolute path, I get the same outcome as I do with a relative path and I get the full output from the command as if it was called from the command line.

Don
-----
It seems to be using /bin/sh as the shell even thou I requested that it uses bash with the shebang. The log file shows that when I issue the command from the CLI it uses bash.
I included the passed variable before the fstrim command is issued and it seems to recognise the variable without a problem. It's only after the fstrim command that the variable is not recognised!

The OS I'm using is Debian derivative Kali.

Script used to generate logfile below.

#!/bin/bash
###############################################################################
##  SCRIPT TO TRIM SSD DRIVE
###############################################################################
##  INPUT: $1 MOUNT POINT OF PARTITION
###############################################################################
LOG=/TRIM.LOG
echo "####" >> $LOG
echo $(date) >> $LOG
echo "SHELL is $SHELL" >> $LOG

    if [ -z "$1" ];
    then echo "No Target" >> $LOG
    else echo "Trimming $1 $(fstrim -v $1)" >> $LOG
        fi

Logfile from above script. Last line shows output from command manually issued at the CLI.

####
Tue Jun 9 03:31:01 BST 2015
SHELL is /bin/sh
Trimming / 
####
Tue Jun 9 03:32:01 BST 2015
SHELL is /bin/sh
Trimming / 
####
Tue Jun 9 03:33:01 BST 2015
SHELL is /bin/sh
Trimming / 
####
Tue Jun 9 03:34:01 BST 2015
SHELL is /bin/sh
Trimming / 
####
Tue Jun 9 03:35:01 BST 2015
SHELL is /bin/sh
Trimming / 
####
Tue Jun 9 03:36:01 BST 2015
SHELL is /bin/sh
Trimming / 
####
Tue Jun 9 03:36:28 BST 2015
SHELL is /bin/bash
Trimming / /: 380747776 bytes were trimmed

Just to see what would happed, I added the eval command just before fstrim that had no effect. Also I tried coding the variable differently i.e. ${1} and ${$1} also no change.
Interestingly, I did find this site that seems to suggest either using the 'bash -c' command or setting the EV 'SHELL=/bin/bash' actually in the crontab file.
How to change cron shell (sh to bash)? - Unix & Linux Stack Exchange
I'll give this a go and report back, but I'd still like to permanently change the shell crontab uses to Bash.

Thanks for your help.

---------- Post updated 09-06-15 at 12:23 AM ---------- Previous update was 08-06-15 at 11:50 PM ----------

Followed the file /bin/sh and it lead to a Debian specific shell called dash!
Apparently it is supposed to be compatible with bash as documented here
Unix Shells: Bash, Fish, Ksh, Tcsh, Zsh - Hyperpolyglot
using the same notation for passed parameters.

Doesn't seem to want to work with the EV set in the crontab file. Was going to change the /etc/crontab setting to SHELL=bin/bash but the whole system has been setup to run faster with dash as bash is much slower and who knows what changing shells will actually do.

If it is not the shell as it does seem to accept the variables that have been passed, could it be a problem with the fstrim command?

As has been said MANY times before, cron doesn't create the same environment that you get when you login. And, there is nothing in your script that attempts to set variables that are needed in your script (in this case, cron is running your job with a default setting for PATH , and it appears that fstrim is not found on the default PATH ) or fstrim needs something set in its environment that cron does not provide.

If you change:

    else echo "Trimming $1 $(fstrim -v $1)" >> $LOG

to:

    else echo "Trimming $1 $(/absolute/path/to/fstrim -v $1)" >> $LOG

where /absolute/path/to is the directory in which the fstrim utility is located on your system and fstrim doesn't depend on any environment variables being set to values not initialized as needed by cron , it might work. Otherwise, you need to set up your login environment in /etc/cron.hourly/trim using the initialization files your login shell invokes when you login, or explicitly determine exactly what is in your environment when your script works that is not in your environment when your script fails AND then be sure the needed environment is created in /etc/cron.hourly/trim before it invokes fstrim .

I wonder if /etc/cron.hourly/ is a magic place where executables are run once an hour by root without a crontab entry - and without arguments.
If you have a crontab entry they are run twice...
BTW the man page for fstrim recommemds to run it weekly.

Awsome!

Just adding the absolute path works, in this case /sbin/fstrim on Debian.
Thanks for every-bodies help.

MIG: After further investigation, it does indeed seem that it is the case
that cron runs scripts at the appropriate named folder times. I eventually
moved all script files to a different location.

At the moment I'm experimenting with the frequency of calls to trim the
mount points. On occasions, it's releasing the entire capacity of the
partition i.e. 128GB. At the moment it is an empty partition and unused.
No idea where it is getting 128GB.

Quick note on dash shell... A lot is missing from it in the name of speed
and security and it requires a lot of experimenting to get your scripts
to work.