I tried some of those Unix commands, but they errored out for various reasons. Here's a Perl script I wrote. It's specifically designed to run on Cygwin using the Cygwin version of Perl.
#!/bin/perl
# This program searches recursively for a given class in .jar files contained in or below
# directories given as command-line arguments. See subroutine printUsageAndExit for details,
# or just run it with -h command-line argument.
#
# It is specfically designed to run on Windows via Cygwin, with Cygwin's version of Perl,
# though it could easily be modified to run elsewhere.
use strict;
use File::Find;
use Getopt::Std;
sub processCommandLineArguments (\$\@);
sub checkCommandLineArguments;
my $className;
my @startingDirectories;
&checkCommandLineArguments;
&processCommandLineArguments (\$className, \@startingDirectories );
my %options;
$options{wanted} = \&processFoundFile;
$options{no_chdir} = 1;
$options{follow} = 1; # So that $File::Find::fullname will be populated.
$options{follow_skip} = 2; # So it won't die if it encounters the same thing twice.
&find ( \%options, @startingDirectories ); # find comes from "use File::Find".
sub processFoundFile{
# This routine is called by File::Find.
#
# $File::Find::dir is the current directory name,
# $_ is the current filename within that directory
# $File::Find::name is the complete pathname to the file.
my $jarFileName = $_;
return unless /\.jar$/;
my $fullFileName = $File::Find::fullname; # set by File::Find only when $options{follow} == 1
# Windowize filename:
$fullFileName = qx{cygpath --windows $fullFileName 2>&1};
chomp $fullFileName;
$fullFileName = '"' . $fullFileName . '"';
my @results = qx{jar -tf $fullFileName 2>&1};
local $/ = "\r\n"; # So that this Unix-based Perl can read output from Windows based jar command.
for my $result ( @results )
{
chomp $result;
if ( $result =~ /\b(\w+)\.((java)|(class))$/ )
{
my $classNameFound = $1;
if ($classNameFound eq $className)
{
print $jarFileName, "\n";
return;
}
}
}
}
sub processCommandLineArguments (\$\@){
my $refClassName = shift;
my $refStartingDirectories = shift;
$$refClassName = '';
# parse @ARGV
while (@ARGV){
my $arg = shift @ARGV;
if ($arg =~ /\Q-c/){
$$refClassName = shift @ARGV;
}elsif ($arg =~ /\Q-directories/){
while ($ARGV[0] =~ m{^/(\w+/?)+\b}){
my $directory = shift @ARGV;
die "Can't find $directory $!" if ! -e $directory;
push @$refStartingDirectories, $directory;
}
}
}
die "Must give -c class_name argument $!" if $$refClassName eq "";
push @$refStartingDirectories, '.' if scalar (@$refStartingDirectories ) == 0;
}
sub checkCommandLineArguments
{
{
# getopts butchers @ARGV, so have to use it on a local version.
local @ARGV = @ARGV;
our $opt_h;
&getopts('hc'); # Have to specify all options given or getopts will die.
&printUsageAndExit if $opt_h;
}
my $className;
{
# getopts butchers @ARGV, so have to use it on a local version.
local @ARGV = @ARGV;
while (@ARGV){
my $arg = shift @ARGV;
if ($arg =~ /\Q-c/){
$className = shift @ARGV;
&printUsageAndExit if $className =~ /^\s*$/ ;
return;
}
}
}
&printUsageAndExit;
}
sub printUsageAndExit
{
print "Usage:\n\n";
print "$0 -c class_name_to_search_for [ -directories startingDirectory1 startingDirectory2 ...]\n\n";
print "Example:\n\n";
print "findJarContainingClass.pl -c ApplicationMaster -directories /home/lylez/Hadoop/hadoop-2.x/hadoop-2.2.0/share/hadoop/yarn/sources /home/lylez/Hadoop/hadoop-2.x/hadoop-2.2.0/share/hadoop/yarn\n\n";
exit;
}