So the following behaviour of unix find just cost me dearly:
> touch foo
> touch bar
> ls
bar foo
> find . -name '*oo' -delete
> ls
bar
> touch baz
> ls
bar baz
> find . -delete -name '*ar'
> ls
> #WHAAAT?
How does this make sense?
So the following behaviour of unix find just cost me dearly:
> touch foo
> touch bar
> ls
bar foo
> find . -name '*oo' -delete
> ls
bar
> touch baz
> ls
bar baz
> find . -delete -name '*ar'
> ls
> #WHAAAT?
How does this make sense?
The command line of find is made from different kinds of options, that are combined to form expressions.
The find
option -delete
is an action.
That means it is executed for each file matched so far.
As first option after the paths, all files are matched... oops!
It is dangerous - but the man page at least has a big warning:
From man find
:
ACTIONS
-delete
Delete files; true if removal succeeded. If the removal failed, an
error message is issued. If -delete fails, find's exit status will
be nonzero (when it eventually exits). Use of -delete automatically
turns on the -depth option.
Warnings: Don't forget that the find command line is evaluated as an
expression, so putting -delete first will make find try to delete
everything below the starting points you specified. When testing a
find command line that you later intend to use with -delete, you
should explicitly specify -depth in order to avoid later surprises.
Because -delete implies -depth, you cannot usefully use -prune and
-delete together.
From further up in man find
:
EXPRESSIONS
The expression is made up of options (which affect overall operation rather
than the processing of a specific file, and always return true), tests
(which return a true or false value), and actions (which have side effects
and return a true or false value), all separated by operators. -and is
assumed where the operator is omitted.
If the expression contains no actions other than -prune, -print is per‐
formed on all files for which the expression is true.
On trying out what a find
command will do:
To see what a command like
find . -name '*ar' -delete
will delete, you can first replace the action -delete
by a more harmless action - like -fls
or -print
:
find . -name '*ar' -print
This will print which files are affected by the action.
In this example, the -print can be left out. In this case, there is not action at all, so the most obvious is added implicitly: -print
. (See the second paragraph of the section "EXPRESSIONS" cited above)
-delete
flag :-)
But is there any reason anyone would ever do find . -delete
rather than rm -rf .
? Or does that just happen to be the way find
parses and processes its arguments?
warning: use -depth when testing stuff you later want to -delete
which you didn't do on your practical side example?
– pqnet
Aug 17 '14 at 17:58
-n
option; The first command should not have any practical use at all, of course; I'll go change it.
– Volker Siegel
Aug 17 '14 at 18:03
In find
argument order matters, a lot.
Arguments can be options, tests and actions. You should typically use options first, then tests, then actions.
Sometimes find
even warns you about a possible bad ordering (for example when you use -maxdepth
after other arguments), but others it seems it doesn't.
What find . -delete -name '*ar'
does is:
What you probably want to do is:
find -name '*ar' -delete
This will, for every file, see if it matches '*ar'
, and only if it satisfies the condition it will delete the file.
Sorry if you found out too late.