[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: GNU find: "print0" and "-type" arguments



Martin Steigerwald wrote:
> Bob Proulx:
> > Martin Steigerwald wrote:
> > > martin@merkaba:~/Zeit/find-Test> find \( -type d -print \) -o \(
> > > -name "file" -printf  "%s %p" \) -o \( -name "anotherfile" -print0
> > > \) .
> > > ./anotherfile./dir
> > > 0 ./file%
> > > martin@merkaba:~/Zeit/find-Test>
> > 
> > It is inconsistent to mix -print0 with -print and -printf.  Just use
> > one or the other consistently.
> 
> Well I wanted to know which action find uses in each case, had I used -
> print in all the case, I could not tell a difference.

In that case I suggest using -printf throughout.  Put an identifying
remark in the printf format string associated with that action.
For example:

  $ find . -type d -printf "%p due to -type d\n" -o -name file -printf "%p due to -name file\n" -o -name anotherfile -printf "%p due to -name anotherfile\n"
  . due to -type d
  ./file due to -name file
  ./anotherfile due to -name anotherfile
  ./dir due to -type d

How is that?

> Yes, my understanding was find would be doing one run for each action, 
> thus first dearch for »-type d« and print it, then search again for »-name 
> "file« and print it and so on, but then it needed to scan the directory 
> three times instead of just once.

Correct.

> So I teach people this stuff and upto now didn´t think deeply about the 
> exact order. I knew that the action follows the search criteria, but I 
> never thought about the case with mutiple actions on one line.

The argument list is a small program that is interpreted for each file
entry.  You write the argument list as you would write a program.

> So another interesting use case:
> 
> martin@merkaba:~/Zeit/find-Test> find -printf "%s %p\n" -print -exec ls -ld {} \; -delete

My first thought was "ew.." due to the "-delete" being mixed in with
the recursive operation and without any restriction.  That is
basically the same as 'rm -rf .' and feels very dangerous to me.
(Which of course won't delete '.' but will delete everything else
below it.)  It could delete a lot of files very quickly!

> martin@merkaba:~/Zeit/find-Test> find
> .
> martin@merkaba:~/Zeit/find-Test>

Yes.

> So find execute all four actions for each search result and all the 
> results are gone then.

Yes.  Each action returned true.  The print actions always return
true.  The exec action will pass back the exit code of the process.
If any return code is not true then the processing left to right over
the argument list will stop.

> Nice ;)

As long as that is what you wanted!  :-)

> All results except for the current directory »find-Test«, which the -
> delete option didn´t touch. The manpage is not clear. It writes about 
> deleting files, but it »-delete« also removes empty directories. And it 
> leaves the current directory alone although it is in the search results.

Of course '.' won't be removed since it can't be.  This is the same as
with 'rm -rf .' too.  (However I see that recent 'rm' doesn't allow
that use nad prints an error and exits.  Probably a good safe behavior.)

I personally only use -delete with a specific restriction such as with
a -type f or -name file1 or other type of specific targeting.  I avoid
having find recursively walk down directories and also have -delete
recursively walk down directories too.

It also feels wrong that it is recursively deleting directories that
find will in the future recurse down.  Due to buffering I think this
won't be visible with small directories.  But with large directories I
believe (but did not test) that it will produce an error when find
tries to read a directory that has been previously deleted in passing.

Using -delete automatically enables -depth.  Therefore the order of
file processing will be the order find would use with 'find . -depth'.
This is done to avoid trying to delete a directory that still contains
files.  Using -depth gives the possibility that the directory will be
emptied first.

  $ mkdir dir
  $ touch dir/otherfile
  $ find . -type d -print -delete
  ./dir
  find: cannot delete `./dir': Directory not empty
  .

  $ find . -print
  .
  ./dir
  ./dir/otherfile

  $ find . -depth -print
  ./dir/otherfile
  ./dir
  .

Bob

Attachment: signature.asc
Description: Digital signature


Reply to: