您的 Perl 风格基于 Perl 4。采用一些更好的做法将使您的 Perl 编写生活更加轻松。首先,快速解决您的问题:
#!/usr/bin/perl -np
use strict;
use warnings;
s{/(\d+\.\d+\.\d+\.\d+)-}{/$1/$1-};
这将匹配您的 4 部分版本字符串,将其捕获并使其成为目录路径中的另一个元素。现在,解决您的脚本并向您展示一些更好的 Perl:
首先,始终始终以use strict; use warnings;
. 这将强制对您的脚本进行更严格的解释,这很好,因为 Perl 通常会假设它知道您想要什么,并尽一切可能避免导致错误。最明显的use strict;
做法是强制词法作用域,这意味着您必须使用my
.
所以你的第一行(之后use strict; use warnings;
)是:
open (FH) or dir ("Could not open the file");
Perl 现在会抱怨一些事情。首先,文件句柄是变量!所以我们需要像这样声明它们my $fh
:坚持使用小写的变量名;它更具可读性。Perl 也不喜欢那个 bareword dir
。我想你的意思是die
,这是一个关键字:
open my $fh or die "Could not open the file";
好的,所以我们消除了一些不必要的括号,使该行更具可读性。但现在该文件永远无法打开。这是因为您没有提供文件名!有很多使用方法open
,但对于大多数用途来说,最好的一种是 3 参数形式。参数是:文件句柄、模式和文件名。在这种情况下,我们要从文件中读取,所以模式是"<"
:
open my $fh, "<", "test.txt" or die "Could not open the file";
现在是指出您可以通过use autodie;
在脚本顶部包含错误处理的好时机。现在您的脚本如下所示:
#!/usr/bin/perl
use strict;
use warnings;
use autodie;
open my $fh, "<", "test.txt";
foreach my $line (<$fh>){
现在,foreach
是 的同义词for
,我更喜欢它,因为它节省了一些输入。$line
被声明为词法(my
),菱形运算符(<>
)现在包围了我们的词法文件句柄$fh
。不幸的是,这会将整个文件拉入内存,这可能会出现问题。如果我们改用while
循环,那么当我们通过循环时,每一行都会被存储、处理和丢弃:
while (my $line = <$fh>) {
($a, $b, $c, $d, $e, $f) = split ('/', $line);
现在看看这个!许多需要词法作用域的变量。一种方法是对所有这些都使用一个my
声明:my ($a, $b, $c, $d, $e, $f)
. 一个更好的主意是注意到我们有一系列相似的项目。这可能会更好地用数组编写:
my @path = split '/', $line;
那里,真好!现在我不确定你为什么决定chomp
下一行;它没有意义,因为你$line
在此之后不使用,所以我们将跳过它。必须修改下一行以使用我们的新@path
变量:
print join(", ", @path), "\n";
使用join
意味着我们不必知道我们将线分成多少个元素。我们还看到(从这个输出)的第四个元素(索引 3)@path
是我们想要匹配的版本字符串的那个,但是正则表达式有点偏离。
if ($path[3] =~ m/^\d.\d.\d.\d-\d+/){
这是寻找由任何字符分隔的一系列单个数字,并在“-”之后跟随更多数字。您的示例显示其中一些应该是多个数字,我们应该匹配文字“。” (句号,句号)而不是正则表达式“。” (任何字符),最后一部分可以是字母(“xn”、“gn”等)。这是一个匹配的正则表达式:
if ($path[3] =~ m/^(\d+\.\d+\.\d+\.\d+)-../){
您会注意到我们添加+
的意思是“一个或多个”并\
转义.
字符。还有一件事,我们添加了分组括号()
来捕获版本字符串,与字符串的其余部分分开,因为这是您想要的目录名称。此捕获将存储在$1
变量中,因此下一行现在是:
my $new_add = $1;
就是这样。显然,您将有更多的工作来完成您的脚本,但希望我已经为您提供了一些工具来改善您的 Perl 体验。如果你想要的只是一个快速的解决方案,那就是在顶部。
如果你想继续用 Perl 编程,我建议你买一本讲授 Perl 5 的书,最好是最近 5 或 6 年写的书。我强烈推荐的一个是Modern Perl,它也可以在线免费获得。