我不确定如何从 Perl 中搜索和替换单词。

我有.txt包含随机顺序图像文件名的文件。

Animals.txt

There is an image Dog_Image_85.jpg
Cat has an image Cat_Image_front.jpg
Here is another image Dog_Image_61.jpg
Cat has another image Cat_Image_back.jpg
Next image Dog_Image_55.jpg
Next Image Cat_Image_side.jpg
Next Image Dog_Image_200.jpg

我只想将狗图像名称更改为计数器,因此:

There is an image Dog_Image_1.jpg
Cat has an image Cat_Image_front.jpg
Here is another image Dog_Image_2.jpg
Cat has another image Cat_Image_back.jpg
Next image Dog_Image_3.jpg
Next Image Cat_Image_side.jpg
Next Image Dog_Image_4.jpg

我尝试过这些但每次都出现错误:

#!/usr/local/bin/perl -w -I ../lib -I ./

use strict;

my $Animals = "Animals";

my $file = "$Animals.txt";

perl -pi -e 's/Dog_Image_.*.jpg/"Dog_Image_.++$i.jpg"/ge' $file;

这给了我一个错误:Can't use bareword perl

我也尝试过:

system('s/Dog_Image_.*.jpg/"Dog_Image_.++$i.jpg"/ge' $file);'

但仍然会出现错误。

5

  • "替换字符串中有一个不匹配的内容。


    – 

  • 3
    您不能perl在另一个 perl 脚本中使用该语句,那是一个 shell 命令。


    – 

  • 2
    同样,您不能将 Perl 替换作为 shell 命令运行。


    – 

  • @barmar 我打字时漏掉了“。仍然出现错误。


    – 

  • 我认为不.++$i应该放在引号里。应该是"Dog_Image_" . ++i . ".jpg"


    – 


最佳答案
3

看起来您正试图运行一个 shell 命令,该命令将调用perl来运行 Perl 命令行程序(“单行程序”),该程序来自 Perl 脚本。这当然是可能的,但它是一种复杂的、通常被称为“饥饿”的杂技。为什么不在那个 Perl 脚本中完成这项工作呢?

这是一种方法,使用有用的

use warnings;
use strict;
use feature 'say';

use Path::Tiny;

my $file_name = ...
...

{
    my $dog_cnt = 0;
    path($file_name) -> edit( sub { 
        s/Dog_Image_\K([0-9]+)\.jpg/++$dog_cnt . '.jpg'/ge 
    });
}

该方法edit对被提取到的文件内容运行回调中的代码$_,然后覆盖该文件。 还有edit_lines将给定代码一次应用于一行的。这些行为都不完全像-i命令行中的,但这不是缺点。

我将代码放在一个{}块中以定位该$dog_cnt计数器。另一种选择是在回调中定义该变量,特别是当周围的代码不需要计数器时。

sub {
    my $dog_cnt = 0;
    s/Dog_Image_\K([0-9]+)\.jpg/++$dog_cnt . '.jpg'/ge 
}

那么该方法edit_lines将不适用于现有的代码,因为回调会针对每一行运行,因此计数器始终被重新定义为零。请根据需要进行更改。


或者,正常编辑文件 – 打开、逐行处理、以您选择的方式覆盖原始文件,之后进行您想要的任何检查。代码不多,只有几行。它比从脚本中运行复杂的 shell 命令好得多。更不用说运行命令perl行程序了。


该库没有说明它如何“覆盖”文件,但在我的测试中,inode 编号发生了变化,因此它会写出一个包含更改内容的文件,然后在原始文件上重命名。

如果 inode 编号需要保持不变(有时文件上使用的工具需要这样做),则可以通过照常打开和处理文件来更改文件,并将新版本写入临时文件或将其保存在内存中。

然后打开原始文件进行写入(这会截断它)并将新内容写入其中(从临时文件或内存中,无论您将其存放在何处)。现在原始文件的内容已更改,但文件的 inode 编号未更改。如果有临时文件,请将其删除。

0

以下是在命令行上执行此操作的一种方法(这在我的 shell 中有效):

perl -pi -e 's/Dog_Image_.*.jpg/"Dog_Image_" . ++$i . ".jpg"/e' Animals.txt

它会覆盖原始文件。

引用至关重要。关键是将固定字符串与替换侧的执行代码分开。我使用.字符串连接运算符来实现这一点。

您的尝试存在很多问题。您将命令行 Perl 与文件中的 Perl 代码混合在一起。

3

  • 1
    nit:这不会覆盖原始文件。它会创建一个新文件并重命名,然后取消链接原始名称。这有时是一个微妙的区别,但有时却极其重要。


    – 

  • 这在 shell 中对我有用,但在我的 perl 脚本中却不行,是否有特定的方法可以格式化它以使其在脚本中工作?


    – 

  • @TreyB 只需使用while(<>)循环。实现 有点棘手-i,但你真的、真的、真的不想这样做。编写你的工具作为简单的过滤器并处理 shell 中的重命名。


    – 

"Dog_Image_.++$i.jpg"不是有效的 Perl 代码。"Dog_Image_" . ++$i . ".jpg"将是。

但您还有许多其他错误。已修复:

#!/usr/bin/perl

use strict;
use warnings;

exec( "perl", "-i", "-pe" 's/Dog_Image_\K.*(?=\.jpg$)/++$i/se', "Animals.txt" );

切换到 shell 脚本更简单。

#!/usr/bin/sh

exec perl -i -pe's/Dog_Image_\K.*(?=\.jpg$)/++$i/se' Animals.txt