Sometimes it is not enough to search for files on your hard drive, but you want to search for files inside the file archives. One good example is when you have to find a particular java class by name inside some jar file. Now, we do not know which jar file contains this particular class, and there are several jar files in several folders.
First, let us find and list all the jar files we have inside a particular directory. To do that we can use the find command.
$ find myfolder/ -name *.jar
This command will list all the jar files inside the directory named myfolder and its sub directories. Now, we have to list the contents of each of these jar files and search for the particular class name that we are interested in. In order to list all the contents of a particular jar file without exploding them on to the hard disk, we can use the jar command
$ jar tf myjarfile.jar
This will print out all the files inside the jar file myjarfile.jar. Now, we do a search over the file names using grep. For this we are going to pipe the output of the jar command above as the input of the grep command
$ jar tf myjarfile.jar | grep -i ClassName
Here we are doing a case insensitive (the -i option) search over the output of the jar command, which is all the file names inside the jar. Now we have to do this for each of the jar files that we found in the directory. In order to do a loop over all the jar files, we will use the for loop which is provided by the unix shell. The generic syntax of the for loop is
for VARIABLE in 1 2 3 4 5 .. N
So, in the case putting the previous commands together, we have the for loop as
for x in $(find myfolder/ -name *.jar);
jar tf $x | grep -i ClassName;
This will find all the files inside all the jar files which match the name ClassName. So far so good, but it is pain to type it all out every time we have to do a class search. So, we will make it into a shell script and save it somewhere in the path that we can reuse all the time. So, copy the above into a executable file in your path.
But, it still is not as useful as the class name and the folder name are hard wired inside the script. We need to parametrize it so that we can use it for different file names. We will also print out the path to the jar file which contains the class, so that it easy to find. Here is the script which does it …
$ for x in $(find "$2" -name "*.$1"); do jar tf "$x" grep -i "$3" && echo "****** Matched Archive :$x"; done
The first argument is actually the extension of the archive files that we want to match against. In this example it will be jar. The second argument is the name of the directory that we want to search under. And the third argument is the class name or a part of the class name that we are searching for.
Well, we usually search for a class when we get a ClassNotFoundException in a java application which prints out the package and name of the class which is not found. This usually uses the dot (.) in the full class name rather than the forward slash (/) which the jar command spits out. So, if we are to search for the complete class path, instead of just the class name, then we will have to manually change every dot (.) to a slash (/) while using this script. So, lets’ go ahead and change the slash (/) that the jar command spits out to dots (.) so that it will exactly match the output of the java exception. This just makes it a lot easier to copy and paste the arguments.
We will use the sed command to substitute all the slash (/) to dot (.). Here is the final version of the command which you can directly copy on to the script file (call it findin or a name of your choice).
for x in $(find "$2" -name "*.$1"); do jar tf "$x" | sed 's/\//\./g'|grep -i "$3" && echo "****** Matched Archive :$x"; done
In order to use this command, assuming you have saved the script file with a name findin.
$ findin jar . DomUtils
This command will search in all jar files inside the current directory for a class named DomUtils.
$ findin jar lib org.apache.tools.ant.util.DOMUtils
This will match the class name along with the package name in all the jar files inside the folder named lib. Now you know that jar file is actually just a zip file, right ? That means we can use this command to search inside the zip archives as well.
$ findin zip . maximize.png
Now, that will find a file named maximize.png inside all the zip files in your current folder.
An easier way to search for class names inside archive files is to use the grep command directly.
$ grep -ir SingleThreadModel .
This will print out the names of the archive files which contains a file with the matching name. The advantage of the above script is that it will print out the entire file name when it is matched rather than just the name of the matched archive.