Perl 文件未在同一文件夹中重命名
我试图在“Linux内核版本”或“USB_STATE=DISCONNECTED”的基础上用Kernel.txt重命名现有文件名。脚本正在运行,没有任何错误,但没有输出。更改的文件需要与以前的文件位于同一文件夹(F1、F2、F3)中Perl 文件未在同一文件夹中重命名,perl,Perl,我试图在“Linux内核版本”或“USB_STATE=DISCONNECTED”的基础上用Kernel.txt重命名现有文件名。脚本正在运行,没有任何错误,但没有输出。更改的文件需要与以前的文件位于同一文件夹(F1、F2、F3)中 Top dir: Log SubDir: F1,F2,F3 F1: .bin file,.txt file,.jpg file F2: .bin file,.txt file,.jpg file F3: .bin file,.txt file
Top dir: Log
SubDir: F1,F2,F3
F1: .bin file,.txt file,.jpg file
F2: .bin file,.txt file,.jpg file
F3: .bin file,.txt file,.jpg file
#!/usr/bin/perl
use strict;
use warnings;
use File::Find;
use File::Basename;
use File::Spec;
use Cwd;
chdir('C:\\doc\\logs');
my $dir_01 = getcwd;
my $all_file=find ({ 'wanted' => \&renamefile }, $dir_01);
sub renamefile
{
if ( -f and /.txt?/ )
{
my @files = $_;
foreach my $file (@files)
{
open (FILE,"<" ,$file) or die"Can not open the file";
my @lines = <FILE>;
close FILE;
for my $line ( @lines )
{
if($line=~ /Linux kernel Version/gi || $line=~ /USB_STATE=DISCONNECTED/gi)
{
my $dirname = dirname($file); # file's directory, so we rename only the file itself.
my $file_name = basename($file); # File name fore renaming.
my $new_file_name = $file_name;
$new_file_name =~ s/.* /Kernal.txt/g; # replace the name with Kernal.txt
rename($file, File::Spec->catfile($dirname, $new_file_name)) or die $!;
}
}
}
}
}
Top目录:日志
细分:F1、F2、F3
F1:.bin文件、.txt文件、.jpg文件
F2:.bin文件、.txt文件、.jpg文件
F3:.bin文件、.txt文件、.jpg文件
#!/usr/bin/perl
严格使用;
使用警告;
使用File::Find;
使用File::Basename;
使用File::Spec;
使用化学武器;
chdir('C:\\doc\\logs');
my$dir_01=getcwd;
我的$all\u file=find({'wanted'=>\&renamefile},$dir\u 01);
子重命名文件
{
如果(-f和/.txt?/)
{
my@files=$\uU4;
foreach my$文件(@files)
{
open(FILE),这段代码看起来有点像cargo cult编程。也就是说,这里的一些构造没有表明您理解这是在做什么
帮你自己一个忙,使用前斜杠,即使是Windows路径名。这通常是受支持的
您的目录图上显示有一个top dirLog
,但您将其chdir到C:/doc/logs
。它是什么
您确实意识到,$dir\u 01
是一个非常不可描述的名称,并且是您刚才chdir要到达的路径?而且,File::Find
不要求您从工作目录开始。也就是说,chdir
在这里有点无用。您实际上想要:
my $start_directory = "C:/doc/Log"; # or whatever
我不确定find
的返回值是什么意思,但我确信我们不必把它放入一些未使用的变量中
当我们使用=>
胖逗号提供键名时,我们不必手动引用这些键。因此:
find({ wanted => \&renamefile }, $start_directory);
此正则表达式执行以下操作:
- 匹配任何字符(不是换行符)
- 后跟文字
tx
- 和可选的
t
。?
是零或一个量词
如果要匹配以.txt
结尾的文件名,应该这样做
/\.txt$/
\.
匹配一个文字句点。$
将正则表达式锚定在字符串的末尾
这通常写为
my $file = $_;
...;
您将$\uu0
的值分配给@files
数组,该数组有一个元素:$\u0
内容。然后在这一个元素上循环。这样的循环不值得称为循环
哦,我给循环贴上了标签(用行
)以供以后参考
将/g
标志放在正则表达式上会将它们变成迭代器。你真的不想这样。我不确定是否真的需要不区分大小写的匹配。你可以将|
移动到正则表达式中,使用正则表达式替换|
。因为我们现在使用$
来包含行,我们不需要每年将正则表达式绑定到字符串。因此,我们可以编写:
if (/Linux Kernel Version|USB_STATE=DISCONNECTED/i) { ... }
默认情况下,原始的$\uuu
,因此我们的$文件
,只包含文件名,而不包含目录。这不是问题:file::Findchdir
'd进入正确的目录。这使我们的处理变得容易得多。如果您想要拥有目录,请使用$file::Find::dir
变量
/.*/
正则表达式说:
- 匹配包括最后一个空格在内的任何内容
- 如果匹配,则将匹配的部分替换为
Kernal.txt
/g
标志在这里是完全无用的。你确定你不希望Kernel.txt
带有e吗?为什么文件名中有空格?我不太明白。如果你想将文件重命名为Kernel.txt
,只需将其作为字符串分配,而不是用奇怪的替换:
my $new_file_name = "Kernel.txt";
我们已经确定错误消息还应该包括文件名,甚至更好:我们应该使用自动错误处理
此外,我们已经在正确的目录中,因此不必将新名称与目录连接起来
rename $file => $new_file_name; # error handling by autodie
last LINE;
这应该足够了。还要注意,我离开了行循环。一旦我们重命名了文件,就不需要再检查其他行了。谢谢你这么好的解释。这将在将来给我很大的帮助。在这里,我有一个疑问,如果不关闭$fh,我们是否可以重命名文件。事实上,我尝试过,但出现了错误。@Maverick是的,some操作系统(我认为像Windows)重命名前确实需要关闭文件句柄。但这并不困难,只需在重命名之前粘贴一个明确的close$fh;
。最后一个问题。如果我想处理多个文件,我指的是不同的文件,那么同样的事情也可以做到。文件::查找在第一次重命名后不会停止ode>。在重命名文件
中,您还可以自由测试其他条件。
my $file = $_;
...;
open (FILE,"<" ,$file) or die"Can not open the file";
my @lines = <FILE>;
close FILE;
for my $line ( @lines )
{ ... }
use autodie; # at the top
open my $fh, "<", $file;
LINE: while (<$fh>) {
...; # no $line variable, let's use $_ instead
}
if($line=~ /Linux kernel Version/gi || $line=~ /USB_STATE=DISCONNECTED/gi) { ... }
if (/Linux Kernel Version|USB_STATE=DISCONNECTED/i) { ... }
my $dirname = dirname($file); # file's directory, so we rename only the file itself.
my $file_name = basename($file); # File name fore renaming.
my $new_file_name = $file_name;
$new_file_name =~ s/.* /Kernal.txt/g;
my $new_file_name = "Kernel.txt";
rename($file, File::Spec->catfile($dirname, $new_file_name)) or die $!;
rename $file => $new_file_name; # error handling by autodie
last LINE;