2017-03-18 22 views
2

想在perl准备字符串在bash evaling它像:安全的方式来创建字符串在bash evaling

str="$(perl -E '$sq=chr(047);say qq{var1=${sq}hello world${sq}}')" #this just for demo - the real perl scirpt is ofcourse real complex script ... 
echo "got for eval: [[$str]]" 
eval "$str" 
echo "var1  : [[$var1]]" 

它打印:

got for eval: [[var1='hello world']] 
var1  : [[hello world]] 

或课程的eval是危险的,所以perl脚本需要做一些准备。

的一件事是,在与'"'"'值替换所有'(单引号),这样的分配don't do thisvar时,应打印为

var='don'"'"'t do this' #safe for eval. 

这里有一些更considartions我应该遵循用于准备变量assingnment的Perl脚本(var='some content')字符串安全eval?从我的真实脚本

片段:

#!/usr/bin/env perl 
use strict; 
use warnings; 

sub make_var { 
    my($name, $value) = @_; 
    die "Wrong variable name [$name]" if $name =~ /\W/; 
    my $sval = sanitise($value); 
    #warn qq{$name='$sval'\n}; 
    print qq{$name='$sval'\n}; 
} 

sub sanitise { 
    my $str = shift; 
    $str =~ s/'/'"'"'/gs; 
    # what more i should do here? 
    return $str; 
} 

#usage 
make_var('var1', q{some 
multiline 
value 
where i should'nt miss 
escape the single quotes}); 

打印字符串安全的EVAL。

var1='some 
multiline 
value 
where i should'"'"'nt miss 
escape the single quotes' 

编辑:理由背后:

bash,我需要很多变量,它由perl脚本生成的值。对于一个变量,我可以这样做:

var="$(my_script)" 

但我需要在bash脚本中有很多变量。做

var1="$(my_script some args)" 
var2="$(my_script other args)" 
... 
var10="$(my_script bla bla)" 

是相当昂贵和缓慢。 (perl脚本做了很多事情,最昂贵的是 - 它从网上获取json ...)因此,想要将呼叫数量减少到一个 - 例如需要eval

索姆werid模式进入我的脑海:

';date;':  var2=''"'"';date;'"'"':' # the escaping solves it 
$(date)  var='$(date)'   # safe 
+0

为什么你想EVAL在bash的东西呢? –

+1

您应该编写一个Perl脚本,而不是不断计算值以返回到'bash'脚本。 – chepner

+0

@chepner - 嘿,真的。不幸的是,bash脚本不是我的责任。所以,不能将它彻底改写成perl。 – kobame

回答

5

这是一个可怕的建议。我建议你忘掉eval,而不是编写你的Perl代码,以便它将值返回到空格分隔字符串的stdout。然后你就可以。如果你愿意,你可以阅读到一个数组,而不是

read -r -a vars <<< $(perl -E '...print "val1 val2 val3\n"') 

现值是vars[0]vars[1]vars[2]

如果在bash

read -r var1 var2 var3 rest <<< $(perl -E '...print "val1 val2 val3\n"') 

使用read其拆分值可能包含空格,那么您应该使用不在数据中使用的不同分隔符(如逗号,或冒号:),并设置IFS该字符在读之前

+0

优秀!我根据你的想法创建了一个解决方案。非常感谢你。 – kobame

0

谢谢@Borodin!根据你的想法,我创造了这个解决方案:

perl脚本打印的null terminated线意甲的形式:

<varname><any variable content> 

,所以我有精确定义和正则表达式解析的结构,每一行。

并使用bash的功能打印到变量我不需要按指定的顺序运行read命令。

的bash脚本:

fetch_external_data() { 
    perl p4.pl 
} 

read_data() { 
    regex='^<([a-zA-Z0-9_][a-zA-Z0-9_]*)><(.*)>$' 
    while IFS= read -d '' -r line 
    do 
     if [[ "$line" =~ $regex ]] 
     then 
      printf -v "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" 
     else 
      echo "Ignoring strange line: $line" >&2 
     fi 
    done < <(fetch_external_data) 
} 

read_data 
echo "var1: [[$var1]]";echo 
echo "var2: [[$var2]]";echo 
echo "var3: [[$var3]]";echo 

和perl脚本:

#!/usr/bin/env perl 
use strict; 
use warnings; 
use Getopt::Std; 

our $opt_d; 
getopts('d'); 

sub make_var { 
    my($name, $value) = @_; 
    die "Wrong variable name [$name]" if $name =~ /\W/; 
    return "<$name><$value>" . ($opt_d ? "\n" : "\0"); 
} 

my $all = make_var('var1','hello'); 
$all .= make_var('var2', q{some 
multiline 
value '" bla 
here $(date) "'}); 
$all .= make_var('var3', 'world'); 

binmode(STDOUT); 
print $all; 
0

您可以使用String::ShellQuoteshell_quote任意文本转换成壳文字。

eval "$(
    perl -e' 
     use String::ShellQuote qw(shell_quote); 
     my $str = qq{Some dangerous symbols: \\\x27"!}; 
     my $cmd = "var1=" . shell_quote($str); 
     print($cmd); 
    ' 
)" 
printf "%s\n" "$var1" 

输出:

Some dangerous symbols: \'"! 
0

这是我使用:

sub shellquote1 
{ 
    return $_ 
     unless m([^@%\w:,./=+-]); 
    s/\'/\'\\\'\'/g; 
    return "'$_'"; 
} 

sub shellquote 
{ 
    return join " ", map { shellquote1 } @_; 
} 

print shellquote(@ARGV);