Rock
Rock

Reputation: 347

Interpolate perl variable in shell command

I want to take date as input from User & pass that input to shell command below.

for e.g.

$date = ARGV[0];
`cd xyz $date`

will this variable be interpolated in perl?

Upvotes: 7

Views: 14469

Answers (4)

James Green
James Green

Reputation: 1753

Perldoc has the answers, as ever.

Specifically, http://perldoc.perl.org/perlop.html#Quote-and-Quote-like-Operators has "Yes" in the Interpolates? column (with a proviso you don't need to worry about here), so yep, it's safe to assume your variable will be interpolated.

You can get the same document by running 'perldoc perlop' at your local commandline, often.

Upvotes: 6

David W.
David W.

Reputation: 107040

Yes, it will interpolate the variable. However, I highly recommend two things:

  • Use qx/../ instead of back ticks.
  • Set the command you're running first in a Perl variable, and then interpolate that variable.

The qx/../ is nice because it makes it more obvious what you're doing:

my $variable = qx(ls $directory);

You could use a wide variety of characters for qx:

my $variable = qx(ls $directory);
my $variable = qx/ls $directory/;
my $variable = qx^ls $directory^;
my $variable = qx#ls $directory#;

The character after the qx will be used as quotes. If you use parentheses, square brackets, or curly braces, you use them in pairs with the opening one and closing one.

This means that you can avoid issues where a particular character in your command might confuse things.

The other thing is to build your command into a Perl variable and then execute it when you try to do interpolations. This gives you more control over what you're doing:

my $HOME;
my $command;

$HOME = "bin";
$command = "ls $HOME";
print qx($command); #Lists the directory bin

$command = 'ls $HOME';
print qx($command); #List user's home directory

In both of these examples, I'm doing qx($command). However, in the first example, I allow Perl to substitute the value of $HOME. In the second example, I use single quotes, so Perl doesn't substitute the value of$HOME. Instead, the string$HOME` is just part of my command I'm using. I'm letting the shell interpolates it.

I usualy am leery of any program that uses qx/.../. In most cases, it's used to run a command that could be done in Perl itself. For example, in early Perl programs, you'd see things like this:

 $date = `date +%M/%Y/%D`
 chop $date;     #Yeah, I said EARLY Perl programs

Because it was simply a lot easier to run the Unix command rather than trying to do it in a pure Perl way. However, doing it the Perl (i.e. the correct) way means you're no longer dependent upon the OS's behavior which is not entirely under your control.

If you need the output of the command for use in your Perl script, you should use open to execute your command, and treat the output of the command as a file.

my $command = "ls $HOME";
open my command_fh, "|-", $command or die qq(Couldn't execute "$command");

If you simply need to execute the command, use the system command:

my $command = "xyz $date";
my $error = system $command;
if ( $error ) {
    #Something terrible happened...
}

Note that if you send only a single scalar argument to the system command, and it contains possible shell meta characters, it will execute the command via the OS shell. If you send the system command a list to execute, or there are no shell metacharacters, Perl will call the command executor to execute the command directly without any shell interpolations:

my @command = qw(ls $HOME);
system @command;   #Will print out "No such directory '$HOME'

Upvotes: 6

ysth
ysth

Reputation: 98398

You have a couple of problems; first of all, cd only takes one parameter. Perhaps you meant something like cd xyz$date? Second, backticks start a shell that executes the command you give, which will do the change directory command and then immediately exit, having no effect. (The parent perl process's current directory is left unchanged.) You might be looking for chdir.

But yes, the interpolation will work; to disable interpolation in backticks, you either escape special characters (echo xyz \$date) or use qx with single quote delimiters (qx'echo xyz $date').

Upvotes: 10

Quentin
Quentin

Reputation: 943625

This is trivial to test:

Input:

use v5.16;
use strict;
use warnings;
my $foo = 123;
say `echo $foo`;

Output:

123

So yes.

Beware of variables containing characters with special meaning in shell though.

Upvotes: 9

Related Questions