2

To remove all emails for all users of a Linux machine, I run:

find /var/spool/mail/ -regextype sed -regex "^.*[^/]$" -exec :> {} \;

... however I received the following error message(s):

find: ‘:’: No such file or directory
find: ‘:’: No such file or directory
find: ‘:’: No such file or directory

What is wrong?

terdon
  • 242,166
Ωmega
  • 123
  • 1
    But your attempt wouldn't work anyway, see: https://unix.stackexchange.com/a/481707/70524. Try truncate, perhaps. – muru Sep 08 '19 at 14:39
  • Thanks, @muru. Indeed, find /var/spool/mail/ -regextype sed -regex "^.*[^/]$" -exec truncate -s 0 {} \; is the best solution. – Ωmega Sep 08 '19 at 14:52
  • 1
    @muru It's IMHO not an exact duplicate as the built-in-ness of : is only part of the issue. The redirection is the other part. – Kusalananda Sep 08 '19 at 15:59
  • 1
    Note that even if this worked, you wouldn't need the : in the first place (not in bash, anyway). You can just do > file and that will empty it. There's no need to do : > file. So even less of a duplicate since the : is essentially irrelevant here. – terdon Sep 08 '19 at 21:03

2 Answers2

4

What's the point of using a regex here? Why not just use find /var/spool/mail/ -type f? and use -maxdepth 1 if you want to prevent recursion into any sub-directories.

Also, why truncate the user mailboxes when you can just delete them? e.g.

find /var/spool/mail/ -type f -delete

or

find /var/spool/mail/ -type f -exec rm {} +

When new mail arrives for a user, the MTA or MDA will create the mbox files as required, with the correct ownership and perms.

cas
  • 78,579
3

You seem to want to truncate the mailboxes for all users. You can't do this by calling : from find as : is not an external utility (it's a shell built-in utility). Using true instead of : would have worked since that is commonly available as an external command, but...

You also can't use a redirection in the command executed via -exec since that redirection would be acted upon by the shell at the time when the find utility first starts (not once for each found file).

Your command is essentially the same as

find /var/spool/mail/ -regextype sed -regex "^.*[^/]$" -exec : \; >{}

i.e., it will create a file called {} into which the standard output stream of find is redirected.

Instead, you may do something like

find /var/spool/mail -type f -exec sh -c '
    for pathname do
        : >"$pathname"
    done' sh {} +

As a "one-liner":

find /var/spool/mail -type f -exec sh -c 'for pathname do : >"$pathname"; done' sh {} +

Or, if all mailboxes are immediately beneath /var/spool/mail,

for pathname in /var/spool/mail/*; do
    : >"$pathname"
done

As a "one-liner":

for pathname in /var/spool/mail/*; do : >"$pathname"; done

In both of these variations, the : utility is correctly invoked and the redirection will happen for each found pathname (any regular file in or below the given search path).

Related:

Kusalananda
  • 333,661
  • What's the point of the : anyway? Why not just > "$pathname"? Does the : add anything useful? Is > file not enough on some systems? – terdon Sep 08 '19 at 21:00
  • @terdon That depends a bit on the shell. In zsh, that would be equivalent of cat >"$pathname" and would therefore wait for input. Using : with a redirection is therefore more portable than a "naked" redirection. I also kept the use of : instead of using e.g. true as this was what was used in the question. Also, since the redirection was another issue, you might as well keep using : (as I did) as it's guaranteed to be a built-in utility. – Kusalananda Sep 08 '19 at 21:33
  • @terdon As for GNU truncate, it's non-standard and I don't have it on my system. – Kusalananda Sep 08 '19 at 21:39
  • Nah, the point about zsh had me covered already, thanks. I had assumed that the redirection handling was POSIX and all shells would handle > file as a command to empty a file. First time I've seen a case where bash was saner than zsh (for my taste, at least)! – terdon Sep 09 '19 at 13:39