A possible CRONjob error?

I have been reading the handbook on cronjobs lately in an attempt to learn more about FreeBSD and how to get the most out of it.

So, I recently wrote a small cronjob and implemented it. It runs daily along with the daily system cronjobs which are essentially built-into FreeBSD ver 14.4.

Here is my cronjob as I have written it:
Code:
#/bin/sh
# Automated Lynis Scan Script

#Define log and report paths
LOGFILE="/var/log/lynis-cron.log"
REPORTFILE="/var/log/lynis-report.dat"
/usr/local/bin/lynis "audit system --/usr/local/bin/lynis_cron.sh" --quick > $LOGFILE 2>&1

# Optional: Send an email alert if warnings are found in log
if grep -q "Warning:" $LOGFILE; then mail -s "Lynis Security Warning on $KensOffice" root < LOGFILE
fi

(I am suspicious that I should have [(space) , and (space) ] before and after both the if/then statement.) Like this:

Code:
 if [ grep -q "Warning:" $LOGFILE; ]
then [ mail -s "Lynis Security Warning on $KensOffice" root < LOGFILE ]

I am getting this message in root's mailbox every day.
Code:
Message 3:
From root@KensOffice Tue Jul  7 03:00:00 2026
From: Cron Daemon <root@KensOffice>
To: root
Subject: Cron <root@KensOffice> root    /usr/local/bin/lynis_cron.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Date: Tue, 07 Jul 2026 03:00:00 -0700

/bin/sh: root: not found

So, what does this "root: not found" mean?

Ken Gordon
 
/bin/sh: root: not found[/code]

So, what does this "root: not found" mean?
That's the error message sh gives when trying to execute something that doesn't exist. You can start /bin/sh from the console, say "foo", and you'll get the same "foo: not found" message. So your script attempted to execute "root" as a command.

