Looking for a Java class in a set of JARs with find, unzip, grep
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]*
Related videos on Youtube
Lorenzo Pistone
Updated on September 18, 2022Comments
-
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 over 12 yearsThank 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 over 12 yearsI 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 over 12 yearsThat 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
withoutjar tvf
. The first echo can be removed. I just added it so that you can quickly browse through the jar files, ourfind
command identifies. -
jaypal singh over 12 yearsAdded a one-liner. Hope that helps!
-
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 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 ;)