LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-12-2012, 03:30 AM   #1
hypernetics
Member
 
Registered: Oct 2003
Location: Berlin, GER
Posts: 35

Rep: Reputation: 15
Combined find/rm in cron


Hi folks,

the following behaviour is driving me mad.

I try to convince my system (centos 5.5) to remove files in a directory older than 3 days. So I added the following line to root's crontab:

Code:
*/5 * * * * /usr/bin/find /backups -mtime +2 -exec /bin/rm {} \;
Result: Nothing happens. The old file still resides in the directory.
Moving the instructins into a shell script doesn't work either.

So I'm a bit helpless.

Can anybody help me out?

Last edited by hypernetics; 06-12-2012 at 03:48 AM.
 
Old 06-12-2012, 09:28 AM   #2
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,779

Rep: Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212
Looks OK to me. Is there anything revealing in /var/log/cron ?
 
Old 06-12-2012, 10:14 AM   #3
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by hypernetics View Post
Code:
*/5 * * * * /usr/bin/find /backups -mtime +2 -exec /bin/rm {} \;
If the first match is a directory, /bin/rm will not be able to remove it (because it is a directory), and therefore returns a nonzero exit status. A nonzero exit status will cause find to abort the search. That should not abort the search, though.

Anyway, To fix the issue, limit the search to files, and use the -f (force delete) flag for rm (to never prompt, and ignore if the file happens to vanish in the mean time -- it might have been a temporary file or something):
Code:
/usr/bin/find /backups -type f -mtime +2 -exec /bin/rm -f '{}' ';'
However, since you're using GNU tools, I recommend you use the equivalent but much faster and simpler
Code:
/usr/bin/find /backups -type f -mtime +2 -delete
instead.

Last edited by Nominal Animal; 06-12-2012 at 03:10 PM.
 
Old 06-12-2012, 10:34 AM   #4
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,779

Rep: Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212
Quote:
Originally Posted by Nominal Animal View Post
If the first match is a directory, /bin/rm will not be able to remove it (because it is a directory), and therefore returns a nonzero exit status. A nonzero exit status will cause find to abort the search.
What version of find do you have that behaves that way? Sounds seriously broken. What is supposed to happen is that find treats the result as true or false depending on the exit status and continues to evaluate the expression accordingly.
 
Old 06-12-2012, 03:18 PM   #5
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by rknichols View Post
What version of find do you have that behaves that way?
Nominal Animal brainfart #1957264, apparently.

Quote:
Originally Posted by rknichols View Post
What is supposed to happen is that find treats the result as true or false depending on the exit status and continues to evaluate the expression accordingly.
And that is exactly what happens using find (GNU findutils) 4.4.2) at least.

Is it possible OP's cron might de-escape the final \; for some reason -- a cron bug perhaps?
 
Old 06-12-2012, 04:52 PM   #6
Tinkster
Moderator
 
Registered: Apr 2002
Location: earth
Distribution: slackware by choice, others too :} ... android.
Posts: 23,067
Blog Entries: 11

Rep: Reputation: 928Reputation: 928Reputation: 928Reputation: 928Reputation: 928Reputation: 928Reputation: 928Reputation: 928
Quote:
Originally Posted by Nominal Animal View Post
Nominal Animal brainfart #1957264, apparently.


And that is exactly what happens using find (GNU findutils) 4.4.2) at least.

Is it possible OP's cron might de-escape the final \; for some reason -- a cron bug perhaps?
Not a bug - documented behaviour.
man 5 crontab
Code:
       The ``sixth'' field (the rest of the line) specifies the command to be run.  The entire command portion of the line, up to a newline
       or % character, will be executed by /bin/sh or by the shell specified in the SHELL variable of the crontab file.  Percent-signs  (%)
       in  the  command, unless escaped with backslash (\), will be changed into newline characters, and all data after the first % will be
       sent to the command as standard input. There is no way to split a single command line onto multiple lines, like the shell's trailing
       "\".
But I, too, have been bitten by this in the past ... anything but the simplest
bash things for me goes into shell-wrappers if I need to run it via cron ;D

The docu for cron on AIX is slightly more precise in the description of the
importance (and "features") of the backslash:
Code:
Note: Any character preceded by a backslash (including the %) causes that character to be treated literally.

Cheers,
Tink
 
