I have a perl module with data definitions (hashes, arrays, etc.), is there any way I can access that data from inside a bash script? This isn't working for me...
#!/bin/bash
perl -e 'use Data'
tests=`perl -e "#tests"; `
echo "Perl tests = ${tests}" # prints "Perl tests = "
The module looks something like this:
our #EXPORT_OK = qw( #tests );
our #tests = qw( 1 2 3 4 5 );
If you have package variable #tests inside Data module,
perl -MData -e 'print "$_\n" for #Data::tests'
For perl 5.10 and above,
perl -MData -E 'say for #Data::tests'
You can use a module from the command line with -M
perl -MData -e'print map {"$_\n"} #tests;'
In the code you give, you run one interpreter that loads Data. It exits. You then run a second interpreter, which prints #tests. As that's the only action the second interpreter has performed, it's uninitialized, and prints nothing.
Related
I have this simple code to execute, but have failed.
a.csh
#! /bin/csh -f
`perl a.pl`
a.pl
#use perl
eval 'exec perl -w -S $0 ${1+"$#"}'
if 0;
use Cwd;
print "here.\n";
When I run a.csh, it reports an error as below.
here: Command not found
I am not sure what that means; any suggestion is welcome.
The backticks in your program are returning the output of the perl script. Then csh tries to execute that output as csh. toolic's comment telling you to remove the backticks is correct: perl a.pl. Reading more about how backticks work might be useful.
The following has been tested with perl 5.24 on OS X 10.11.5.
I wrote a short program (perl-embed.pl) to determine whether perl escapes shell metacharacters when interpolating strings into backticks (it doesn't).
use strict;
use warnings;
my $bar = '" ; echo 45 ; "';
printf "%s\n", `echo "hi${bar}ls"`;
I was very surprised to see that this generated a warning and only executed part of the command.
$ perl perl-embed.pl
Redundant argument in printf at perl-embed.pl line 6.
hi
For comparison the following program (perl-embed2.pl) with print instead of printf runs without warnings.
use strict;
use warnings;
my $bar = '" ; echo 45 ; "';
print `echo "hi${bar}ls"`;
I then ran it.
$ perl perl-embed2.pl
hi
45
<contents of current working directory>
perl-embed.pl's behavior is totally unexpected. printf interpolates the contents of strings just fine in other contexts, even if the string contains weird characters.
$ perl -Mstrict -Mwarnings -e 'printf "%s\n", q[5]'
5
$ perl -Mstrict -Mwarnings -e 'printf "%s\n", q["]'
"
The system perl (version 5.18) does not emit this warning, but seems not to execute ls or echo 45 like we would expect
$ /usr/bin/perl perl-embed.pl
hi
$ /usr/bin/perl perl-embed2.pl
hi
45
<contents of current directory>
Why is perl behaving this way? Note that in every case perl is exiting normally.
You are using backticks in list context, so the expression
`echo "hi${bar}ls`
will run the command
`echo "hi"; echo 45; ls`
and return each line of output in a separate element, for example
( "hi",
"45",
"foo",
... # other files in current directory
)
But the template in printf ("%s\n") only has one placeholder, so printf gets confused and issues the warning, just as if you said
perl -we 'printf "%d\n", 1, 2, 3, 4'
i am very new to perl just began to learn when i try to assign a scalar a value and the print it i am facing problem. I am doing
perl -e "$number=30;"
perl -e "print $number;"
the output doesnt show anything but when i do
perl -e "$number=30; print $number;"
the output shows 30 why?
This:
perl -e "$number=30;"
runs the Perl program $number=30;, which sets the variable $number to 30 and then does nothing with it.
This:
perl -e "print $number;"
runs the Perl program print $number;, which prints the value of the uninitialized variable $number.
The key point is that, since these are two completely separate Perl programs, there's no connection between the variable $number in the first program and the variable $number in the second program. There is no relationship between the two programs, and no communication between them, so they do not and cannot share any variables.
when you execute:
perl -e "$number=30;"
perl -e "print $number;"
these are two independent processes, so they don't share information. Variable $number won't be available to the second command.
The other one:
perl -e "$number=30; print $number;"
Works because it runs in the same execution, and $number is visible to the next print sentence
Hi would like to pass a parameter to my perl script that should be executed trough qsub.
So I run:
qsub -l nodes=node01 -v "i=500" Test.pl
While in Test.pl I try to call i parameter in several way:
use Getopt::Long;
$result = GetOptions ("i" => \$num);
open(FILE,">/data/home/FILEout.txt");
print FILE "$num\n";
print FILE "$ARGV[0]";
close(FILE);
Unfortunatelly output file of the perl script is always empty.
Do you have any suggestions? Where I'm wrong? Help please
According to all documentation I can find -v sets an environment var, so you'd use $ENV{i} to get 500. (Check your own documentation to confirm.)
If you wanted to actually pass an arg to your script, you could try using
qsub ... Test.pl -i=500
But based on my web search, that might only work for some versions of qsub. Others would require that you make a helper script (say Test.sh)
#!/bin/sh
Test.pl "-i=$i"
along with the command
qsub ... -v 'i=500' Test.sh
If qsub ... Test.pl ...args... is supported and you can change your script, the simplest solution is
qsub ... Test.pl 500
and
my ($i) = #ARGV;
I Finally get the solution that works with PBRProfessional 10.4.
There are two way to solve it:
First one is the following
echo "perl /path/to/Test.pl -i 500" | qsub -l nodes=node06
Second one is two use
qsub -l nodes=node06 -v i=500 Test.pl
and read the parameter in the Test.pl through $ENV{i}
I've got a script that calls Perl's Time::HiRes module to calculate elapsed time. Basically the script gets the time by passing the following one-liner:
use Time::HiRes qw(time); print time
to the Perl interpreter via backticks and gets back the results.
#/bin/sh
START_TIME=`perl -e 'use Time::HiRes qw(time); print time'`
END_TIME=`perl -e 'use Time::HiRes qw(time); print time'`
ELAPSED_TIME=$(echo "($END_TIME - $START_TIME)" | bc)
echo $ELAPSED_TIME
I tried to rewrite it in a more modular way, but I'm stumped by the quoting rules of the Bash shell.
#/bin/sh
CALCULATE='bc'
NOW="perl -e 'use Time::HiRes qw(time); print time'"
START_TIME=`$NOW`
[Some long running task ...]
ELAPSED_TIME=$(echo "($NOW - $START_TIME)" | $CALCULATE)
echo $ELAPSED_TIME
Bash complains that something is not quoted properly. Why doesn't Bash just expand the command in $NOW and pass it to the backtick to be executed?
I tried various ways to embed Perl code in a shell script variable, but I can't seem to get it right.
How can I quote Perl code inside a shell script correctly?
Using a function is the most straightforward way to do this, I think:
#! /bin/bash
now() {
perl -e 'use Time::HiRes qw(time); print time';
}
calc=bc
time1=$(now)
time2=$(now)
elapsed=$(echo $time2 - $time1 | $calc)
echo $elapsed $time1 $time2
Essentially no quoting is required.
Your problem is that $NOW is just a string with some Perl code in it. You need to tell Bash to execute it, with backticks or $():
ELAPSED_TIME=$(echo "($($NOW) - $START_TIME)" | $CALCULATE)
Also, Bash can do arithmetic natively:
ELAPSED_TIME=$(( $($NOW) - $START_TIME))
There isn't any need to invoke bc.
Finally, starting and stopping perl is likely to take a lot of time, which will add noise to your results. I'd recommend running perl only once, and having perl itself execute the long-running task. You'd then do all the computation within Perl itself as well:
#!/usr/bin/perl
use Time::HiRes qw(time);
my $start = time;
system(#ARGV);
my $end = time;
print "Elapsed: ", ($end - $start), "\n"
Or you could just use the Bash builtin time (or /usr/bin/time) to just do all the timing directly.
If $NOW is outside of quotes, it gets split on whitespace.
$ perl -E'say 0+#ARGV; say for #ARGV' $NOW
7
perl
-e
'use
Time::HiRes
qw(time);
print
time'
You can surround the variable by double-quotes to avoid this:
$ perl -E'say 0+#ARGV; say for #ARGV' "$NOW"
1
perl -e 'use Time::HiRes qw(time); print time'
But you want to execute that string as a shell command. For that, use eval.
$ eval "$NOW"
1335602750.57325
Finally, to assign it, we use the backticks (or equivalent $( ... )).
$ START_TIME=$(eval "$NOW")
$ echo $START_TIME
1335602898.78472
The previously posted function is obviously cleaner, but you said you wanted help with quoting.
By the way,
perl -e 'use Time::HiRes qw(time); print time'
can be shortened to
perl -MTime::HiRes=time -e'print time'
and even to the following (since the trailing new line is perfectly fine):
perl -MTime::HiRes=time -E'say time'
Or if you really wanted to golf:
perl -MTime::HiRes=time -Esay+time
Below is a modified version of your script. You basically need to understand that some applications have their standard output towards standard error (stderr), so when you don't see their output put in a variable, you just need to redirect it to standard output (stdout):
#/bin/sh
CALCULATE='bc'
echo 'starting'
NOW=$(perl -e 'use Time::HiRes qw(time); print time' 2>&1)
sleep 3
echo 'ending'
END_TIME=$(perl -e 'use Time::HiRes qw(time); print time' 2>&1)
ELAPSED_TIME=$(echo "($NOW - $START_TIME)")
echo $ELAPSED_TIME
I think the benefit of HiRes time is negated by the fact that perl is a relatively heavy external process and it is separately invoked two times.
If you don't need that many decimal places for the value. you can use the time builtin in Bash like
task() {
[Some long running task ...]
}
TIMEFORMAT=%R
elapse=$({ time task > task.out 2>&1; } 2>&1)
echo $elapse