Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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
share|improve this question
add comment

2 Answers

up vote 4 down vote accepted

Try this:

find -name "*3.0.6.RELEASE.jar" -exec sh -c 'unzip -l "{}" | grep -q stereotype.Controller' \; -print

There's no need for xargs or a for loop here. All can be done with a single find. If you want to also output the content that got grepped, just remove the -q option to grep - but notice that the grep matches will appear before each file name. For a clearer output, you can add -exec echo \; at the very end.

share|improve this answer
    
excellent, thank you –  stivlo Nov 28 '11 at 13:17
    
+1, I always wanted to see how buffered items from find can be passed on to two items. Good stuff!! –  JS웃 Nov 28 '11 at 16:14
add comment

In your 1st one-liner, in the grep command add -H option. That is to include the file name in the result.

Here is from the man-page -

-H, --with-filename
              Print the filename for each match.</strike>

UPDATE

May be this script will help out -

#!/bin/bash

searchSTR="YOUR SEARCH"

for i in `find . -name "*jar"`
do
  echo "Scanning $i ..."
  jar tvf $i | grep $searchSTR > /dev/null
  if [ $? == 0 ]
  then
    echo "==> Found \"$searchSTR\" in $i"
  fi
done

One-Liner:

for i in `find . -name "*.jar"`; do jar tvf $i | grep "search pattern" && echo $i ; done

The only sad part is the name of the jar file will be displayed after the grep content

share|improve this answer
1  
Thank you, but doesn't help, since it's already processed with unzip, is too late to get the file name. Here is the output: (standard input): 554 2011-08-18 16:49 org/springframework/stereotype/Controller.class –  stivlo Nov 28 '11 at 8:10
    
I saw the update, it's conceptually similar to my Perl, I think I will probably change it to accept a parameter for the search string, look into my .m2 Maven repo, and save the script (well formatted and commented instead of the one liner) in /usr/local/bin/searchJar. I will do it in the next few days, unless someone will tell me that there is a simpler solution. –  stivlo Nov 28 '11 at 9:15
    
That sounds right, you can make this into a one-liner but because we need to look inside the jar file, I don't really know a way of doing grep without jar tvf. The first echo can be removed. I just added it so that you can quickly browse through the jar files, our find command identifies. –  JS웃 Nov 28 '11 at 9:19
    
Added a one-liner. Hope that helps! –  JS웃 Nov 28 '11 at 9:29
    
Thanks Jaypal, I've +1 for your multiple solutions. –  stivlo Nov 28 '11 at 9:37
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.