How to find a .class file in a bunch of JARs?

O

Owen Jacobson

<pedantic>
'find' is definitely a must in the programmer toolbox, but there's a
little gotcha that I wanted to bring up here;

It's generally better to use the

{grep <pattern> `find <path> -name <filename-pattern> -print`}

Beware of tokenizing issues with this kind of command. Consider:

~/spacecase $ touch a\ b
~/spacecase $ touch c
~/spacecase $ find .
.
./a b
./c

~/spacecase $ touch `find . -print` # using touch to illustrate
problem
~/spacecase $ find .
.
./a
./a b
./b
./c

This is probably a more common issue on Mac OS, where spaces are
normal, than on solaris, where spaces are supported but unusual.

-o
 
M

Mark Space

maaxiim said:
It's generally better to use the

{grep <pattern> `find <path> -name <filename-pattern> -print`}

than

{find <path> -name <filename-pattern> -exec grep \{} \; -print}

for the simple reason that the first form will execute the grep once
for the generated list of names
matched by find, whereas the second form will launch a new instance of
grep for every file, which

That's a good point. I think everybody up-post was using pipes however,
which I think doesn't fork a new command per input line. (Or we would
have been using pipes, if I had remembered to put mine in.)

Just saying...
 
M

Mark Space

Owen said:
This is probably a more common issue on Mac OS, where spaces are
normal, than on solaris, where spaces are supported but unusual.

Also a good point. John did use print0, however, which uses null (0)
delineated strings, rather than print, which uses space delineated
strings. Xargs needs a -0 to interpret null delineated strings, I
assume that was just a typo in his command line.

find <path> -name \*jar -print0 | xargs -0t jar tf | grep ...

I believe this fixes the problem with spaces and all other special
characters in filenames (including newlines). I could be wrong about
that, I've only read the man pages, not tried it...

Xargs can be told via command-line parameters to "batch up" the strings
it receives so that it forks it's command argument less, or it can be
told to run the lines one at a time. This is pretty handy for
controlling how much forking it does. I think the default for xargs is
to buffer everything it can and run the command in one go. It only
spawns multiple commands if it runs out of buffer space.
 
J

John B. Matthews

Mark Space said:
Also a good point. John did use print0, however, which uses null (0)
delineated strings, rather than print, which uses space delineated
strings. Xargs needs a -0 to interpret null delineated strings, I
assume that was just a typo in his command line.

find <path> -name \*jar -print0 | xargs -0t jar tf | grep ...

"Typo" is a generous interpretation, but I got the command wrong! With
my -print0 and xargs -t, jar only sees the first found file. With
-print0 and xargs -0t, jar ignores the list of space-delimited
input-files if it includes more than one jar, at least on my
implementation. An alternative is to feed the results one at a time,
using the -n1 option:

find said:
I believe this fixes the problem with spaces and all other special
characters in filenames (including newlines).

Yes, but maaxiim was right, "...xargs is not so intuitive." :)

[...]
 
M

Mark Space

Harold said:
Except that there's a better, though less well known, alternative:

% find ... -exec grep pattern {} +

Notice the + instead of the \; - this has xargs semantics but without
the parsing flaws (or the non-intuitive nature) of xargs. In other words

Yup, it's right in the GNU man page too. In the ; version "The
specified command is run once for each matched file." but in the +
version "the command line is built by appending each selected file name
at the end; the total number of invocations of the command will be
much less than the number of matched files."

A good find.

There's some differences in the use of {} semantics for each version of
the command, but + seems like it will work in the vast majority of cases.

I think neither version will do exactly what I'd personally like: the
strings command is required for me. Jar doesn't list filenames in
addition to contents on the same line, and my grep doesn't seem to like
binary files.

I think:

find <path> -name \*jar -exec strings -f {} + | egrep ':.*<pattern>'

is still best for me. (Command line not tested.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,815
Messages
2,569,703
Members
45,494
Latest member
KandyFrank

Latest Threads

Top