1

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

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

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

另一方面,我试图在 Perl 脚本中使用它system()

system('mv', "$a/$fileName", "$a/${fileName%.*}".'.png');

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

"syntax error near %"它随后抛出"missing right curly or square bracket within string". 错误消息中没有 EOF。

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

4

3 回答 3

4

所以你想替换扩展名——来改变一个文件名。一旦您在 Perl 脚本中,就没有理由为此使用 shell。

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

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

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

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

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

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

use File::Copy qw(move);

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

(如果您注意到内置的重命名,请保持冷静并走过它。请参阅其链接页面了解原因。)


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

use Path::Tiny;

my $path = path($filename);

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

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

该方法以对象parent的形式返回到最后一个组件(文件/目录)的路径Path::Tiny。然后child调用它的方法向它添加另一个组件。

为此,我们得到basename(最后一个组件,在此使用中去掉了扩展名),然后将新的扩展名附加到它上面。瞧,我们得到了替换扩展名的整个路径。这确实会解析路径两次,一次 forparent和一次 for basename

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

$path->move($new_fqn);

完成工作。

模块检查错误,或者抛出它自己的类croaks的异常。


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

use File::Basename;

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

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

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

于 2020-04-29T05:49:40.497 回答
1

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

重击:

"${f%.*}.png"

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

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

重击:

mv

珀尔:

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

使用文件::复制

$ 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
于 2020-04-29T05:44:29.443 回答
0

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

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

你会得到同样的错误。

于 2020-04-29T07:01:05.110 回答