Get full call of Perl script with parameters - perl

How can I get the file name and input parameters of the script into a variable?
So it should look like this:
# Start script as such: ./myscript.pl -d -s server1.domain
#!/usr/bin/perl
use strict;
use warnings;
my $call = some_command;
print $call; # Output: myscript.pl -d -s server1.domain
# OR ./myscript.pl -d -s server1.domain
# OR /path/to/myscript.pl -d -s server1.domain
Tried doing this with __FILE__ and $0 but I can't seem to get the input parameters in the variable.
I'm running v5.10.1 on a AIX machine.

The program and its args are found in $0 and #ARGV respectively.
You can use String::ShellQuote's shell_quote to form a command line from them.

Related

Is there any equivalent of `pwd -L` in perl?

Is there an equivalent of shell's "pwd -L" in perl?
I want the current working directory with symlinks unresolved?
My current working directory is "/path1/dir1/dir2/dir3", and here dir1 is symlink to test1/test2. I want current working directory to be "/path1/dir1/dir2/dir3" via perl script. What I am getting is /path1/test1/test2/dir2/dir3.
How can I get the current working directory to be the path with no symlinks resolved? In other words, I would want to implement shell's pwd -L.
use the perl backtick operator to run the pwd -L command on your system and capture the output into a variable, this works on my system:
perl -e 'chomp( my $pwdl = `pwd -L` ); print "$pwdl\n";'
An attempt to replicate the behavior of bash's pwd builtin using just perl (In particular, with the aid of the Path::Tiny and core Cwd modules):
First, from help pwd in a bash shell:
-L print the value of $PWD if it names the current working directory
-P print the physical directory, without any symbolic links
(The GNU coreutils version of pwd(1) also reads the PWD environment variable for its implementation of -L, which is why running it with qx// works even though it doesn't have access to the shell's internal variables keeping track of the working directory and path taken to it)
$ pwd -P # First, play with absolute path with symlinks resolved
/.../test1/test2/dir2/dir3
$ perl -MCwd -E 'say getcwd'
/.../test1/test2/dir2/dir3
$ perl -MPath::Tiny -E 'say Path::Tiny->cwd'
/.../test1/test2/dir2/dir3
$ pwd -L # Using $PWD to preserve the symlinks
/.../dir1/dir2/dir3
$ /bin/pwd -L
/.../dir1/dir2/dir3
$ PWD=/foo/bar /bin/pwd -L # Try to fake it out
/.../test1/test2/dir2/dir3
$ perl -MPath::Tiny -E 'my $pwd = path($ENV{PWD}); say $pwd if $pwd->realpath eq Path::Tiny->cwd'
/.../dir1/dir2/dir3
As a function (With some added checks so it can handle a missing $PWD environment var or one that points to a non-existent path):
#!/usr/bin/env perl
use strict;
use warnings;
use feature qw/say/;
use Path::Tiny;
sub is_same_file ($$) {
my $s1 = $_[0]->stat;
my $s2 = $_[1]->stat;
return $s1->dev == $s2->dev && $s1->ino == $s2->ino;
}
sub get_working_dir () {
my $cwd = Path::Tiny->cwd;
# $ENV{PWD} must exist and be non-empty
if (exists $ENV{PWD} && $ENV{PWD} ne "") {
my $pwd = path($ENV{PWD});
# And must point to a directory that is the same filesystem entity as cwd
return $pwd->is_dir && is_same_file($pwd, $cwd) ? $pwd : $cwd;
} else {
return $cwd;
}
}
say get_working_dir;

Conditional Perl Shebang?

I have a situation where I need to detect if a particular perl executable, /usr/goofy/bin/perl exists and if so use it to run the Perl script otherwise use /usr/bin/perl.
I have been struggling with this small POC script, called perlshebang.pl:
#!/bin/sh -e
perls="/usr/goofy/bin/perl /usr/bin/perl"
for pl_exec in $perls
do
if [ -x $pl_exec ]; then
exec "$pl_exec -w -S \"$0\" ${1+\"$#\"}"
fi
done
print "[$^X] Whoop!\n";
When I run this on a system that does not have /usr/goofy/bin/perl I get this error message:
./perlshebang.pl: 6: exec: /usr/bin/perl -w -S "./perlshebang.pl" : not found
And when I run it on a system that does have /usr/goofy/bin/perl I get a similuar error message:
./perlshebang.pl: line 6: /usr/goofy/bin/perl -w -S "./perlshebang.pl" : No such file or directory
I think I am close but cannot figure out why I am getting these error messages.
Thanks!
To answer your question, "Why am I getting these error messages?", the problem is your exec line:
exec "/path/to/cmd arg arg"
# This will attempt to execute a file named "cmd arg arg"
# (with spaces in name) in directory /path/to/
Contrast that with
exec /path/to/cmd arg arg
# This will attempt to execute a file named "cmd" in directory
# /path/to/, with arguments "arg" and "arg"
So, that is why the shell complains that it cannot find your executable. You don't have a file named perl -w -s "perlshebang.pl", neither under /usr/bin/ nor under /usr/goofy/bin/.
This sounds a little ugly to me if you are releasing software that uses this hack
If you have no other choice, then I suggest you make sure there is always a /usr/goofy/bin/perl, and use the shebang line
#!/usr/goofy/bin/perl
on all your scripts.
For those systems where you want to use the system perl, just make /usr/goofy/bin/perl a symlink to /usr/bin/perl
A co-worker of mine came up with this. I am not sure I fully understand it but it seems to work fine:
#!/bin/sh
#! -*-perl-*-
eval ' if test -x /usr/goofy/bin/perl ; then
exec /usr/goofy/bin/perl -x -S $0 ${1+"$#"};
elif test -x /usr/bin/perl ; then
exec /usr/bin/perl -x -S $0 ${1+"$#"};
fi '
if $running_under_some_shell;
use strict;
use warnings;
print "hello world\n"; # if $foo;
printf("running %s v(%vd)\n", $^X, $^V);
__END__
unpod like docs.
See http://perldoc.perl.org/perlrun.html
You can run the idea out of a Perl script running /usr/bin/perl. Use the shebang line with the 'goofy perl' in your script that should run. Then run the following wrapper, followed by the normal invocation of the script (its name and arguments).
#!/usr/bin/perl
exec "#ARGV";
exec "/usr/bin/perl #ARGV";
print STDERR "Couldn't execute either.\n";
Let's call the above pick_perl.pl, and your script is script.pl. Run it all as
pick_perl.pl script.pl args-for-script
The exec replaces the running program altogether with the one it executes, ie. it loads the new program. Thus your script runs with its own shebang. If that failes exec returns quietly (with false) and the next statement is executed so the other Perl runs the script (overriding the shebang). This happens if script's shebang fails, but also if the first exec fails to execute for any reason.
If you wish/need to run checks then put exec in a full if block. One can also interrogate the 'goofy_perl' file further if -e isn't assuring enough.
#!/usr/bin/perl
$system_perl = "/usr/bin/perl";
$goofy_perl = "/usr/goofy/bin/perl";
# Your 'goofy_perl' script with its arguments
#script_cmd = #ARGV;
if (-x $goofy_perl) { exec "#script_cmd" }
exec "$system_perl #script_cmd";
The #script_cmd has the full command line for your script (which has 'goofy_perl' shebang).

Access perl module within Bash script

I have a perl module with data definitions (hashes, arrays, etc.), is there any way I can access that data from inside a bash script? This isn't working for me...
#!/bin/bash
perl -e 'use Data'
tests=`perl -e "#tests"; `
echo "Perl tests = ${tests}" # prints "Perl tests = "
The module looks something like this:
our #EXPORT_OK = qw( #tests );
our #tests = qw( 1 2 3 4 5 );
If you have package variable #tests inside Data module,
perl -MData -e 'print "$_\n" for #Data::tests'
For perl 5.10 and above,
perl -MData -E 'say for #Data::tests'
You can use a module from the command line with -M
perl -MData -e'print map {"$_\n"} #tests;'
In the code you give, you run one interpreter that loads Data. It exits. You then run a second interpreter, which prints #tests. As that's the only action the second interpreter has performed, it's uninitialized, and prints nothing.

Pass parameter to a perl script executed trough qsub

Hi would like to pass a parameter to my perl script that should be executed trough qsub.
So I run:
qsub -l nodes=node01 -v "i=500" Test.pl
While in Test.pl I try to call i parameter in several way:
use Getopt::Long;
$result = GetOptions ("i" => \$num);
open(FILE,">/data/home/FILEout.txt");
print FILE "$num\n";
print FILE "$ARGV[0]";
close(FILE);
Unfortunatelly output file of the perl script is always empty.
Do you have any suggestions? Where I'm wrong? Help please
According to all documentation I can find -v sets an environment var, so you'd use $ENV{i} to get 500. (Check your own documentation to confirm.)
If you wanted to actually pass an arg to your script, you could try using
qsub ... Test.pl -i=500
But based on my web search, that might only work for some versions of qsub. Others would require that you make a helper script (say Test.sh)
#!/bin/sh
Test.pl "-i=$i"
along with the command
qsub ... -v 'i=500' Test.sh
If qsub ... Test.pl ...args... is supported and you can change your script, the simplest solution is
qsub ... Test.pl 500
and
my ($i) = #ARGV;
I Finally get the solution that works with PBRProfessional 10.4.
There are two way to solve it:
First one is the following
echo "perl /path/to/Test.pl -i 500" | qsub -l nodes=node06
Second one is two use
qsub -l nodes=node06 -v i=500 Test.pl
and read the parameter in the Test.pl through $ENV{i}

Calling a perl script as a shell command

I want to call my perl script as a command from command line.
Example lets say I have a perl file like following
#!/usr/local/bin/perl -w
#args =("mvn","package");
system(#args) == 0
or die "system #args failed"
I right not call this using package.pl
I tried doing the following
#!/bin/sh
eval 'exec /bin/perl –x -S $0 ${1+"$#"}'
if 0;
#!/usr/local/bin/perl -w
#args =("mvn","package");
system(#args) == 0
or die "system #args failed"
and then name the file 'package' .Do chmod on package
When I try to run package, then I get the error
"Can't open perl script []x:No such file or directory
Can someone please point me out , as to how to do this properly??
Thanks
Neeraj
Change to the name you want to use and make it executable:
cp package.pl package
chmod +x package
Run it:
package
or:
./package
Changed single quotes to double quotes and escaped inner double quotes. Also, there seems to be some problem with paths. Try calling your script with absolute path. I tried adding "./" and it worked:
#!/bin/sh
echo "This is shell"
eval "exec /usr/bin/perl -x -S ./$0 ${1+\"$#\"}"
if 0;
#!/usr/bin/perl -w
print "This is Perl\n";