To run a Perl script directly like a binary from within the shell, you have to
- set the executable flag on the script
- Add the shebang line (the 1st line (
#!...) specifiyng the interpreter to use)
#!/usr/bin/env perl
#!/usr/bin/perl
#!/u01/app/oracle/product/19/perl/bin/perl
the 2nd and 3rd example will run the script with the given Perl-binary.
The 1st example uses the 1st perl binary found in $PATH
If you work with Oracle and want to use a Perl script connecting to the database, then the Perl from the OS (/usr/bin/perl) is usually not usable because the Perl-modules for Oracle (DBI / DBD::Oracle) are missing.
A solution could be to use the line of the 3rd example, but then, the script is hardcoded to only that ORACLE_HOME.
As a solution, often a shell-wrapper script is used to call the perl-script with the correct perl binary (both scripts are in the same directory and have the same name, but different suffixes: .sh and .pl)
#!/usr/bin/env bash
cd $(dirname `command -v $0`) # change to script-directory
$ORACLE_HOME/perl/bin/perl $(basename $0 .sh).pl
But is it also possible to integrate both scripts in one file? Yes, it is possible.
#!/usr/bin/env bash
echo "hello shell"
# additional code, e.g. setting the env. for a specific ORACLE_SID
# Hand off to the embedded Perl section in this file:
exec $ORACLE_HOME/perl/bin/perl -x "$0" "$@"
#!perl
# the line above is essential to detect the begin of Perl-code
# Everything below this line is treated as Perl
print "hello perl\n";
use DBD::Oracle; #if there is an error, the wrong Perl is used
And the output is as expected:
hello shell
hello perl
Both “hello *” appear and no error that DBD::Oracle is not found, because we use Oracle’s Perl.
And what happens, if we call this script with Perl?
# perl shell1.sh
hello shell
hello perl
For me, an unexpected behavior. Perl does not complain about the shell code (unknown syntax), it executes it as shell code according the shebang-line (#!/usr/bin/env bash).
But how can we call the script as a real Perl-script, without executing the shell-Part? We can hide it with the Perl Old Documentation tags (=pod / =cut). The shell will complain and ignore the unknown POD line and continues with the next one. Perl will skip this block from parsing:
=pod 2>/dev/null
echo "hello shell"
exec $ORACLE_HOME/perl/bin/perl -x "$0" "$@"
=cut
#!perl
print "hello perl\n";
use DBD::Oracle;
Little disadvantage: We can no longer use the shebang line for the shell. The script uses the shell from which it was invoked. To explicitly use a specific shell, we have to call the script with the shell: bash script2.sh
perl script2.sh # perl references to /usr/bin/perl
Can't locate DBD/Oracle.pm in @INC (...
OK, the script is really executed with the given Perl (which does not contain DBD::Oracle). Now, try it with the Oracle Perl.
$ORACLE_HOME/perl/bin/perl scrip2.sh
hello perl
And success! Perl skips the shell-code and only runs the Perl-code.
So, we have a script that can be used as a “normal” Perl-Script, and as a wrapper-script without maintaining 2 separate scripts.