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.