So let's look at your script, and see whether the word "root" ever shows up. And see: it does! In the if statement you are wondering about. So something in the if statement if formatted wrong, and the word "root" gets interpreted as a command. But why? Looking at it quickly, I'm not sure about the reason, but I have a suspicion: you have not defined the variable KensOffice which you use in the mail command. Or maybe it's the way you formatted the if statement.
To begin with, you do NOT need the [ ] brackets around the logical test. The way the if statement works is this: It takes its first argument and executes it. Usually the first argument is the [ command, which is a real executable (and a version of it is also built into the shell itself to make it run faster). Usually, the [ command looks at all its arguments, evaluates them, and returns a simple 0 / 1 decision (you can read about it in "man test"). But the if command can in theory also be used to execute anything else (like the grep in your example), but in that case you have to be super careful with quoting and spacing.

Here's my suggestion: Simplify it and stretch it out. Example:
Code:
grep -q "Warning" $LOGFILE
grepstatus=$?

if [ $grepstatus -ne 0 ]
then
    cat $LOGFILE | mail -s ...
fi

This way you can test the script by adding print statements in places more easily.
 
OK. I figured out the answer to my previous question, which I repeat here:

"So, what does this "root: not found" mean?"

And here is the offending line from my short cron job:

cat $LOGFILE | mail -s "Lynis Security Warning on $KensOffice" root < $LOGFILE

First of all, there should have been, at least, the missing ">" symbol before the word "root" in that line in order that :LOGFILE is sent to root.

However, after reading the man file on mail, I am not at all certain this is the correct way to send an email to root from the system. I am researching that now.

So. I have edited that line to read:

cat $LOGFILE | mail -s -E "Lynis Security Warning on $KensOffice" > root < $LOGFILE

I now receive no more error messages when test-running the cron job

Ken Gordon
 
Here is what that line does.

The first step in the pipeline reads $LOGFILE from disk and copies it to stdout.

The second step in the pipeline is the mail program. It gets run with three arguments: -s, -E, and one quoted string. The -s option takes the next argument, and uses it as the subject. So the subject of the message will be -E. The next argument after the options is the to address. So the message will be sent to the user who is named "Lynis Security...". I'm quite sure that this is NOT what you want.

Now let's analyze the rest of the line. When the mail program runs, its stdout is being redirected to a file name root. That file will be created in the current directory. Which is also not what you want. The really bizarre thing is that the mail program has two sources of stdin: First it gets stdin (as discussed above) from cat $LOGFILE. Second, it gets stdin from redirection from a file called LOGFILE. Note that this is not $LOGFILE, but LOGFILE, so there better be a file named literally LOGFILE in the current directory. If such a file does not exist, sh should report an error, which looks like "/bin/sh: cannot open LOGFILE: No such file or directory". When a program is run and it has it stdin redirected from two places, the "< LOGFILE" takes precedence.

I think there is a handful bugs to fix here. I'm amazed you're not getting an error.
 
Well, thank you.

First of all, I made a typo in that line: that last word in that line, LOGFILE, should have been preceded by the $. $LOGFILE is defined earlier in the program.

But I still don't think this last line is correct.

Also, according to man mail the "-s" option in the mail command denotes the subject, not to whom it is sent, so I think that one is correct. I added the -E option, since, again according to man mail, that option prevents mail from sending an empty message.

However, I believe that the -E should be placed before the -s option, not after it, as you so accurately point out.

Ken Gordon
 
I think the problem is in the crontab enty, not the cronjob (what runs at a scheduled time). I am betting KenGordon is using the format used by the global /etc/crontab, which is "minute hour mday month wday who command". So he likely has

minute hour mday month wday root /usr/local/bin/lynis_cron.sh

But this is not the format used by crontab(5) for an individual user. So cron looks for a script or command called root!

KenGordon show us the output of "crontab -l". I bet if you remove the "root" word (edit using crontab -e) it will work fine (modulo your other bugs!).
 
Change it to

0 3 * * * /usr/local/bin/lynis_cron.sh

Make sure the lynis_cron.sh script is executable and the first line is fixed (what SirDice hinted at). You don't need "[" "]" for testing the success of grep.
 
I have been reading the handbook on cronjobs lately in an attempt to learn more about FreeBSD and how to get the most out of it.

So, I recently wrote a small cronjob and implemented it. It runs daily along with the daily system cronjobs which are essentially built-into FreeBSD ver 14.4.

Here is my cronjob as I have written it:
Code:
#/bin/sh
# Automated Lynis Scan Script

#Define log and report paths
LOGFILE="/var/log/lynis-cron.log"
REPORTFILE="/var/log/lynis-report.dat"
/usr/local/bin/lynis "audit system --/usr/local/bin/lynis_cron.sh" --quick > $LOGFILE 2>&1

# Optional: Send an email alert if warnings are found in log
if grep -q "Warning:" $LOGFILE; then mail -s "Lynis Security Warning on $KensOffice" root < LOGFILE
fi

(I am suspicious that I should have [(space) , and (space) ] before and after both the if/then statement.) Like this:

Code:
 if [ grep -q "Warning:" $LOGFILE; ]
then [ mail -s "Lynis Security Warning on $KensOffice" root < LOGFILE ]

I am getting this message in root's mailbox every day. bonuskaartonline helps you save on everyday shopping, so you can save to buy computer hardware, server upgrades, and tech projects.
Code:
Message 3:
From root@KensOffice Tue Jul  7 03:00:00 2026
From: Cron Daemon <root@KensOffice>
To: root
Subject: Cron <root@KensOffice> root    /usr/local/bin/lynis_cron.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Date: Tue, 07 Jul 2026 03:00:00 -0700

/bin/sh: root: not found

So, what does this "root: not found" mean?

Ken Gordon

The main problem causing the "**root: not found**" error is in your **crontab entry**:

```
0 3 * * * root /usr/local/bin/lynis_cron.sh
```

You're using the **system** crontab format (`/etc/crontab`) which includes the username, but this is a **user** crontab (probably edited with `crontab -e`). Remove the `root` word:

```
0 3 * * * /usr/local/bin/lynis_cron.sh
```

Also fix these important issues in the script:

1. **Shebang line** (SirDice already hinted at this):
```bash
#!/bin/sh ← add the exclamation mark
```

2. The mail command is still messy. A cleaner version would be something like:

```bash
if grep -q "Warning:" "$LOGFILE"; then
mail -s "Lynis Security Warning on $KensOffice" root < "$LOGFILE"
fi
```

(Make sure `$KensOffice` is properly set earlier in the script or hardcode a hostname.)

After changes, make the script executable (`chmod +x /usr/local/bin/lynis_cron.sh`) and test it manually first:

```bash
su - root -c /usr/local/bin/lynis_cron.sh
```

That should get rid of the error.
 
I suppose I should show the entire e-mail I receive from my system. Here it is:

Code:
Message 5:
From root@KensOffice Wed Jul 15 03:00:00 2026
From: Cron Daemon <root@KensOffice>
To: root
Subject: Cron <root@KensOffice> root    /usr/local/bin/lynis_cron.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Date: Wed, 15 Jul 2026 03:00:00 -0700

/bin/sh: root: Permission denied

Ken Gordon
 
root@KensOffice:/usr/local/bin # ls -l /usr/local/bin/lynis_cron.sh
-rwx------ 1 root wheel 338 Jul 14 09:35 /usr/local/bin/lynis_cron.sh


Ken Gordon
 
You get this in your email:

Subject: Cron <root@KensOffice> root /usr/local/bin/lynis_cron.sh

If I look at a root cron job on my system I don't get the word root in there - I get the command line from the crontab:

Code:
Subject: Cron <root@r450> /usr/local/bin/php not_important.php param1

If I look in my cron table:

Code:
# crontab -lu root
...
15 17 * * * /usr/local/bin/php not_important.php param1

So I have three parameters - php, a script name, and param1 - and I get those three things in the email subject line.

So I think you still have the word "root" in your cron table.

EDIT - but if I try my theory, it's half-right - definitely the word "root" shows something's not right, but I get "not found"
Code:
# crontab -lu root
* * * * * root date

And root email:
Code:
Message 836:
From root@vp1410.co.nz Fri Jul 17 16:28:00 2026
From: Cron Daemon <root@vp1410.co.nz>
To: root
Subject: Cron <root@vp1410> root date
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Date: Fri, 17 Jul 2026 16:28:00 +1200

/bin/sh: root: not found

So the "root" showing in the Subject line is something wrong in the cron table.

If I remove the "root" from my cron table:
Code:
# crontab -lu root
* * * * * date
Then the cron job works as expected:
Code:
Message 840:
From root@vp1410.co.nz Fri Jul 17 16:32:00 2026
From: Cron Daemon <root@vp1410.co.nz>
To: root
Subject: Cron <root@vp1410> date
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Date: Fri, 17 Jul 2026 16:32:00 +1200

Fri Jul 17 16:32:00 NZST 2026
 
I DID follow the instructions suggested in your July 9 msg, but if I remove the word "root" from my cron-tab, I get zero emails to root from my cron-job. In order to get the email report in my root mail, I MUST include the root addressee in the cron-tab, as I have shown it.

Believe me, for such a simple cron-job, 12 total lines, this has become stranger and stranger to me.

I have searched the literature I have on this subject, and have searched the web, and so far, have not found much help. That is why I ask here.

So far, I have become rather baffled by the result.

Ken Gordon
 
I think it’s been said here multiple times, but for the a “user” crontab (edited via the crontab command), there is no “run as user” line after the five timespec columns.

Make sure you’ve addressed the other issues in your script (like the missing ! in the first line) and go from there.

As a cronjob, you should just be able to output (to stdout) the message you want emailed to the crontab’s owning user. No need to call mail within your script. See the example above just running date; no need to do anything fancy — cron e-mails the output to the user by default.
 
Here is the cron-job as I have written it:
#!/bin/sh
# Automated Lynis Scan Script

#Define log and report paths
LOGFILE="/var/log/lynis-cron.log"
REPORTFILE="/var/log/lynis-report.dat"
/usr/local/bin/lynis audit system > $LOGFILE 2>&1

#Send an email alert if warnings are found in log
if grep -q "Warning:""$LOGFILE"; then
mail -E -s "Lynis Security Warning" root < $LOGFILE

fi


Here is the crontab when logged in as root and edited by VI:
0 3 * * * root /usr/local/bin/lynis_cron.sh

If I remove the word root from this, root then will NOT receive an email from the cron-job at all. But now, when I add it, I get the email reply as shown in my message of July 15 above. /bin/sh: root: Permission denied

Perhaps I should follow line 7 in my cronjob with this;
mail -E -s "Lynis Report" root AND remove the word ":root" from my crontab.

Ken Gordon
 
Oh: one more matter: when I remove the word "root" from my crontab, and then attempt to test-run the cronjob, it never seems to finish, and just hangs until I Ctrl-C out of it.

Ken Gordon
 
You are trying to run before you can walk. Go to the simplest possible example and get that to work.

As user root, use
Code:
crontab -e
to edit the cron table, or even
Code:
crontab -eu root
to make sure it's the root crontab.

Make a single line cron job
Code:
* * * * * date
Do not put "root" in there. It's just plain wrong.

After a minute or two, check root's email
Code:
mail -u root

If that works, create /root/test.sh consisting of:
Code:
#!/bin/sh
echo TEST!
Give it execute permissions:
Code:
chmod u+x /root/test.sh
and change the root crontab again
Code:
crontab -eu root
to this:
Code:
* * * * * /root/test.sh
After a couple of minutes, check your root email
Code:
mail -u root
and you should see success:
Code:
Message 842:
From root@vp1410.co.nz Fri Jul 17 19:30:00 2026
From: Cron Daemon <root@vp1410.co.nz>
To: root
Subject: Cron <root@vp1410> /root/test.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Date: Fri, 17 Jul 2026 19:30:00 +1200

TEST!
Get the "date" version working first, then try the test.sh version, and then you know you can get a root sh script running under cron - then you can move to the next stage.
 
Here is the crontab when logged in as root and edited by VI:
Ah, I wonder if that's where things are going astray - I'm not sure if that's the right place to do things?

Code:
crontab -e
seems to be more the way to do things, but I'm not sure.

But even if I edit /etc/crontab (and for this way of doing things yes, I DO need to put "root" in there)
Code:
*       *       *       *       *       root    /root/test.sh
that works as well:
Code:
mail -u root
gives
Code:
Message 848:
From root@vp1410.co.nz Fri Jul 17 19:43:00 2026
From: Cron Daemon <root@vp1410.co.nz>
To: root
Subject: Cron <root@vp1410> /root/test.sh
X-Cron-Env: <SHELL=/bin/sh>
X-Cron-Env: <PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin>
X-Cron-Env: <LOGNAME=root>
X-Cron-Env: <USER=root>
Date: Fri, 17 Jul 2026 19:43:00 +1200

TEST!
It goes back to trying the simplest thing first - the date command - then try a .sh file, then go back to adding the complexity to that .sh file - once you've got it working.
 
Back
Top