I was trying to find the JAR containing a Java Class. JARs are in zip format.
My first attempt was:
$ find -name "*3.0.6.RELEASE.jar" | xargs -l1 unzip -l \
| grep stereotype.Controller
554 2011-08-18 16:49 org/springframework/stereotype/Controller.class
554 2011-08-18 16:49 org/springframework/stereotype/Controller.class
I found the class, but I still don't know which of the 25 matching files contains it (there are two JARs containing it). So I thought to use tee
in the middle to output the file names.
$ find -name "*3.0.6.RELEASE.jar" | tee - | xargs -l1 unzip -l \
| grep stereotype.Controller
554 2011-08-18 16:49 org/springframework/stereotype/Controller.class
554 2011-08-18 16:49 org/springframework/stereotype/Controller.class
554 2011-08-18 16:49 org/springframework/stereotype/Controller.class
554 2011-08-18 16:49 org/springframework/stereotype/Controller.class
I'd have expected to see a filename followed by the Controller.class for matching files and by the next filename for non mathing. However, now that I think about it, standard output just flows in the pipe and gets processed by xargs, so it makes sense.
I could use standard error, but then, I suppose, that since the processes are running concurrently, I could have timing issues that make the output not in the order I would hope to see.
So there must be a better way to approach this problem, anyone has ideas?
UPDATE: While waiting for an answer, I wrote a horrible Perl one liner that does the trick, but looking forward to see more elegant solutions.
$ find -name "*3.0.6.RELEASE.jar" | perl -e 'while (<>) { \
$file=$_; @class=`unzip -l $_`; foreach (@class) { \
if (/stereotype.Controller/) {print "$file $_";} } }'
Output:
./spring-context/3.0.6.RELEASE/spring-context-3.0.6.RELEASE.jar
554 2011-08-18 16:49 org/springframework/stereotype/Controller.class
./org.springframework.context/3.0.6.RELEASE/org.springframework.context-3.0.6.RELEASE.jar
554 2011-08-18 16:49 org/springframework/stereotype/Controller.class
Best Answer
Try this:
There's no need for
xargs
or afor
loop here. All can be done with a singlefind
. If you want to also output the content that got grepped, just remove the-q
option togrep
- but notice that thegrep
matches will appear before each file name. For a clearer output, you can add-exec echo \;
at the very end.