Script day – find Java jar files that contain a Java class

From time to time I need to work with a Java program or library that requires some import which I’m not familiar with. Its often very easy to just copy the fully qualified class name and search for it on Google which usually helps identify the product that contains this class.

But if you know that you have this class on your system somewhere, and you are just not sure which jar file you need to add to your project for it to compile – this script will come in handy:

The script below generates a list of jar files, then look for the specified pattern (using grep) in each jar file’s directory and prints each jar file that contains a class to match the pattern. The script has two modes of operation – the default mode uses the operating system’s locate implementation to look for all jar files in the file system – this is very fast, but the list may not be up to date and contain files that were deleted and/or missing new files that were recently added. The second mode, triggered by the ‘-j‘ command line option uses find to get the list of all jar files under the system’s Java libraries directory (/usr/share/java) – while this works directly on the file system, it is also relatively fast because we limit the search to a rather small directory tree and doesn’t suffer from locate‘s dependency on a database which may not be up to date.

The script:

#!/bin/sh

ONLY_JAVA_DIR=

function getJars() {
    if [ -n "$ONLY_JAVA_DIR" ]; then
        find /usr/share/java/ -name '*.jar' | egrep '[^]0-9]\.jar$'
    else
        locate 'jar' | egrep '[^]0-9]\.jar$'
    fi
}

class=

while [ -n "$1" ]; do
    case "$1" in
        -j)
            ONLY_JAVA_DIR="yes"
            ;;
        *)
            class="$1"
            ;;
    esac
    shift
done
export IFS="
"

for file in $(getJars); do
    [ -f "$file" ] && (unzip -l "$file" 2>/dev/null | grep -q $class) && echo $file;
done

I often just write this script down as a one liner (it is simple as replacing getJars with a wildcard match of your choice and packing the for loop into a single line), but when using the locate mode, its common to encounter directories and files with spaces in their name and this usually causes bash to break horribly – the default record separator which is used by the for command matches spaces and breaks a single file path with spaces inside into two or more different paths. To fix this we change the value of IFS (the bash record separator definition) locally to only include new lines (hence the weird assignment) and we make sure that getJars() generates a list of files where each file path is on a line by its own.

Leave a Reply