在这段代码中,我解析了一个文件(包含ls -lrt
的输出),以获取日志文件的修改日期。然后我将所有日志文件移动到一个新文件夹中,并将其修改日期添加到文件名中,而不是制作所有这些文件的tar。
我遇到的问题是在while
循环中。因为它正在读取所有文件的数据,所以while循环继续运行15次。我知道代码中存在一些问题,但我无法弄明白。
在while循环中,我将分割ls -lrt
条记录以查找日志文件修改日期。 $file
是ls
命令的输出,我将其存储在文本文件/scripts/yagya.txt
中以获取修改日期。但是while
循环执行了15次,因为文件夹中有15个与模式匹配的日志文件。
#!/usr/bin/perl
use File::Find;
use strict;
my @field;
my $filenew;
my $date;
my $file = `ls -lrt /scripts/*log*`;
my $directory="/scripts/*.log";
my $current = localtime;
my $current_time = $current;
$current_time = s/\s+//g;
my $freetime = $current_time;
my $daytime = substr($current_time,0,8);
my $seconddir = "/$freetime/";
system ("mkdir $seconddir");
open (MYFILE,">/scripts/yagya.txt");
print MYFILE "$file";
close (MYFILE);
my $data = "/scripts/yagya.txt";
my $datas = "/scripts/";
my %options = (
wanted => \&wanted,
untaint => 1
);
find (\%options, $datas);
sub wanted {
if (/[._]log\d*$/){
my $files;
my @fields;
my $fields;
chomp;
$files=$_;
open (MYFILE,$data);
while(<MYFILE>){
chop;
s/#.*//;
next unless /\S/;
@fields = (split)[5,6,7];
$fields = join('',@fields), "\n";
}
close (MYFILE);
system ("mv $files $seconddir$fields$files");
}
}
system ("tar cvf /$daytime/$daytime.tar.gz /$daytime/*log*");
system ("rm $seconddir*log*");
system ("rm $data");
答案 0 :(得分:3)
您的代码很难阅读。在您开始测试之前,您似乎已将程序编写为单个大块。这种工作方式很常见,但非常错误。您应该首先实现程序的一小部分并在添加更多功能之前进行测试,再次测试,等等。这样你就不会在一个未经测试的大型程序中同时修复许多问题而不知所措。
如果您将use warnings
添加到程序顶部的use strict
,这对您也有很大帮助。它有助于捕捉您可能忽略的简单错误。
另外,您是否知道File::Find
每次遇到文件时都会调用您的wanted
回调子程序?它不会立即传递所有文件。
当您找到与yagya.txt
找到的当前文件匹配的记录时,当您应该停止时,问题似乎是您正在读取File::Find
文件的所有内容。您需要做的是检查ls
输出中的当前记录是否以当前文件的名称结尾。如果你像这样编写循环
while (<MYFILE>) {
if (/\Q$files\E$/) {
my @fields = (split)[5,6,7];
$fields = join('',@fields);
last;
}
}
然后$fields
将以当前文件的修改日期结束,这就是你想要的。
但如果您使用Perl为您阅读文件修改日期,这将容易一千倍。
不是将ls
列表写入文件并将其读回,而应该执行类似的操作
use File::stat;
my $mtime = localtime(stat($files)->mtime);
会给你一个像Wed Jun 13 11:25:23 2012
这样的字符串。我ls
输出中的日期仅包括月份名称,月份日期和时间,例如Jun 8 12:37
。这不是非常具体,你或许应该至少包括一年,但要从这个$mtime
生成相同的字符串,你可以写
my $fields = join '', (split ' ', $mtime)[1,2,3];
关于你的节目还有很多我可以说的,但我希望现在能让它适合你。
我注意到的另外几件事:
行$current_time = s/\s+//g
应为$current_time =~ s/\s+//g
以从当前时间字符串中删除所有空格
Sun Jun 3 11:50:54 2012
之类的值将减少为SunJun311:53:552012
,然后$daytime
将采用不正确的值SunJun31
答案 1 :(得分:1)
我通常不建议使用bash而不是perl,但有时它会更短
这个问题有两部分:
表示1。)
find ./scripts -name \*[_.]log\* -type f -printf "%p\0./logs/%TY%Tm%Td-%TH%Tk%TM-%f\0" | xargs -0 -L 2 mv
上面将找到名称中包含[_。]日志的所有普通文件,并将它们重命名为带有时间戳前缀的./logs
目录。 e.g。
./scripts/aaa.log12 get renamed into ./logs/20120403-102233-aaa.log12
2。)归档
ls logs | sed 's/\(........-....\).*/\1/' | sort -u | while read groupby
do
( cd logs && echo tar cvzf ../$groupby.tgz $groupby* )
done
这将通过timestamp-prefix创建tar存档。 (假设./logs
仅包含具有有效(带时间戳)文件名的文件)
当然,上面的sed模式并不好,但清楚地显示从时间戳中删除seconds
- 因此它按分钟创建存档。如果想要其他分组,您可以使用:
sed 's/\(........-..\).*/\1/' - by hours
sed 's/\(........\).*/\1/' - by days
其他:
-printf
查找 - Linux中常见的/scripts
,因此我的示例使用./