[PLUG] bash / find question (Solution inside)

Dean S. Messing deanm at sharplabs.com
Sun Sep 15 23:54:04 UTC 2002


This does not appear to have made it to the list. Let's try again.

======

Thanks Rogan for trying to help.

Rogan Creswick wrote:
 :: Dean S. Messing wrote:
 :: > To be specific suppose I want, on each instance of the command
 :: > w/in the -exec block,  to output something to a file
 :: > named {}.foo.
 :: 
 :: find will only replace the first occurrence of {} with
 :: the "found" file,

In fact, according to the "find" man page:

       -exec command ;
              Execute command; true if 0 status is returned.  All
              following arguments to find are taken to  be  argu­
              ments  to  the command until an argument consisting
              of `;' is encountered.  The string `{}' is replaced
              by the current file name being processed everywhere
              it occurs in the arguments to the command, not just
              in arguments where it is alone, as in some versions
              of find.  Both of these constructions might need to
              be  escaped  (with a `\') or quoted to protect them
              from expansion by the shell.  The command  is  exe­
              cuted in the starting directory.

the salient phrase being "everywhere it occurs" which suggests
that {} can occur more than once.

To disprove your statement simply try:

   find DIR -type f -exec echo {} ... {} \;

(where DIR is your favourite small directory) and you will get what
you expect.

 :: so you have to write a script of sorts:
<script snip>

Yep, I could have written a script. I thought of that.  But being the
tenacious (some would say anal) person that I am, when it comes to
computers, I believed that it should be possible to do what I wanted.
And so finding a solution to the problem became a task unto itself
(I work a lot of overtime to make up the time I waste solving these
idiotic questions I have :-).

 :: I imagine something like this would work also:
 :: 
 :: $ find $DIR -type f -exec FILE={} && $COMMAND $ARGS $FILE > $FILE.foo \;

Nope, it won't, though I'm not completely sure why.  I believe that it
is because `-exec' is expecting a _command_ (which a shell assignment
is not). So it goes ahead and tries to execute the string 'FILE={}'
and, of course, finds "No such file or directory".  Try doing:

   find DIR -type f -exec FILE={} \;

 :: -Rogan
 :: 
 :: > How do I do this?  I've tried the obvious (but wrong)
 :: > 
 :: >   find $DIR -type f -exec $COMMAND $ARGS {} > {}.foo \;
 :: > 
 :: > I've tried escaping the redirection thus:
 :: > 
 :: >   find $DIR -type f -exec $COMMAND $ARGS {} \> {}.foo \;
 :: > 
 :: > I've tried also (and only) escaping the  {}  (which
 :: > I normally never escape).
 :: > 
 :: > And I've tried double quoting  various substrings of
 :: > 
 :: >          $COMMAND $ARGS {} > {}.foo
 :: > 
 :: > Now I'm going to try asking you.
 :: > 
 :: > What is the general form of the stuff following -exec
 :: > when you have pipes, multiple cammands &c.

After a further hour of screwing around with every possible permutation
of quoting and escaping I finally discovered how to do what I want.

And in good unix fashion it is in the man page, right in front
of my eyes.  I just had to read it twelve times to "get it".
In Unix, as in Mathematics, _every word_ in a man page is important. 
Ignore a word at your own risk.

Observe that it says:

          The string `{}' is replaced by the current file name
          being processed everywhere it occurs in the arguments
          to the command ...

The salient phrase is "in the arguments to the command".

If the -exec string is:  -exec cat /dev/null > {} \;

then {} is _not_ an argument of the command `cat' since
the arguments stop at `>' which is not passwd to cat but
rather processed by the shell.  This is also why I've never
gotten pipes to work.

The solution is to "fake the systyem out" by writing:


     -exec sh -c "cat /dev/null > {}" \;

Now everything to the right of `sh' and to the left of `\;' is
"an argument" and so it all works.  So do pipes!

Dean




More information about the PLUG mailing list