Old 06-12-2012, 06:21 PM   #7
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by Tinkster View Post
Not a bug - documented behaviour.
Ah, that explains it, then: the shell consumes the semicolon which cron helpfully de-escaped, causing find to fail with find: missing argument to `-exec' . Good catch, Tink.

hypernetics, you can fix your command using ';' instead of \; although I do recommend you use the equivalent but faster and simpler find /backups -type f -mtime +2 -delete instead.
 
Old 06-12-2012, 06:27 PM   #8
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,779

Rep: Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212
Quote:
Originally Posted by Tinkster View Post
Not a bug - documented behaviour.
[SNIP]
The docu for cron on AIX is slightly more precise in the description of the
importance (and "features") of the backslash:
Code:
Note: Any character preceded by a backslash (including the %) causes that character to be treated literally.
Interesting. The cron daemon (cronie-1.4.4-7.el6) in RHEL-6 does not do that. The "\;" at the end of the command is passed literally to the find command, which works just as the OP intended.
 
Old 06-12-2012, 06:43 PM   #9
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by rknichols View Post
Interesting. The cron daemon (cronie-1.4.4-7.el6) in RHEL-6 does not do that. The "\;" at the end of the command is passed literally to the find command, which works just as the OP intended.
Literally \;? Do you mean that cron passes it as-is to the shell, which de-escapes it to ; ? I'd expect the latter.
Or does cronie cron execute the command directly, without a shell? That is possible, but it would be a big departure from traditional crons.

In any case the differences indicate it is probably a bad idea to make any assumptions about how cron handles the command parameters wrt. escaping, and use a separate script instead, like Tinkster mentioned.
 
Old 06-12-2012, 10:21 PM   #10
rknichols
Senior Member
 
Registered: Aug 2009
Distribution: Rocky Linux
Posts: 4,779

Rep: Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212Reputation: 2212
Quote:
Originally Posted by Nominal Animal View Post
Literally \;? Do you mean that cron passes it as-is to the shell, which de-escapes it to ; ? I'd expect the latter.
Or does cronie cron execute the command directly, without a shell? That is possible, but it would be a big departure from traditional crons.
OK, my turn for a brain fart. The cron daemon passes it literally to the shell, which then passes just the ";" character as an argument to find.

I ran a few tests (while linuxquestions.org was down) and found that if the command is "simple" (no shell meta-characters, though simple quoted strings seem to bo OK), the cron daemon will indeed bypass the shell and directly exec() the command. For anything more complicated, the command line is passed with "-c" to a shell.
 
Old 06-13-2012, 11:00 AM   #11
Nominal Animal
Senior Member
 
Registered: Dec 2010
Location: Finland
Distribution: Xubuntu, CentOS, LFS
Posts: 1,723
Blog Entries: 3

Rep: Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948Reputation: 948
Quote:
Originally Posted by rknichols View Post
I ran a few tests (while linuxquestions.org was down) and found that if the command is "simple" (no shell meta-characters, though simple quoted strings seem to bo OK), the cron daemon will indeed bypass the shell and directly exec() the command. For anything more complicated, the command line is passed with "-c" to a shell.
Thanks; that is very interesting, and useful to know for me.

You see, for administration I often create a directory (typically /usr/local/bin/admin/) to put scripts that any user can run privileged using sudo. Instead of adding that directory to PATH and adding the one-line privilege escalation test at the start of the script, I prefer to create aliases similar to admin-task="sudo -- /usr/local/bin/admin/task" . While these tasks are only intended to be run interactively by humans, I now know the reason why it may fail if somebody puts one in cron: as it is an alias, it cannot be exec()d directly, which the cron may do if the command is simple. It is very useful to have it documented (in the README at that directory); thank you.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
/etc/cron.daily/find script sulekha Ubuntu 1 11-09-2008 03:06 AM
adding a perl script to cron.daily / cron.d to setup a cron job CrontabNewBIE Linux - Software 6 01-14-2008 08:16 AM
How to find out if cron is running ? Rustylinux SUSE / openSUSE 3 01-25-2007 12:22 PM
annoying cron job on find, how to get rid of it feetyouwell Linux - Software 2 06-27-2005 08:44 PM
New to cron programming: need to find a good tutorial lhoff Programming 1 03-31-2002 02:00 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 05:43 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration