I have a question about how to execute the perl file inside of a shell script
I have 2 files now, "test.sh" and "test.pl", here are example of my scripts
SHELL script
#!/bin/bash
perl FILEPATH/test.pl
......
PERL script
#!/usr/bin/perl
my $a = "hello"
sub saysomething
{
print $a;
}
.....
The way I call the shell script is : under the path of shell scripts, execute "./test.sh"
All mentioned above are working under the environment
GUN bash, version 4.2.24(1)-release (i686-pc-linux-gnu) + perl (v5.14.2)
But if I put those scripts on server (which I couldn't change the bash / perl version)
GNU bash, version 4.2.10(1)-release (x86_64-pc-linux-gnu) + perl (v5.12.4), I got the followign message:
FILEPATH/test.pl: line 2: my: command not found
Does anybody know how can I solve this problem?
BTW, if I execute the perl script individually (perl FILEPATH/FILENAME.pl), it works perfectly.
In order to execute a perl script by .sh script you dont need to use perl prefix, but only:
#!/bin/sh
/somewhere/perlScript.pl
It will work without problem.
This problem is at least two-fold. One, you have to have the location of Perl in your environment PATH. Two, the location of Perl may be different on different machines. One solution to both problems that I, and others, have used for years is to make use of a "magic header" of some sort at the top of Perl programs. The header identifies itself as a sh shell script and leverages the fact that /bin/sh exists in every version/flavor of Linux/UNIX. The header's job is to fortify the PATH with various possible Perl locations and then run the Perl script in place of itself (via exec). Here is a "Hello World" example:
1 #! /bin/sh --
2 eval '(exit $?0)' && eval 'PERL_BADLANG=x;PATH="/usr/bin:/bin:/usr/local/bin:$PATH";export PERL_BADLANG;: \
3 ;exec perl -x -S -- "$0" ${1+"$#"};#'if 0;
4 exec 'setenv PERL_BADLANG x;exec perl -x -S -- "$0" $argv:q;#'.q
5 #!/bin/perl -w
6 +($0=~/(.*)/s);do(index($1,"/")<0?"./$1":$1);die$#if$#;__END__+if 0;
7 # Above is magic header ... real Perl code begins here
8 use strict;
9 use warnings;
10 print "hello world!\n";
Note: I added line numbers just to make it clear where lines start and end.
First check where perl is installed on your system, e.g. which perl and use that location in the shebang line instead of /usr/bin/perl, if it is different.
If all other recommendations fail, check the first line of the script on the machine where it is not running properly by doing this: head -1 test.pl | xxd. Does the output show the last two bytes as 0d 0a? If so, you probably copied over the file via Windows and didn't do a dos2unix conversion.
"command not found" is an error emitted by the shell. You are trying to run your Perl script by the shell, not by Perl.
Related
I received a Perl script that apparently is called from an SBATCH script to be submitted as a job to a computer cluster managed by SLURM. The script is old and I am yet to become more familiar with Perl. Additionally, the Perl script is being used as wrapper to call an executable with mpiexec_mpt.
But whenever I do sbatch sbatch_submission, the Perl script is executed by the computer node but I don't obtain any output or execution of the system() method - or I do but I don't know where it is.
I know Perl is executed by SBATCH because I got an error that it couldn't find a module so I manually pointed Perl to the library path using the -l flag as shown below. But after that I don't get any output.
The SBATCH script and the perl script are below:
SBATCH SCRIPT
1 #!/bin/bash
2 #SBATCH --job-name=job_submission
3 #SBATCH --output=output_perl.run
4 #SBATCH --error=error_perl.run
5 #SBATCH -n 2 # request 2 cores
6 #SBATCH --constraint=intel
7
8 # Load Needed Modules:
9 module load mpt
10
11 # Set-up environment for perl:
12
13
14
15 # Running perl script:
16 echo "Calling simple hello_world.c with perl (sbatch)"
17
18 perl input_perl.pl 1> perl_in.stdout 2> perl_in.stderr # edit after
# suggestions
19 echo "Done with perl script (sbatch)"
20
PERL INPUT
1 #!/usr/bin/perl -w
2 use strict;
3 use warnings;
4 use diagnostics;
5 use List::MoreUtils qw(indexes); ## edit after suggestions
6 system("echo this is your hostname:");
7 system("hostname");
8 system("mpiexec_mpt -np 2 hello_world");
9 print "Done executing hello world! from within perl script!\n"
OUTPUT FROM STDERR
1 Can't locate List/MoreUtils.pm in #INC (#INC contains: /usr/lib64/perl5/vendor_perl/List /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl / usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at input_perl.pl line 5.
Aside from the output above the output files: perl.output and output_perl.run are empty.
I suspect I am missing something regarding the applicability of the system() method in Perl, as well as how to tell Perl where to send it's output when working with slurm. I have also tried generating a .txt file with the Perl script, but when I run it with SBATCH the .txt file is not generated. I have no issues running the perl_input.pl without using the SBATCH script as wrapper: e.g: perl perl_input.pl.
Additional info, the hello_world executable has been written in C and I have tested it independently and it runs. It is a simple MPI program that lists ranks and size. I don't think that's the issue though.
Independently and running locally the Perl and C scripts run, it's when I use SBATCH that the issues arise.
I am not sure this is a solution but this is what worked for me.
Ended up re-installing perl using the instructions here:
https://learn.perl.org/installing/unix_linux.html
I work from a computer cluster so there might be something going on with the perl installation I was using. The module call that was causing the problem seems to be installed but perl can't find it when I call the script from SBATCH.
I installed the module I needed: List::MoreUtils as follows:
perl -MCPAN -Mlocal::lib -e 'install List::MoreUtils'
Link: https://www.perlmonks.org/?node_id=1117597
Logged out and then started a new session. The new perl installation sources a bashrc file that automatically updates the perl version to the one that was just installed. So whenever you run a perl script you don't use the old installation.
After that, I set the PERL5LIB variable to the path where MoreUtils is located and everything worked.
I'd like to know if someone knows a function or command that I can put at the beginning of my Perl script that tells the user for example "this script is being run by perl v 5.XXX".
Specially when we have many versions installed.
$^V shows the "...revision, version, and subversion of the Perl interpreter." From perlvar.
You can use a special variable $]:
$ perl -e 'print $];'
5.014002
I came across the following example. I tried to google but could not find much so I'm posting this question here.
What is the benefit of executing the perl script like this?
How can we make the shell script work like a "normal" shell script once we are through executing the perl code?
Here's the code:
#!/bin/ksh
#! -*- perl -*-
eval 'exec $PERLLOCATION/bin/perl -x $0 ${1+"$#"} ;'
if 0;
print "hello world\n";
# how can I make it behave like a "normal" shell script from this point onwards? What needs to be done?
# echo "hello world" ### this results in error
This idiom is described in the perlrun documentation.
The -x switch scans the whole file and ignores anything that appears before the first line that begins with #! and also contains the word perl.
It means that your system will run the script with the Perl interpreter whether you invoke the script with perl or with a shell command (sh/bash/ksh/etc.)
That is,
$ perl this_script
and
$ sh this_script
will both run the script with perl.
To address your second question, this idiom has just about nothing to do with combining shell script and Perl script in the same file. There are a few different ways to approach that problem, but maybe the most readable way is to write in shell script, but use the shell's heredoc notation to invoke perl code.
#!/bin/bash
# this is a bash script, but there is some Perl in here too
echo this line is printed from the shell
echo now let\'s run some Perl
perl <<EOF
# this is now perl script until we get to the EOF
print "This line is printed from Perl\n";
EOF
echo now this is from the shell script again
1. If you start a Perl script in the usual way:
#!/usr/bin/perl
print "hello world\n";
the #! line will only work if the Perl interpreter is actually installed under /usr/bin. The perl/ksh bilingual script you show is a tricky kluge to make the script work even if perl is installed somewhere else. For more information, see e.g. this.
2. You can't. When the shell process encounters the exec command, it terminates and hands control over to perl. (Technically, it executes perl in place of the shell, without creating a new process.) The only way to run more shell commands after that would be to launch a new shell.
It's way simpler than what's already been posted.
#!$PERLLOCATION/bin/perl
doesn't work because the shebang (#!) line is interpreted by the kernel (not the shell), and the kernel doesn't do variable interpolation.
The code invokes ksh to expand the environment variable and to launch the specified installation of Perl.
I often write one-liners on the command line like so:
perl -Magic -wlnaF'\t' -i.orig -e 'abracadabra($_) for (#F)'
In order to scriptify this, I could pass the same flags to the shebang line:
#!/usr/bin/perl -Magic -wlnaF'\t' -i.orig
abracadabra($_) for (#F);
However, there's two problems with this. First, if someone invokes the script by passing it to perl directly (as 'perl script.pl', as opposed to './script.pl'), the flags are ignored. Also, I can't use "/usr/bin/env perl" for this because apparently I can't pass arguments to perl when calling it with env, so I can't use a different perl installation.
Is there anyway to tell a script "Hey, always run as though you were invoked with -wlnaF'\t' -i.orig"?
You're incorrect about the perl script.pl version; Perl specifically looks for and parses options out of a #! line, even on non-Unix and if run as a script instead of directly.
The #! line is always examined for switches as the line is being
parsed. Thus, if you're on a machine that allows only one argument
with the #! line, or worse, doesn't even recognize the #! line, you
still can get consistent switch behavior regardless of how Perl was
invoked, even if -x was used to find the beginning of the program.
(...)
Parsing of the #! switches starts wherever perl is mentioned in the
line. The sequences "-*" and "- " are specifically ignored so that you
could, if you were so inclined, say
#!/bin/sh
#! -*-perl-*-
eval 'exec perl -x -wS $0 ${1+"$#"}'
if 0;
to let Perl see the -p switch.
Now, the above quote expects perl -x, but it works just as well if you start the script with
#! /usr/bin/env perl -*-perl -p-*-
(with enough characters to get past the 32-character limit on systems with that limit; see perldoc perlrun for details on that and the rest of what I quoted above).
I had the same problem with #!env perl -..., and env ended up being helpful:
$ env 'perl -w'
env: ‘perl -w’: No such file or directory
env: use -[v]S to pass options in shebang lines
So, just modify the shebang to #!/usr/bin/env -S perl -...
How do I run a Perl script on OS X?
You can run your Perl script by invoking the Perl interpreter and giving your file as input:
perl myprogram.pl
The easiest way to run a perl script is with the option:
perl myprogram.pl
However, you may find it more useful to add a shebang line at the top of the perl file.
#!/usr/bin/perl
print "Hello World!\n";
In order to execute this script, you need to add execute permissions to your program. Run:
chmod +x myprogram.pl
Now, in order to run your script, you can simply type:
./myprogram.pl
A good tutorial on Perl in OSX can be found here:
http://www.mactech.com/articles/mactech/Vol.18/18.09/PerlforMacOSX/index.html
A generic documentation on executing Perl code is of course perldoc perlrun.
To answer your question directly:
You can run a perl script on any Unix system by either having the code evaluated and executed from command line:
perl -e 'print "Hello World\n"';
Or you can save your Perl script to a file (customarily having .pl extension, say script1.pl and with the first line being #!/usr/bin/perl) and then you can execute it as any Unix program (after setting proper execute permissions)
/path/to/script/script1.pl
You can also execute a script from a file by running perl interpreter as the command and giving the script as a parameter (in this case execute permissions to the script are not needed):
perl /path/to/script/script1.pl
For some reason the whole directory didn't work for me but I just did
perl ~/Desktop/file.pl
(you could also use any folder that is in your user-folder after the ~/)