Can't remember what you called that script you wrote a couple years ago?
Was it
foobar ... or maybe it was
fooBar ...
or was it ... never mind...
% findcmd foo
foo_bar
You know there's some fancy grep installed,
but need to be reminded of its name. Oh, yeah...
% findcmd grep
zgrep
grep
egrep
cgrep
fgrep
findcmd is a script which searches through the directories
in the Unix PATH variable for executable files matching a specified
regular expression. The idea for this script was not mine; I had been
using the Bourne shell script of the same name from the CD from the
ever-excellent book, Unix Power Tools. This script served me
well for years on solaris. After switching to Linux, I would get
intermittent strange behavior. So, I hacked at the sed code
until it seemed to be working again... until we upgraded to the latest
version of Linux. That's when I decided it was time to re-code this in Perl.
While I was at it, I decided to extend its capabilities:
- match against a regular expression, rather than a simple string
- option for case-sensitive matching
- print full directory path, or just the command name
Here is the code:
#!/usr/bin/env perl
use warnings;
use strict;
use Getopt::Long;
use Pod::Usage;
my $print_path;
my $re;
parse_args();
my @dirs = split /:/, $ENV{PATH};
for my $dirname (@dirs) {
if (-d $dirname) {
if (opendir my $DIR, $dirname) {
my @xfiles =
grep { -x "$dirname/$_" } # choose only executable
+files
grep { !-d "$dirname/$_" } # reject directories
grep { /$re/ } # pattern match
readdir $DIR;
closedir $DIR;
for (@xfiles) {
if ($print_path) {
print "$dirname/$_\n";
}
else {
print "$_\n";
}
}
}
}
}
exit;
sub parse_args {
my ($help, $sens);
GetOptions(
'sens' => \$sens,
'path' => \$print_path,
'help' => \$help
) or pod2usage();
$help and pod2usage(-verbose => 2);
if (@ARGV) {
my $pat = shift @ARGV;
$re = ($sens) ? qr/$pat/ : qr/$pat/i;
}
else {
pod2usage('Error: regex required.');
}
@ARGV and pod2usage("Error: unexpected args: @ARGV");
}
=head1 NAME
findcmd
=head1 SYNOPSIS
findcmd [options] regex
Options:
-help Verbose help
-path Print out full directory paths also
-sens Case-sensitive [default is case-insensitive]
=head1 DESCRIPTION
Search through the directories in the Unix PATH variable
for executable files matching a specified regular expression.
The names of all the commands which match will be printed to STDOUT.
This is based on the I<findcmd> script from the CD that comes with
the I<Unix Power Tools> book.
It is important to note that neither aliases nor shell built-ins
(I<cd>, I<which>, etc.) will be printed since neither is found
in directories in the PATH variable.
Any directories listed in the PATH variable which do not exist
or are not readable will be silently ignored.
Duplicate directories will not be removed.
=head1 ARGUMENTS
=over 4
=item regex
A regular expression is required. The regex may be a simple string,
such as C<foo>, or it may be a more complicated expression, such as
C<^foo.*bar\d>. The regex syntax is Perl; it should not be confused
with shell wilcard syntax or the syntax for other common Unix utilitie
+s,
such as I<sed> or I<grep>. It is best to quote the regex to prevent
interaction with the shell.
=back
=head1 OPTIONS
All options can be abbreviated.
=over 4
=item sens
By default, the regular expression is case-insensitive. So, if the inp
+ut
regex is C<foo>, it will match C<foo> as well as C<FOO> and C<Foo>, et
+c.
To use case-sensitive, use the C<-sens> option.
findcmd -sens foo
=item path
By default, only the command name is printed. To instead print the ful
+l
directory path to the command, use the C<-path> option.
findcmd -path foo
=item help
Show this verbose usage information.
=back
=head1 EXAMPLES
Match a command name exactly (C<gnuplot>), and print
the full directory path. This provides the same functionality as
the I<whereiz> utility from I<Unix Power Tools>.
findcmd -sens -path '^gnuplot$'
Find all executable files in all path directories:
findcmd .
Find commands which begin with a dot:
findcmd '^\.'
Find commands with strange characters (not word, period, plus, dash):
findcmd '[^\w.+-]'
Find commands with a literal, case-sensitive "-s":
findcmd -sens '\-s'
=head1 SEE ALSO
Refer to the following book:
Unix Power Tools
2nd Edition
Jerry Peek, Tim O'Reilly and Mike Loukides
O'Reilly & Associates, Inc.
=cut
Constructive criticism, suggestions for improvements and bug reports are
welcome.