perl中以下语句的含义是什么?
($script = $0) =~ s#^.*/##g;
我试图理解运算符 =~ 以及右侧 s#^.*/##g 的语句。
谢谢
=~
将右侧的事物(模式匹配或搜索和替换)应用于左侧的事物。有很多关于=~
那里的文档,所以我只想为您指出一个非常好的文档。
那里有几个成语不明显,也没有很好的记录,可能会让你绊倒。让我们覆盖它们。
首先是这个...
($copy = $original) =~ s/foo/bar/;
这是一种复制变量并在一个步骤中对其执行搜索和替换的方法。它相当于:
$copy = $original;
$copy =~ s/foo/bar/;
运行左侧代码后,对左侧的=~
任何内容进行操作。 评估为对副本执行的操作。($copy = $original)
$copy
=~
s#^.*/##g
与s/^.*\///g
使用替代定界符以避免倾斜牙签综合症相同。您几乎可以使用任何东西作为正则表达式分隔符。 #
很常见,尽管我认为它丑陋且难以阅读。我更喜欢{}
,因为他们平衡。 s{^.*/}{}g
是等效代码。
展开成语,你有这个:
$script = $0;
$script =~ s{^.*/}{}g;
$0
是脚本的名称。所以这是复制脚本名称并将所有内容剥离到最后一个斜杠(.*
贪婪并且会尽可能匹配)的代码。它只获取脚本的文件名。
/g
表示对字符串执行尽可能多的匹配。由于这只能匹配一次(将其^
锚定到字符串的开头)它没有任何用途。
有一种更好、更安全的方法可以做到这一点。
use File::Basename;
$script = basename($0);
这非常非常简单:
Perl类似引号的表达式可以采用许多不同的字符作为部分分隔符。命令之后的分隔符(在本例中为s
)是其余操作的分隔符。例如:
# Out with the "Old" and "In" with the new
$string =~ s/old/new/;
$string =~ s#old#new#;
$string =~ s(old)(new);
$string =~ s@old@new@;
所有这四种表达方式都是一样的。他们用old
我new
的$string
. 之后的任何s
内容都是分隔符。请注意,括号、花括号和方括号使用配对。这对于q
and qq
which 可以用来代替单引号和双引号非常有效:
print "The value of \$foo is \"foo\"\n"; # A bit hard to read
print qq/The value of \$foo is "$foo"\n/; # Maybe slashes weren't a great choice...
print qq(The value of \$foo is "$foo"\n); # Very nice and clean!
print qq(The value of \$foo is (believe it or not) "$foo"\n); #Still works!
最后一个仍然有效,因为引号之类的运算符计算左括号和右括号。当然,对于正则表达式,括号和方括号是正则表达式语法的一部分,因此您不会在替换中看到太多。
大多数情况下,强烈建议您坚持使用该s/.../.../
表单只是为了便于阅读。这是人们习惯的,而且很容易消化。但是,如果你有这个怎么办?
$bin_dir =~ s/\/home\/([^\/]+)\/bin/\/Users\/$1\bin/;
那些反斜杠会使阅读变得困难,因此传统上一直更换反斜杠分隔符以避免山丘和山谷效应。
$bin_dir =~ s#/home/([^/]+)/bin#/Users/$1/bin#;
这有点难以阅读,但至少我不必引用每个正斜杠和反斜杠,因此更容易看到我要替换的内容。正则表达式很难,因为很难找到好的引号字符。各种特殊符号,如^
、*
、|
和+
是神奇的正则表达式字符,可能出现在正则表达式中,#
是常用的符号。在字符串中不常见,在正则表达式中也没有什么特殊含义,所以不会用到。
回到你原来的问题:
($script = $0) =~ s#^.*/##g;
相当于:
($script = $0) =~ s/^.*\///g;
但是因为最初的程序员不想反引号那个斜线,所以他们改变了分隔符。
至于:
($script = $0) =~ s#^.*/##g;`
这和说的一样:
$script = $0;
$script =~ s#^.*/##g;
您正在分配$script
变量并在一个步骤中进行替换。它在 Perl 中很常见,但一开始有点难以理解。
顺便说一句,如果我理解这个基本表达式(将所有字符删除到最后一个正斜杠。这会更干净:
use File::Basename;
...
$script = basename($0);
更容易阅读和理解——即使对于 Perl 的老手来说也是如此。
在 perl 中,您可以使用多种字符作为引用字符(字符串、正则表达式、列表)。让我们分解一下:
$script
为变量分配内容$0
(包含调用脚本名称的字符串。)=~
字符是绑定运算符。 它调用正则表达式匹配或正则表达式搜索和替换。在这种情况下,它与新变量 匹配$script
。s
字符表示搜索和替换正则表达式。#
字符被用作正则表达式的分隔符。正则表达式模式引号字符通常是/
字符,但您可以使用其他字符,包括#
在这种情况下。^.*/
。这意味着,“在字符串的开头,搜索零个或多个字符,直到出现斜杠。这将继续捕获每一行,但换行符除外(.
默认情况下不匹配。)#
开始。通常,您在这里有一个模式,它使用第一行的任何捕获部分。#
再次。这结束了替换模式。由于替换模式的开始和结束之间没有任何内容,因此在第一个中找到的所有内容都将被替换为任何内容。g
,或全局匹配。搜索和替换将继续发生与值匹配的次数。实际上,搜索并清空 value 中 / 之前的每个值,但保留脚本名称中的所有换行符。当在仅适用于类 unix 路径的长脚本中调用时,这是获取脚本名称的一种非常懒惰的方式。
如果有机会,请考虑用File::Basename
Perl 中的核心模块替换:
use File::Basename;
# later ...
my $script = fileparse($0);