Accessing Shell Variable in a Perl Program

Accessing shell variable in a Perl program

The variable $ddd isn't set *in the shell that you invoke from your Perl script.

Ordinary shell variables are not inherited by subprocesses. Environment variables are.

If you want this to work, you'll need to do one of the following in your shell before invoking your Perl script:

ddd=arraytest.pl ; export ddd # sh

export ddd=arraytest.pl # bash, ksh, zsh

setenv ddd arraytest.pl # csh, tcsh

This will make the environment variable $ddd visible from your Perl script. But then it probably makes more sense to refer to it as $ENV{ddd}, rather than passing the literal string '$ddd' to the shell and letting it expand it:

$var = `ls -l $ENV{ddd}`;

How could I access shell variable from Perl script?

From bash manual:

When a program is invoked it is given an array of strings called the
environment. [...] The shell provides several ways to manipulate the
environment. On invocation, the shell scans its own environment and
creates a parameter for each name found, automatically marking it for
export to child processes. Executed commands inherit the environment.
The export and declare -x commands allow parameters and functions to
be added to and deleted from the environment.

So (assuming a Bash shell) using:

export LINES

will make the variable $LINES available from within a Perl script startet from the Shell (using $ENV{LINES} from the Perl script).

How to use shell variables in perl command call in a bash shell script?

The same way you pass values to any other program: Pass it as an arg. (You might be tempted to generate Perl code, but that's a bad idea.)

Dt=$( perl -MPOSIX -e'print strftime $ARGV[0], localtime time-86400;' -- "$myDate" )

Note that code doesn't always return yesterday's date (since not all days have 86400 seconds). For that, you'd want

Dt=$( perl -MPOSIX -e'my @d = localtime time-86400; --$d[4]; print strftime $ARGV[0], @d;' -- "$myDate" )

or

Dt=$( perl -MDateTime -e'print DateTime->today(time_zone => "local")->subtract(days => 1)->strftime($ARGV[0]);' -- "$myDate" )

or simply

Dt=$( date --date='1 day ago' +"$myDate" )

Using Bash environment variables from within a Perl script?

There are two queries here, on use of Bash variables and on running external commands.

There is the %ENV hash in Perl, with environment variables

perl -wE'say $ENV{PWD}'

However, you are often better off getting the equivalent within the script, as things may have a subtly different meaning for the script or change as the script runs.

More importantly, using shell commands exposes you to all kinds of potential problems with quoting, shell injection, and interpretation. For instance, the command you show is dangerous, as outlined in Charles Duffy comment. It is in principle better to use Perl's rich functionality. See for example

  • Executing system commands safely while coding in Perl   and

  • Using system commands in Perl instead of built in
    libraries/functions

for a sober, and detailed, account of advantages.


In case you do need to run external commands, it is best to avoid the shell altogether, for example by using the multi-argument form of system. If you need the output of the command as well there are various modules in Perl that provide that. See links below.

If you also need to use the shell's capabilities, instead of quoting everything just right in order for the shell to receive what it needs better use a ready tool like String::ShellQuote.

Some examples:

  • How to use both pipes and prevent shell expansion in perl system function?

  • Perl is respecting '<' as a regular character rather an output redirection

  • How to pipe the content of a variable as STDIN in a qx{} statement in Perl?

  • Perl system command with multiple parameters output to file.

Note that qx operator (backticks) uses /bin/sh, which may or may not get relegated to Bash. So if you want Bash you'll need system('/bin/bash', '-c', @cmd). See the links with examples.


Here is a full example related to the objective behind the question.

Your program's working directory may be other than expected depending on how it's started. For one, it changes after chdir. I don't know your exact intent with PWD, but in Perl there are core Cwd::cwd and FindBin with $RealBin, for the current working directory and for the directory where the script resides (generally different things).

To create a symbolic link to $path, with the relative path following the current working directory

use warnings;
use strict;
use Cwd qw(cwd);

my $cwd = cwd;

my $path = '/first/path';

symlink($path, "$cwd/second/path") or die "Can't make a symlink: $!";

If the path is meant to be the script's location use $RealBin from FindBin instead of cwd.

Note that with symlink you cannot pass a directory instead of a link name. See this page.

How do I pass $SHELL variable into a perl search and replace

For an example like the following:

$ value=$(uname -r)
$ perl -e 'print "$value"'

When we run Perl to execute our code here we are not sending the contents of the shell variable $value to Perl. We are sending the literal string '$value', which Perl will then try and print the Perl variable $value, which does not exist.

Here are two ways that you could correct this.

The first would be to wrap your Perl code in double quotes instead of single quotes so that $value becomes the contents of the shell variable $value instead of the literal string '$value' when sent to Perl:

$ value=$(uname -r)
$ perl -e "print '$value'"
3.13.9-generic

However when using this method if you have Perl variables along with this shell variable you will need to 'escape' the Perl variables or you'll get an error like this:

$ value=$(uname -r)
$ perl -e "$example = 'test'; print \"$value $example\";"
syntax error at -e line 1, near "="

Using \'s will correct this:

$ value=$(uname -r)
$ perl -e "\$example = 'test'; print \"$value \$example\";"
3.13.9-generic test

Secondarily, you can avoid changing the single quotes to double quotes by exporting "value" to the environment, and then accessing it through the %ENV hash already available inside your Perl program (http://perldoc.perl.org/Env.html). For example:

$ export value=$(uname -r)
$ perl -e 'print "$ENV{value}\n"'
3.13.9-generic

Be mindful of your environment that you do not accidentally overwrite some needed environment variable. Using a naming convention very specific to your work can help:

$ export MYPROGRAMNAME_KERNEL_VERSION=$(uname -r)
$ perl -e 'print "$ENV{MYPROGRAMNAME_KERNEL_VERSION}\n"'
3.13.9-generic

printenv on most Linux systems will show you the current established environment variables. You could also just use Perl to inspect %ENV.

using environment variable in the perl script

$GATE in a double quoted string will be considered a Perl variable. If you want to use an environment variable, you can use the %ENV hash:

system ("bsub xyz +OPTIONS_GATE=$ENV{GATE}")

Alternatively, you can escape the dollar sign so Perl does not treat $GATE as a Perl variable:

system ("bsub xyz +OPTIONS_GATE=\$GATE")

Or use a single quoted string, which does not interpolate variables:

system ('bsub xyz +OPTIONS_GATE=$GATE')

Note that if you had used

use strict;
use warnings;

It would have told you about this error. strict would have said:

Global symbol "$GATE" requires explicit package name
Execution of script.pl aborted due to compilation errors.

And warnings would have said:

Name "main::GATE" used only once: possible typo at script.pl line 12.
Use of uninitialized value $GATE in string at script.pl line 12.

When you do not use use strict; use warnings; your errors are not removed, they are only hidden from you, so that they are harder to find. Therefore, always use these two pragmas.



Related Topics



Leave a reply



Submit