7

I can do math like

perl -e 'print 5253413/39151' -l

But I don't quite get how to take advantage of Perl's ability to do math with my own predefined bash variables. I've tried

var1=$(some wc command that yields a number); var1=$(some wc that yields another number)
perl -e 'print var1/var2' -l

But it doesn't work

1
  • The reason it doesn't work is that your var1/var2 is just text to Perl. Even after correcting it to $var/$var2, the script can't see that these two variables are defined in the shell calling the script. You must pass their values to the script in some way (e.g. as environment variables, see the answers). Commented Jan 19, 2016 at 8:18

3 Answers 3

15

There are two main ways to do this.

  • Within the Perl code you can use the %ENV built-in hash to access environment variables that are exported from the shell

    $ export var1=5253413
    $ export var2=39151
    $ perl -E 'say $ENV{var1}/$ENV{var2}'
    134.183366963807
    
  • You can use the shell interpolation facility to insert the value of a shell variable into a command

    This is best done as parameters to the perl one-liner rather than introducing the values directly into the code

    $ var1=5253413
    $ var2=39151
    $ perl -E '($v1, $v2) = @ARGV; say $v1/$v2' $var1 $var2
    134.183366963807
    
Sign up to request clarification or add additional context in comments.

9 Comments

+1; also worth mentioning the more concise ad-hoc, one-off method of defining environment variables for a command: var1=5253413 var2=39151 perl -E 'say $ENV{var1}/$ENV{var2}'
@mklement0: I considered including that but dismissed it as being more centred on shell techniques than Perl. But in retrospect I guess that's what this question's all about. I'll leave your comment to represent it. Thank you
Incidentally, the quickest (and dirtiest) way to do this is just perl -e 'print '$var1/$var2 -l
@reinierpost , I tried that and it didn't work. Why is it considered dirty ?
@Tom: what do you mean by it didn't work? What was the error message? The reason it's dirty is that it will only work if $var1 and $var2 have been set to numbers (e.g. they must not contain any whitespace).
|
6

Two less common ways to do this make use of long-standing perl features.

The first is the core module Env, which ties process environment variables to perl variables:

sh$ export VAR1=1000
sh$ export VAR2=33
sh$ perl -MEnv -E 'say $VAR1/$VAR2'           # imports all environ vars
333.333333333333
sh$ perl -MEnv=VAR1,VAR2 -E 'say $VAR1/$VAR2' # imports only VAR1, VAR2
333.333333333333

Note that the variables need to be present in the environment inherited by the perl process, for example with export VAR as above, or explicitly for a single command (as by FOO=hello perl -MEnv -E 'say $FOO').

The second and rather more obscure way is to use use perl's -s switch to set arbitrary variables from the command line:

sh$ VAR1=1000
sh$ VAR2=33
sh$ perl -s -E 'say $dividend/$divisor' -- -dividend=$VAR1 -divisor=$VAR2
333.333333333333

awk does something similar with its -v switch.

6 Comments

Environment variables are also available via the global %ENV hash; shell# export FOO=BAR && perl -E 'say $ENV{FOO}'
@Joshua, of course, but many perl hackers and admins in need of a one-liner are just(ly) too impatient to type $ENV{this} and $ENV{that}. :)
This is a really neat idea and I almost want to vote for it as an answer. But, wouldn't just using double quotes work just fine? For some reason this answer was deleted, but someone said that you could do perl -e "print $var1/$var2" -l
@Tom, the danger with simply interpolating the shell variables into the perl command string is twofold. First, these constructions are confusing to folks who can't get the quoting and variable expansion quite right — is that "$foo" a shell var or a perl var? — and quickly become opaque when you've quotes within quotes. Second, this practice is essentially an eval in your perl program, a code injection opportunity. If you get too cavalier about that, even in one-liners, you'll hurt yourself one day.
@pilcrow. I'm not sure I understand your figures of speech. Can expand your explanation to provide more detail? It seems like this solution is identical to the one you provided, just without the export step. It seems much more intuitive just to put it in double quotes
|
0

I believe the spirit of the question is to pass variables without exported ENV vars.

Beside using perl -s -e expression -perlvar=val, below is code that uses two other mechanisms to pass the variable to perl.

a=x; b=N; c=z;
b=y perl -e '$pa='$a';'  -e "\$pc=$c;" -e 'print "$pa$ENV{b}$pc\n";'
echo $a$b$c

Passing a and c is same, only the quoting is different. When passing using chained expressions, like this, it is important to end the expression with semi-colon; because, they flow into one expression at the end.

Passing b is done by ENV, but instead of using the exported value, it is passed directly into perl's ENV by giving the assignment before the command on the same command-line.

Last the echo command is to emphasize how the shell's definition of $b is unchanged.

Using the mechanism of b's passing, we arrive at a more secure solution, because the process's ENV data cannot be checked for the value, and it will not be seen in the command-line argument list.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.