Perl 文件未在同一文件夹中重命名

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

我试图在“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,.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 dir
Log
,但您将其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::Find
chdir
'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;