2017-03-18 43 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);