linuxbashperlpwd

Using Bash environment variables from within a Perl script?


I am trying to run a Bash command from within my Perl program. However Perl seems to be confusing my Bash $PWD environment variable as a Perl variable.

How can I make it just read it all as a string?

This is what I'm trying to run

my $path = /first/path;
`ln -s $path $PWD/second/path`

Those backticks runs the second line in Bash. Using System() produces the same problem.

Any ideas?


Solution

  • 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

    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:

    Note that qx operator (backticks) uses /bin/sh, which may or may not get relegated to Bash. So if you want Bash you need system('/bin/bash', '-c', $cmd), where $cmd need be built carefully to avoid problems. 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.