Looking for a Java class in a set of JARs with find, unzip, grep

14,763

Solution 1

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.

Solution 2

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

Solution 3

An old thread but this looks like a cleaner way to get this done: http://alumnus.caltech.edu/~leif/opensource/cpcheck/CpCheckApp.html

Windows:
    cpcheck [flags] classpath [classpath]*
Unix:
    ./cpcheck.sh [flags] classpath [classpath]*
Java:
    java -jar cpcheck.jar [flags] classpath [classpath]*
Share:
14,763

Related videos on Youtube

Lorenzo Pistone
Author by

Lorenzo Pistone

Updated on September 18, 2022

Comments

  • Lorenzo Pistone
    Lorenzo Pistone over 1 year

    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
    
  • Lorenzo Pistone
    Lorenzo Pistone over 12 years
    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
  • Lorenzo Pistone
    Lorenzo Pistone over 12 years
    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.
  • jaypal singh
    jaypal singh over 12 years
    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.
  • jaypal singh
    jaypal singh over 12 years
    Added a one-liner. Hope that helps!
  • jaypal singh
    jaypal singh over 12 years
    +1, I always wanted to see how buffered items from find can be passed on to two items. Good stuff!!
  • Moreaki
    Moreaki about 10 years
    @jaypalsingh if you really found the printing order sad, maybe a slight variation of your code could suffice to render you happy again: SEARCH="Logger"; time while read jar _; do resultset=$(grep "${SEARCH}.*.class" < <(tar tf $jar)); if [ ${#resultset} -gt 0 ]; then printf "%s\n%s\n" "--> Found $SEARCH in $jar:" "$resultset"; fi; resultset=""; done < <(find . -type f -name "*.jar"). It's even mighty fast ;)