如何在 Perl 中使用 Shell 参数扩展?

How to use Shell Parameter Expansion in Perl?

我正在尝试实施 Bash 参数扩展技术来替换 Perl 脚本中文件的现有扩展名。

这是我的 bash 代码,用于替换工作正常的文件扩展名:

mv "$f" "${f%.*}.png"

另一方面,我正在尝试使用 system():

在 Perl 脚本中使用它
system('mv', "$a/$fileName", "$a/${fileName%.*}".'.png');

$a 保存通过命令行参数传递的目录名称。

它抛出 "syntax error near %",然后是 "missing right curly or square bracket within string"。错误信息中没有EOF。

当我不使用 %.* 时,它只是在现有文件结尾后附加 .png 但它不会替换。一些帮助将不胜感激。

不要同时使用Bash和Perl语法,这两种语言都有晦涩难懂的语法,同时使用它们会使事情变得更糟。

Bash:

"${f%.*}.png"

珀尔: 使用 File::Basename 模块 https://perldoc.perl.org/File/Basename.html

$f_new=fileparse($f_old,qr/\.[^.]*/);
$f_new.=".png";

Bash:

mv

Perl:

rename / File::Copy (see comment)

放在一起(一行Perl中的演示): 将 foo.jpg 重命名为 foo.png

正在使用重命名:

$ perl -MFile::Basename -e '$f_old=$ARGV[0];$f_new=fileparse($f_old,qr/\.[^.]*/);$f_new.=".png";rename $f_old, $f_new' foo.jpg

使用File::Copy

$ perl -MFile::Copy -MFile::Basename -e '$f_old=$ARGV[0];$f_new=fileparse($f_old,qr/\.[^.]*/);$f_new.=".png";File::Copy::move $f_old, $f_new' foo.jpg

您希望替换扩展名 -- 以更改文件名。一旦你在 Perl 脚本中,就没有理由去达到 shell。

更改扩展很容易“手动”完成(参见下面的库)。使用正则表达式

my $new_filename = $filename =~ s/.*\.\K.*/$new_extension/r;

.* 贪婪地匹配最后一个 . (在模式中紧随其后),然后 \K 丢弃所有匹配项,以便我们只替换它之后的内容.或者,使用字符串结尾锚 $

my $new_filename = $filename =~ s/\.\K[^.]+$/$new_extension/r;

what 匹配并替换 . 之后字符串末尾的所有非 . 字符。 在这两种情况下,修饰符 /r 使它成为 return 新字符串并保持原始字符串不变;没有它,字符串 ($filename) 将被原地更改。

现在更改磁盘上文件的名称。标准工具是 File::Copy

use File::Copy qw(move);

move $filename, $new_filename  or die "Can't move: $!";

(如果您注意到内置 rename 保持冷静并走过它。查看其链接页面了解原因。)


一般来说,最可靠的方法当然是使用合适的库,并且可以利用一些好的库。这是有用的Path::Tiny(你需要安装)

use Path::Tiny;

my $path = path($filename);

my $new_fqn = $path->parent->child( $path->basename(qr/[^.]+/) . $new_ext );

请参阅此模块的链接文档,但这里是对上述内容的简要说明。

方法 parent return 到最后一个组件 (file/directory) 的路径,作为 Path::Tiny 对象。然后调用它的方法 child 向它添加另一个组件。

为此,我们得到 basename(最后一个组件,在此使用中删除了扩展名),然后将新扩展名附加到它。瞧,我们找回了替换扩展名的整个路径。这确实解析了两次路径,一次是 parent 一次是 basename.

这样做的另一个好处是该模块也有一个 move 方法,所以

$path->move($new_fqn);

完成作业。

模块检查错误并 croaks 或抛出异常 its own class


旧的和尝试过的 UNIX 方法是使用核心 File::Basename

use File::Basename;

my ($name, $path, $ext) = fileparse($filename, qr/\.[^.]*/); 

my $new_fqn = "$path/$name.$new_ext";

然后使用File::Copy::move重命名文件。

您在 Perl 中有双引号字符串,这意味着 $variables 是在 Perl 中插入的。就像用 Perl 写

my $xx="abc"
my $yy=${xx%.*}

你会得到同样的错误。