skip to Main Content
#/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


  1. 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 "nn[ --- $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.
    
    $
    
    Login or Signup to reply.
  2. As suggested by @Hannu, in Linux-like environments, exploit the type -a, perhaps like:

    $ cat showperls
    #!/usr/bin/env bash
    for which in $(type -a perl|perl -pe 's/perl is //')
    do
        printf "%s %sn" $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';
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search