0

My use case is I want to search a collection of JARs for a specific class file. More specifically, I want to search recursively within a directory for all *.jar files, then list their contents, looking for a specific class file.

So this is what I have so far:

find . -name *.jar -type f -exec echo {} \; -exec jar tf {} \;

This will list the contents of all JAR files found recursively. I want to put a grep within the seconed exec because I want the second exec to only print the contents of the JAR that grep matches.

If I just put a pipe and pipe it all to grep afterward, like:

find . -name *.jar -type f -exec echo {} \; -exec jar tf {} \; | grep $CLASSNAME

Then I lose the output of the first exec, which tells me where the class file is (the name of JAR file is likely to not match the class file name).

So if there was a way for the exec to run two commands, like:

-exec "jar tf {} | grep $CLASSNAME" \;

Then this would work. Using a grep $(...) in the exec command wouldn't work because I need the {} from the find to take the place of the file that was found.

Is this possible? (Also I am open to other ways of doing this, but the command line is preferred.)

Michael Plautz
  • 3,578
  • 4
  • 27
  • 40

2 Answers2

0

i find it difficult to execute multiple commands within find-exec, so i usually only grab the results with find and loop around the results.

maybe something like this might help?

find . -type f -name *.jar | while read jarfile; do echo $jarfile; jar tf $jarfile; done

yftse
  • 183
  • 6
0

I figured it out - still using "one" command. What I was looking for was actually answered in the question How to use pipe within -exec in find. What I have to do is use a shell command with my exec. This ends up making the command look like:

 find . -name *.jar -type f -exec echo {} \; -exec sh -c "jar tf {} | grep --color $CLASSNAME" \;

The --color will help the final result to stick out while the command is recursively listing all JAR files.

A couple points:

  • This assumes I have a $CLASSNAME set. The class name has to appear as it would in a JAR, not within a Java package. So com.ibm.json.java.JSONObject would become com/ibm/json/java/JSONObject.class.
  • This requires a JDK - that is where we get the jar command. The JDK must be accessible on the system path. If you have a JDK that is not on the system path, you can set an environment variable, such as JAR to point to the jar executable. I am running this from cygwin, so it turns out my jar installation is within the "Program Files" directory. The presence of a space breaks this, so I have to add these two commands:

    export JAR=/cygdrive/c/Program\ Files/Java/jdk1.8.0_65/bin/jar
    find . -name *.jar -type f -exec echo {} \; -exec sh -c "\"$JAR\" tf {} | grep --color $CLASSNAME" \;
    

    The $JAR in the shell command must be escaped otherwise the terminal will not know what to do with the space in "Program Files".

Community
  • 1
  • 1
Michael Plautz
  • 3,578
  • 4
  • 27
  • 40