如何在 Perl 替换运算符的替换端使用变量?
我想做以下事情:
$find = "start (.*) end";
$replace = "foo \1 bar";
$var = "start middle end";
$var =~ s/$find/$replace/;
我希望 $var 包含“foo middle bar”,但它不起作用。也不:
$replace = 'foo \1 bar';
不知怎的,我错过了一些关于逃跑的事情。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
在替换方面,您必须使用 $1,而不是 \1。
你只能通过替换一个可评估的表达式来完成你想要的操作,该表达式给出你想要的结果,并告诉 s/// 使用 /ee 修饰符评估它,如下所示:
要了解为什么需要“”和双 /e,在这里查看双重 eval 的效果:(
尽管正如 ikegami 所说,单个 /e 或双 e 的第一个 /e 并不是真正的
eval()
;相反,它告诉编译器尽管如此,eval(eval(...))
仍然说明了为什么您需要做您需要做的事情才能让 /ee 按需要工作。 .)On the replacement side, you must use $1, not \1.
And you can only do what you want by making replace an evalable expression that gives the result you want and telling s/// to eval it with the /ee modifier like so:
To see why the "" and double /e are needed, see the effect of the double eval here:
(Though as ikegami notes, a single /e or the first /e of a double e isn't really an
eval()
; rather, it tells the compiler that the substitution is code to compile, not a string. Nonetheless,eval(eval(...))
still demonstrates why you need to do what you need to do to get /ee to work as desired.)Deparse 告诉我们这就是正在执行的内容:
然而,
被解释为:
不幸的是,似乎没有简单的方法可以做到这一点。
您可以使用字符串 eval 来完成此操作,但这很危险。
对我来说最明智的解决方案是:
对 ee 技术的反驳:
正如我在回答中所说,我避免评估是有原因的。
这段代码的作用完全符合您的想法。
如果您的替换字符串位于 Web 应用程序中,那么您就打开了执行任意代码的大门。
好工作。
此外,由于这个原因,它不会在污点打开的情况下工作。
然而,更谨慎的技术是明智的、安全的、可靠的,并且不会失败。 (不过请放心,它发出的字符串仍然受到污染,因此您不会失去任何安全性。)
Deparse tells us this is what is being executed:
However,
Is interpreted as :
Unfortunately it appears there is no easy way to do this.
You can do it with a string eval, but thats dangerous.
The most sane solution that works for me was this:
A rebuttal against the ee technique:
As I said in my answer, I avoid evals for a reason.
this code does exactly what you think it does.
If your substitution string is in a web application, you just opened the door to arbitrary code execution.
Good Job.
Also, it WON'T work with taints turned on for this very reason.
However, the more careful technique is sane, safe, secure, and doesn't fail taint. ( Be assured tho, the string it emits is still tainted, so you don't lose any security. )
正如其他人所建议的,您可以使用以下内容:
上面是以下内容的缩写:
我更喜欢第二个而不是第一个,因为它没有隐藏
eval(EXPR)
。然而,上面的两个静默错误,所以下面的会更好:但正如你所看到的,以上所有都允许执行任意 Perl 代码。以下内容会更安全:
As others have suggested, you could use the following:
The above is short for the following:
I prefer the second to the first since it doesn't hide the fact that
eval(EXPR)
is used. However, both of the above silence errors, so the following would be better:But as you can see, all of the above allow for the execution of arbitrary Perl code. The following would be far safer:
不过要小心。这会导致发生两层
eval
,一层对应正则表达式末尾的每个e
:Be careful, though. This causes two layers of
eval
to occur, one for eache
at the end of the regex:我会建议这样的内容:
它很有可读性,而且似乎很安全。如果需要多次替换,很简单:
I would suggest something like:
It is quite readable and seems to be safe. If multiple replace is needed, it is easy:
这让我得到了“1234”。
This got me the '1234'.
请参阅这个 上一篇关于在 Perl 中的
s///
替换端使用变量的文章。查看 接受的答案和反驳答案。您尝试做的事情可以使用
s///ee
形式来实现,该形式在右侧字符串上执行双重eval
。有关更多示例,请参阅 perlop 引用运算符。请注意,
eval
存在安全隐患,并且这在污点模式下不起作用。See THIS previous SO post on using a variable on the replacement side of
s///
in Perl. Look both at the accepted answer and the rebuttal answer.What you are trying to do is possible with the
s///ee
form that performs a doubleeval
on the right hand string. See perlop quote like operators for more examples.Be warned that there are security impilcations of
eval
and this will not work in taint mode.我没能让最受欢迎的答案发挥作用。
我尝试使用普通的旧式 eval 提出自己的解决方案:
当然,这允许代码注入。但据我所知,逃避正则表达式查询和注入代码的唯一方法是在 $find 中插入两个正斜杠或在 $replace 中插入一个正斜杠,后跟一个分号,之后可以添加添加代码。例如,如果我这样设置变量:
评估的代码是这样的:
那么我要做的就是确保字符串不包含任何未转义正斜杠。
首先,我将字符串复制到虚拟字符串中。
然后,我从虚拟字符串中删除所有转义的反斜杠(反斜杠对)。这使我能够找到未转义的正斜杠,而不会陷入如果前面有转义的反斜杠则认为正斜杠已转义的陷阱。例如:
\/
包含转义的正斜杠,但\\/
包含文字正斜杠,因为反斜杠已转义。现在,如果字符串中保留有任何前面没有反斜杠的正斜杠,我会抛出一个致命错误,因为这将允许用户插入任意代码。
然后我评估。
我不是防止代码注入的专家,但我是唯一使用我的脚本的人,所以我很满意使用这个解决方案,但不完全知道它是否容易受到攻击。但据我所知,可能是这样,所以如果有人知道是否有任何方法可以将代码注入其中,请在评论中提供您的见解。
I did not manage to make the most popular answers work.
I attempted to come up with a solution of my own using plain old eval:
Of course, this allows for code injection. But as far as I know, the only way to escape the regex query and inject code is to insert two forward slashes in $find or one in $replace, followed by a semi-colon, after which you can add add code. For example, if I set the variables this way:
The evaluated code is this:
So what I do is make sure the strings don't contain any unescaped forward slashes.
First, I copy the strings into dummy strings.
Then, I remove all escaped backslashes (backslash pairs) from the dummy strings. This allows me to find forward slashes that are not escaped, without falling into the trap of considering a forward slash escaped if it's preceded by an escaped backslash. For example:
\/
contains an escaped forward slash, but\\/
contains a literal forward slash, because the backslash is escaped.Now if any forward slash that is not preceded by a backslash remains in the strings, I throw a fatal error, as that would allow the user to insert arbitrary code.
Then I eval.
I'm not an expert at preventing code injection, but I'm the only one using my script, so I'm content using this solution without fully knowing if it's vulnerable. But as far as I know, it may be, so if anyone knows if there is or isn't any way to inject code into this, please provide your insight in a comment.
我不确定你想要实现什么目标。但也许你可以使用这个:
即只保留中间部分并替换开始和结束。
I'm not certain on what it is you're trying to achieve. But maybe you can use this:
I.e. just leave the middle alone and replace the start and end.