Perl行使用单引号比使用双引号快30倍

Ada*_*dam 6 linux bash perl

我们有一项任务是将二进制文件中的某些字符串更改为小写(来自mixed/upper/whatever).相关的字符串是对其他文件的引用(它与升级相关,我们也将Windows作为服务器环境从Windows迁移到Linux,因此案例突然变得很重要).我们编写了一个使用perl循环执行此操作的脚本.我们有一个包含大约300个文件的目录(目录的总大小约为150M)所以它是一些数据但不是很大的数量.

以下perl代码大约需要6分钟才能完成工作:

for file_ref in `ls -1F $forms6_convert_dir/ | grep -v "/" | sed 's/\(.*\)\..*/\1/'` 
do
    (( updated++ ))
    write_line "Converting case of string: $file_ref "
    perl -i -pe "s{(?i)$file_ref}{$file_ref}g" $forms6_convert_dir/* 
done
Run Code Online (Sandbox Code Playgroud)

而以下perl代码需要3个小时!

for file_ref in `ls -1F $forms6_convert_dir/ | grep -v "/" | sed 's/\(.*\)\..*/\1/'` 
do
    (( updated++ ))
    write_line "Converting case of string: $file_ref "
    perl -i -pe 's{(?i)$file_ref}{$file_ref}g' $forms6_convert_dir/* 
done
Run Code Online (Sandbox Code Playgroud)

有谁能解释为什么?这是$ file_ref是否作为字符串$ file_ref而不是用单引号版本中的值替换?在这种情况下,在这个版本中它取代了什么?我们想要的是用自己替换任何文件名的所有出现但是小写.如果我们在文件之前和之后运行字符串并搜索文件名,那么两者似乎都做了相同的更改.但是,如果我们对两个循环(diff firstloop/file1 secondloop/file1)生成的文件运行diff,那么它会报告它们不同.

这是在linux上的bash脚本中运行的.

Kar*_*ath 17

shell不对单引号字符串进行变量替换.所以,第二个是不同的程序.


cjm*_*cjm 4

正如其他答案所说,shell 不会替换单引号内的变量,因此第二个版本正在s{(?i)$file_ref}{$file_ref}g为每个文件中的每一行执行文字 Perl 语句。

正如您在评论中所说, if$是行尾元字符,$file_ref永远无法匹配任何内容。 $在行尾的换行符之前匹配,因此下一个字符必须是换行符。因此,Perl 不解释$为元字符;而是将其解释为元字符。它将其解释为变量插值的开始。

在 Perl 中,变量$file_refundef,插值时被视为空字符串。所以你实际上是在执行s{(?i)}{}g,它表示用空字符串替换空字符串,并以不区分大小写的方式对所有出现的情况执行此操作。好吧,每对字符之间都有一个空字符串,并且每行的开头和结尾都有一个空字符串。Perl 正在查找每一个并将其替换为空字符串。这是一项无操作,但成本高昂,因此需要 3 小时的运行时间。

您肯定误认为两个版本都进行了相同的更改。正如我刚才所解释的,单引号版本只是一个昂贵的无操作;它根本不对文件内容进行任何更改(它只是为每个文件创建一个新副本)。您运行它的文件必须已经转换为小写。