A puzzle! Crontab and mkdir and files, oh my!

Karl Auer kauer at biplane.com.au
Thu Apr 24 13:03:11 UTC 2025


On Thu, 2025-04-24 at 14:16 +1000, Karl Auer wrote:
> On Thu, 2025-04-24 at 14:01 +1000, Karl Auer wrote:
> > This is a crontab entry. I've broken it up over several lines for
> > clarity, but it's all one line in the crontab.
> > 
> > The first line is just saying "do this every day at 01:00".
> > 
> > The second line locates and deletes directories matching "*_temp*.
> >  
> > But what is going on in the last line?
> > 
> >    0 1 * * * 
> >    find /home/ubuntu/data -type d -name '*_temp*' -exec rm -r {} +
> >    > mkdir /home/ubuntu/data/log/adfd_cleanup.log 2>&1
> > 
> > Please - no theories! If you know, you know. And I don't know!
> 
> Now I do know.
> 
> I'll wait to tell you more in case the people that like a puzzle want
> to have a go at figuring it out. But I will leave a hint: The crontab
> line as a whole is badly broken.

OK, strap in, this is my best effort at an explanation :-)

What this crontab entry actually does, every day at 1am, is drop these
lines into a file called "mkdir" in the user's home directory (it's a
user crontab, you can tell because there is no username after the time
specification):

   find: paths must precede expression:
`/home/ubuntu/data/log/adfd_cleanup.log'
   find: possible unquoted pattern after predicate `-exec'?

The first mistake in the entry is "mkdir". I'm really not sure what the
intention was with that, but I think it just shouldn't be there at all.
Because of "mkdir" the path after it causes "find" to output an error
and stop (more on that later). It doesn't try to find anything and it
doesn't run "rm", so the only output is the error messages.

The second mistake (I suspect) was using a single ">" instead of ">>".
The single ">" causes the output to overwrite the log file every time.
Except it overwrites "mkdir" every time because of the first mistake.

It's been suggested that this crontab entry arose because of a cut and
paste error. It was clearly never tested, which is arguably mistake
number three.

Basically the find command failed because it could not properly parse
its arguments. The final "2>&1" sent the error output to the same place
as its standard output - namely into a file called "mkdir".

Simplified, the end result of all this is

   find x -exec y {} + > mkdir /some/path 2>&1

... where x and y may or may not exist.

On my system I don't get the second error message. This may be a
difference between Linux versions; I am running 20.04LTS, the offending
crontab is on 24.04LTS.

Now, how come find "sees" that final path at all? Why does it see
anything on the command line after the point where its output is
redirected? Because the shell only "consumes" from the command line
what it needs to do the redirection. The rest still gets passed to the
command as extra arguments. You can see it more clearly with this:

   kauer at kt1:~$ ls t.txt fred mary
   ls: cannot access 'fred': No such file or directory
   ls: cannot access 'mary': No such file or directory
   t.txt
   kauer at kt1:~$ ls t.txt > fred mary
   ls: cannot access 'mary': No such file or directory
   kauer at kt1:~$ cat fred
   t.txt

Neither "fred" nor "mary" exist initially, so the un-redirected ls
complains about them. "t.txt" does exist, so it is listed.

In the redirected version, "fred" is consumed as the redirection target
and is not seen by the redirected ls. But "mary" is still passed as an
additional argument to ls, causing a complaint.

Here's another example:

   kauer at kt1:~$ ls fred mary
   ls: cannot access 'fred': No such file or directory
   ls: cannot access 'mary': No such file or directory
   kauer at kt1:~$ echo blah > fred mary
   kauer at kt1:~$ cat fred
   blah mary

Happy to hear corrections or better explanations.

Regards, K.

-- 
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Karl Auer (kauer at biplane.com.au, he/him)
http://www.biplane.com.au/kauer





More information about the ubuntu-users mailing list