[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