#/usr/bin/env perl
# Last modified: Sat Aug 24 2024 10:48:44 PM -04:00 [EDT]
#
use File::Which;
use File::Basename;
use File::stat;
use Digest::MD5;
# use Data::Dump qw/dump/;
use warnings;
=head1 Installation
C<chmod 700 perlwitch> - on GNU/Linux and similar *nix-ish systems
=head1 Usage
C<perl perlwitch>
=cut
my @heap = which( 'perl' );
my $trimmed;
my $struct; my $index = 0;
my @versions;
print "We are running [$^X] on $^O which is perl $^Vn";
if (($^O eq 'cygwin') or ($^O eq 'MSWin32')) {
no warnings;
my $pn;
my $i = 0;
for $pn (@heap) {
unless ( $pn =~m/(.exe)$/i ) {
splice (@heap, $i, 1);
} else {
# print "nItem $i Not removed from data: matched $1 :", $pn, qq[n];
$i++
}
}
}
$index = 0;
my $strl = 0; my $s = 0; my $first = 0;
for $s (@heap) {
if (length($s) >= $strl) { $strl = length $s; }
open READPIPE, '-|', $s, '-v' || warn "Call a plumber! Pipe broken on attempted fork!n $!";
while (<READPIPE>) {
if ($_ =~m/This is perl .+(v[.[[:digit:]]+)) /) { push @versions, ($1) }
}
close READPIPE || warn "Got a bad close: $?n";
}
my $fmt = $strl + 6;
for $path (@heap) {
$struct->[$index]->[0] = $path;
$struct->[$index]->[1] = $versions[$index];
my $arro = csum($path);
my $st = stat($path);
my $bytesize = $st->size;
$struct->[$index]->[2] = $bytesize;
my (undef, $dir, undef) = fileparse($path);
$struct->[$index]->[3] = $dir;
$struct->[$index]->[4] = $arro;
$trimmed = $strl - 4;
print sprintf(qq/%-${fmt}s/, $path), $versions[$index], q[ ], $bytesize, q[ ],
q[ ], sprintf(qq/%-${trimmed}s/, $dir), q[ ], sprintf("%36s", $arro), qq[n];
$index++;
}
# print dump $struct; print qq[n];
sub csum {
# we pass in a fqual filename
my $fpath = shift @_;
open( my $fhandl, '<', $fpath ) || warn "Failed open on file $fpath: $!" && return q[];
binmode( $fhandl );
my $check = Digest::MD5->new->addfile($fhandl)->hexdigest;
close( $fhandl );
return $check;
}
__END__
=pod
The purpose of this program is to locate all installations of Perl on a system that are locateable
in the system $PATH. It might be a box you haven't used for while, or perhaps one you
are unfamiliar with. It will list these with a checksum for each, making it easy to see if there
are any duplicates (such as might be found where some symlink sorcery is involved, like linking F</bin> to
F</usr/bin>. The widely used (and wisely used) Debian GNU/Linux now does this, for example.
=head3 Sample output from a complex case: cygwin and MSWin32 perls on the same system
We are running [C:perlperlbinperl.exe] on MSWin32 which is perl v5.32.1
C:ixcygwinbinperl.EXE v5.36.3 12819 C:ixcygwinbin 68ba8b0c3d9bb4859076e938e0cbdafe
C:perlperlbinperl.EXE v5.32.1 39936 C:perlperlbin 3686d8a7e98b82a6452f88fef293ca1a
=head3 TODO
Get script working on cygwin, which is not displaying correctly.
=head2 License
Copyright (c) 2024 Soren Andersen. All rights reserved.
This library is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=cut
enter code here
2
Answers
In a Linux-like environment you should have
type
available.… so you could do a much simpler check,
or resort to running the portion of your script that displays a shorter version number:
As suggested by @Hannu, in Linux-like environments, exploit the
type -a
, perhaps like: