views:

145

answers:

4

Due to pressure from outside our group, we have to port over one hundred Perl scripts from Sparc to x86. This means changing dozens of shebang lines from #!/home/Perl/bin/perl -w to something else, which is a real pain. What is good way to do this (I can't find anything on Lycos)?

Also what happens when we're forced to move from x86 to something else (like Cray, I suppose)? Is there some way to "future-proof"?

+5  A: 

Perl is cross-platform. Unless your code makes use of XS compiled code or system-specific paths, facilities, etc., you should be fine.

You have two options:

  1. Don't use shebang lines (perl yourscript.pl).
  2. find . -name '*pl' | xargs sed 's/#!\/home\/Perl\/bin\/perl -w/#!\/usr\/bin\/env perl/

In any case, the shebang line has nothing to do with the hardware platform you're running, and all with the shell you're running on.

Pedro Silva
Sorry. I should have state my shell. I am using `tcsh` is this my problem?
Ariel Bold
Nope, `tcsh` supports shebang lines. If your systems have `env` installed, you just need to change your scripts with option 2, above.
Pedro Silva
I cannot guarantee that the systems running our scripts have `env` installed.
Ariel Bold
+10  A: 

This is one reason many people advocate using #!/usr/bin/env perl instead of #!/usr/bin/perl:

Chas. Owens
How does this make my scripts portable?
Ariel Bold
They will run on whichever "perl" executable the system finds, via `/usr/bin/env`...
mfontani
@Ariel: More specifically, using `#!/usr/bin/env perl` will cause the program to be run using the first `perl` binary found in the controlling user's `PATH`. Note that if, by "x86" you mean "Windows", this isn't relevant anyhow, since Windows goes by the file extension and completely ignores the `#!` line.
Dave Sherohman
I use this script for Perl shebang headers:http://www.win.tue.nl/~rp/bin/envperl
reinierpost
+4  A: 

Changing the shebang lines en masse ain't so bad:

#! /usr/bin/perl

use warnings;
use strict;

use File::Find;

sub usage { "Usage: $0 dir ..\n" }

my @todo;
sub has_perl_shebang {
  return unless -f;
  open my $fh, "<", $_ or warn "$0: open $File::Find::name: $!", return;
  push @todo => $File::Find::name
    if (scalar(<$fh>) || "") =~ /\A#!.*\bperl/i;
}

die usage unless @ARGV;
find \&has_perl_shebang => @ARGV;

local($^I,@ARGV) = ("",@todo);
while (<>) {
  s[ ^ (\#!.*) $ ][#! /usr/bin/env perl]x
    if $. == 1;
  print;
}
continue {
  close ARGV if eof;
}

Depending on what you have, the s/// may need to be a little smarter to handle switches such as -T that must be on the shebang line.

Add a dry-run option with a few changes, plus an interesting use of redo:

my $dryrun;
{
  die usage unless @ARGV;
  $dryrun = shift @ARGV, redo if $ARGV[0] eq "-n";
}

find \&has_perl_shebang => @ARGV;
if ($dryrun) {
  warn "$0: $_\n" for @todo;
  exit 1;
}
Greg Bacon
Very nice!Do I run this on Sparc or X86? I guess X86 will be faster.
Ariel Bold
@Ariel Thanks! You'd run this on the x86 (destination) side because it fixes the shebang lines in-place.
Greg Bacon
+1  A: 

Another alternative (might be simpler though I would hesitate to say "better") is, of course, to soft-link /home/Perl/bin/perl to wherever actual Perl binary on the new systems will be... it's only feasible if you have efficient bulk system admin tools which most normal companies should.

DVK
What is "efficient bulk system admin tools"? I don't think we have that.
Ariel Bold
Something that'd allow you to create such a symlink on every single existing and new x86 server without doing it individually server-by-server (unless of course you only have 2-3 servers in which case it's feasible to do it by hand)
DVK