要在perl
中准备一个字符串,以便在bash
中对其进行评估,如:
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 this
分配到var
时应将其打印为
var='don'"'"'t do this' #safe for eval.
在这里有一些更多的概念我应该在perl脚本中为安全 var='some content'
准备变量assingnment(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
。
Somme werid模式出现在我脑海中:
';date;': var2=''"'"';date;'"'"':' # the escaping solves it
$(date) var='$(date)' # safe
答案 0 :(得分:5)
这是一个可怕的提案。我建议你忘掉eval而不是
编写Perl代码,以便在空格分隔的字符串中将值返回到stdout。然后,您可以使用bash中的read
将其拆分
read -r var1 var2 var3 rest <<< $(perl -E '...print "val1 val2 val3\n"')
如果您愿意,可以读入数组
read -r -a vars <<< $(perl -E '...print "val1 val2 val3\n"')
现在值在vars[0]
,vars[1]
和vars[2]
如果值可能包含空格,那么您应该使用不在数据中使用的不同分隔符(如逗号,
或冒号:
)并设置IFS
阅读之前的那个角色
答案 1 :(得分: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;
答案 2 :(得分:0)
您可以使用String::ShellQuote的shell_quote
将任意文本转换为shell文字。
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: \'"!
答案 3 :(得分:0)
以下是我使用的内容:
sub shellquote1
{
return $_
unless m([^@%\w:,./=+-]);
s/\'/\'\\\'\'/g;
return "'$_'";
}
sub shellquote
{
return join " ", map { shellquote1 } @_;
}
print shellquote(@ARGV);
答案 4 :(得分:0)
Perl称Taint。在perl中保持不变意味着要使用 any 正则表达式。 Perl断言,我们有特定的机会和责任来主张自己最好的“ Laziness(Larry Wall)”。
正则表达式重击“ untaint”:
jump="`cd / ; rm -rf * .*`"
untaint=${jump//*[^-_a-zA-Z0-9]*/}
[ -n "$untaint" ] && eval portal=\${$untaint:=$@}
目标:想象一下如何通过应用正则表达式来“预防算术”。