如何在Perl字符串中插值文字\t和\n?

4

假设我有一个环境变量 myvar:

myvar=\tapple\n

当执行以下命令时,将打印出此变量。
perl -e 'print "$ENV{myvar}"'

我有一个字符串 \tapple\n,但是我希望这些控制字符被执行而不是被转义,请问该如何实现?
在实际应用中,$ENV 通常会被替换,但我希望你的回答能够涵盖这种情况。

回到之前的步骤,为什么你的环境变量中会有那些序列? - brian d foy
@brian d foy:因为它们来自文本文件,有多行和格式。 - Pablo
3个回答

3
使用 eval 函数:
perl -e 'print eval qq{"$ENV{myvar}"}' 

更新:您还可以使用带有ee开关的替换,这样更安全:

perl -e '(my $s = $ENV{myvar}) =~ s/(\\n|\\t)/"qq{$1}"/gee; print $s'

2
直接从环境变量中评估代码?听起来像是一个安全风险。 - rjh
这有点冒险,但似乎是迈克尔所需要的答案。 - modz0r
不要这样做。字符串 "eval" 经常意味着您需要学习更多的 Perl。 :) - brian d foy
1
@brian d foy:不完全是。如果您想根据Perl的规则精确评估某些内容,使用eval比手动实现更可靠。另一方面,eval不仅仅是将"\t"转换为Tab字符 - 它还可以删除文件 :) - jrockway
eval 可以在你知道自己在做什么的情况下是正确的,但这并不改变我的陈述。大多数情况下,你仍然会看到一个字符串 eval,这是不正确的,意味着它会按照你想要的方式执行,而不会执行你不想要或不知道的操作。仅仅因为你知道如何正确使用它,并不能否定“大多数”或“经常”的情况。 :) - brian d foy

2
你可能应该使用 String::Escape
use String::Escape qw(unbackslash);

my $var = unbackslash($ENV{'myvar'});

unbackslash可以将任何字符串转义序列解码,使其成为它们所代表的字符。如果你只想显式地转换\n\t,你可能需要自己使用substitution来实现,例如这个答案


1
这里我唯一的担忧是,“unprintable”可能会被翻译成比你所愿意接受的更多的内容。 - brian d foy
那是一个很好的观点。让我想一想... - darch
这个回答听起来与他想做的相反。“我希望那些控制字符被评估而不是转义,”他写道。因此,看起来“unbackslash”是他从该模块中想要的函数。 - jrockway
1
不准确;“unprintable”是评估函数之一。话虽如此,我会采纳你的建议和perldoc的建议,并推荐使用“unbackslash”。 - darch

1

包含反斜杠\的字符序列并没有什么特别之处。如果您想要用另一个字符序列替换它,那么在Perl中实现这一点非常简单:

my %sequences = (
      '\\t' => "\t",
      '\\n' => "\n",
      'foo' => 'bar',
      );

 my $string = '\\tstring fool string\\tfoo\\n';

 print "Before: [$string]\n";
 $string =~ s/\Q$_/$sequences{$_}/g for ( keys %sequences );
 print "After: [$string]\n";

\ 的唯一技巧是要注意 Perl 认为它是转义字符的次数。

Before: [\tstring fool string\tfoo\n]
After: [    string barl string  bar
]

然而,正如darch所指出的那样,你可能只需要使用String::Escape

请注意,在从环境变量中获取值时,你必须非常小心。我不愿意使用String::Escape,因为它可能会处理比你想要转换的更多内容。安全的方法是仅展开你明确想要允许的特定值。请参阅我的《Perl大师》一书中的“安全编程技术”章节,在其中我谈到了这个问题,以及在这种情况下你可能想要使用的污点检查。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接