#/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 $^V\n";
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:\perl\perl\bin\perl.exe] on MSWin32 which is perl v5.32.1
C:\ix\cygwin\bin\perl.EXE v5.36.3 12819 C:\ix\cygwin\bin\ 68ba8b0c3d9bb4859076e938e0cbdafe
C:\perl\perl\bin\perl.EXE v5.32.1 39936 C:\perl\perl\bin\ 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
3 Answers
In a Linux-like environment you should have type available.
$ type -a perl
perl is /usr/bin/perl
perl is /bin/perl
... so you could do a much simpler check,
or resort to running the portion of your script that displays a shorter version number:
$ type -a perl | cut -d' ' -f3 | while read name ;\
do echo -e "\n\n[ --- $name --- ]"; $name --version ;done
[ --- /usr/bin/perl --- ]
This is perl 5, version 38, subversion 2 (v5.38.2) built for x86_64-linux-gnu-thread-multi
(with 44 registered patches, see perl -V for more detail)
Copyright 1987-2023, Larry Wall
Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.
Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl". If you have access to the
Internet, point your browser at https://www.perl.org/, the Perl Home Page.
[ --- /bin/perl --- ]
This is perl 5, version 38, subversion 2 (v5.38.2) built for x86_64-linux-gnu-thread-multi
(with 44 registered patches, see perl -V for more detail)
Copyright 1987-2023, Larry Wall
Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.
Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl". If you have access to the
Internet, point your browser at https://www.perl.org/, the Perl Home Page.
$
1 Comment
As suggested by @Hannu, in Linux-like environments, exploit the type -a, perhaps like:
$ cat showperls
#!/usr/bin/env bash
for which in $(type -pa perl|cut -d" " -f3)
do
printf "%s %s\n" $which, $($which -V:version)
done
$ ./showperls /Users/jrf/perl5/perlbrew/perls/perl-5.40.0/bin/perl, version='5.40.0'; /usr/bin/perl, version='5.34.1';
The -p option of type:
...either returns the name of the disk file that would be executed if name were specified as a command name, or nothing if ''type -t name'' would not return file. See https://linux.die.net/man/1/bash
1 Comment
I've posted the final, debugged version of perlwitch on github:
This code is now working properly on Gnu/Linux, MSWindows, and Cygwin in Windows.
#/usr/bin/env perl
# Last modified: Thu Aug 29 2024 05:22:45 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
(optional) C<chmod 700 perlwitch> - on GNU/Linux and similar *nix-ish systems
=head1 SYNOPSIS
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 $^V\n";
print 'All perls installed to the system $PATH:'."\n";
if (($^O eq 'cygwin') or ($^O eq 'MSWin32'))
{
no warnings;
my $pn; my @selected;
for $pn (@heap) {
if ( $pn =~m/(\.exe)$/i ) {
push(@selected, $pn);
}
}
@heap = @selected; # overwrite instance array
}
$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++;
}
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
=head1 DESCRIPTION
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 ERRONIOUS output from a complex case: cygwin and MSWin32 perls on the same system
$ perl perlwitch
/usr/bin/perl v5.36.3 12819 /usr/bin/ 68ba8b0c3d9bb4859076e938e0cbdafe
/usr/bin/perl.exe v5.36.3 12819 /usr/bin/ 68ba8b0c3d9bb4859076e938e0cbdafe
/cygdrive/c/perl/perl/bin/perl v5.32.1 39936 /cygdrive/c/perl/perl/bin/ 3686d8a7e98b82a6452f88fef293ca1a
/cygdrive/c/perl/perl/bin/perl.exe v5.32.1 39936 /cygdrive/c/perl/perl/bin/ 3686d8a7e98b82a6452f88fef293ca1a
=head1 AUTHOR
Soren Andersen
=head1 BUGS / TODO
Get script working on cygwin, which is not displaying correctly.
=head1 COPYRIGHT
Copyright (c) 2024 Soren Andersen. All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
=cut
which( 'perl' ), which, I guess, returns an array of all executables namedperlin your PATH (iswhicha standard function in Perl?). This means that you don't look for perl installed in your file system, but those that are also in your PATH. Is this really what you want to do?