Bash / shell error running perl -e 'use [module]': Cannot find line terminator "" anywhere before EOF on -e line 1

I am writing a shell script that must check before running to ensure that Perl system updates do not break the Perl scripts being glued together. I keep getting what looks like a parsing error. To reproduce this on the command line:

$ module='Scalar::Util'; check="perl -e 'use $module' 2>&1"; check_status=`$check`; echo $check
Can't find string terminator "'" anywhere before EOF at -e line 1.
perl -e 'use Scalar::Util' 2>&1

      

Does anyone see what I am doing wrong?

Thank.

+3


source to share


4 answers


Handling arguments with spaces in them like this is trickier at best; try to avoid it.

You should also use more vertical space; "one-liners" is a derogatory term, not a deadline for approval.

You have:

module='Scalar::Util'
check="perl -e 'use $module' 2>&1"
check_status=`$check`
echo $check

      

The problem is when the shell processes:

`$check`

      

it splits the string at word boundaries by calling the arguments:

perl
-e
'use
Scalar::Util'
2>&1

      

Note that I / O redirection is treated as an argument! To avoid the problem, in this context you can use:



module='Scalar::Util'
check="perl -e 'use $module' 2>&1"
check_status=`eval $check`
echo $check

      

eval

forces the shell to re-process the string without getting errors.

Be careful; simple use is eval

not always the solution to these problems. In particular, if you have backslashes, dollars, or backslashes around (or more quotes) then it eval

might just complicate things .

One way to check if a module exists in Perl:

perl -M$module -e "print $module::VERSION . '\n'"

      

This gives the version number of the module (and complicates the string). You can also just do:

perl -M$module -e exit

      

which will exit with status 0 if the module is loaded and spewing errors and so on if it isn't.

$  perl -MSalar::Util -e exit
Can't locate Salar/Util.pm in @INC (@INC contains: /Users/jleffler/Perl/v5.14.1-64/lib/perl5/site_perl/5.14.1/darwin-2level /Users/jleffler/Perl/v5.14.1-64/lib/perl5/site_perl/5.14.1 /Users/jleffler/Perl/v5.14.1-64/lib/perl5/5.14.1/darwin-2level /Users/jleffler/Perl/v5.14.1-64/lib/perl5/5.14.1 .).
BEGIN failed--compilation aborted.
$ echo $?
2
$

      

+9


source


I'm not sure what the shell does, but it works $check

in sh

:

module='Scalar::Util'; check="perl -e 'use $module' 2>&1";echo $check |sh

      



However, it would be much less awkward to use something like Module::Load::Conditional

. You can also use pminst

.

+1


source


Basically, if you put commands in a variable, the shell only parses the string once (i.e. when it expands the variable) and therefore won't process it when the command itself contains shell special characters. In your case, the shell material is '

and 2>&1

. This is why bash is giving you an error. Even if you remove '

with help -m$module

, you will still get errors in2>&1

So, as said above, you need to use eval

or call a subclass ( bash

or sh

) to force parse the variable.

If all you are doing is testing that perl will compile the required module, is that good enough?

module='Scalar::Util'
perl -m$module
ok=$?

      

It ok

will be here 0

if everything is cool or not-0, if there was some mistake. This may not be the right fit for you if the real problem is much more complex than the example posted.

+1


source


The only safe way to do this in bash is to use an array. This will properly support arguments with spaces.

module='Scalar::Util' 
check=(perl -e "use $module")
check_status=$("${check[@]}" 2&>1)   # must use quotes here
status=$?
echo "$status: $check"

      

Note that the stderr / stdout redirection cannot be part of the command array, you must specify it as part of the command, otherwise it is just another string parameter to the perl command.

0


source







All Articles