このコードは、カーゴカルト プログラミングに少し似ています。つまり、これが何をしているかを理解していることを示すことなく、いくつかの構成要素がここにあります。
chdir('C:\\doc\\logs');
my $dir_01 = getcwd;
Windows のパス名であっても、スラッシュを使用してください。これは一般的にサポートされています。
あなたのディレクトリ図は、トップ dir があることを示してLog
いますが、chdir に移動しC:/doc/logs
ます。それは何ですか?
これ$dir_01
は非常にわかりにくい名前であり、chdir したばかりのパスであることに気付きましたか? また、File::Find
作業ディレクトリで開始する必要はありません。つまり、chdir
ここでは少し役に立ちません。あなたは実際に欲しい:
my $start_directory = "C:/doc/Log"; # or whatever
my $all_file=find ({ 'wanted' => \&renamefile }, $dir_01);
find
の戻り値が何を意味するのかわかりません。しかし、それを未使用の変数に入れる必要はないと確信しています。
太いコンマでキー名を提供する場合=>
、これらのキーを手動で引用する必要はありません。したがって:
find({ wanted => \&renamefile }, $start_directory);
/.txt?/
この正規表現は次のことを行います。
- 任意の文字 (改行ではない) に一致します。
- その後にリテラル
tx
、
- オプションで a
t
. the?
は 0 または 1 の量指定子です。
で終わるファイル名を一致させたい場合は.txt
、次のようにする必要があります
/\.txt$/
は\.
文字どおりのピリオドに一致します。文字列の$
末尾に正規表現を固定します。
my @files = $_;
foreach my $file (@files) {
...;
}
これは通常、次のように記述されます。
my $file = $_;
...;
の値を配列に代入する$_
と、配列には1 つの要素 (コンテンツ) が含まれます。次に、この1 つの要素をループします。このようなループは、ループと呼ぶに値しません。@files
$_
open (FILE,"<" ,$file) or die"Can not open the file";
my @lines = <FILE>;
close FILE;
for my $line ( @lines )
{ ... }
ああ、どこから始めますか?
ファイル ハンドルにはレキシカル変数を使用します。これらには、自分自身を閉じるという優れた特性があります。
エラー処理については、use autodie
. 本当に自分でやりたい場合は、エラー メッセージに次の 2 つの重要な情報が含まれている必要があります。
- 開けなかったファイルの名前 (
$file
)
- オープンに失敗した理由 (
$!
)
のような意味になり... or die "Can't open $file: $!"
ます。
ファイル全体を配列に読み取って、それをループしないでください。代わりに、 -like ループを使用して、メモリ効率を高め、行を反復処理します。while(<>)
これは一度に 1 行しか読み取れないため、はるかに優れています。
組み合わせるとこんな感じ
use autodie; # at the top
open my $fh, "<", $file;
LINE: while (<$fh>) {
...; # no $line variable, let's use $_ instead
}
LINE
ああ、あとで参照できるように、ループに ( を付けて) ラベルを付けました。
if($line=~ /Linux kernel Version/gi || $line=~ /USB_STATE=DISCONNECTED/gi) { ... }
フラグを正規表現に置くと、/g
正規表現が反復子になります。あなたは本当にそれを望んでいません。そして、大文字と小文字を区別しないマッチングが本当に必要かどうかはよくわかりません。||
正規表現の代替を使用して、またはを正規表現に移動できます|
。行を含めるために使用するようになっ$_
たため、正規表現を文字列に手動でバインドする必要はありません。したがって、次のように書くことができます。
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.
デフォルトでは、元$_
の 、したがって私たち$file
の にはファイル名のみが含まれ、ディレクトリは含まれません。これは問題ではありません: File::Findchdir
は正しいディレクトリに移動します。これにより、処理がはるかに簡単になります。ディレクトリが必要な場合は、$File::Find::dir
変数を使用します。
my $new_file_name = $file_name;
$new_file_name =~ s/.* /Kernal.txt/g;
/.* /
正規表現は次のように述べています。
- 最後のスペースを含めて何にでもマッチ
- これが一致する場合は、一致した部分を に置き換え
Kernal.txt
ます。
ここ/g
ではフラグはまったく役に立ちません。eKernel.txt
を使いたくないですか?そして、なぜファイル名にスペースがあるのですか? よくわかりません。ファイルの名前を に変更したい場合は、置換で奇妙なことをする代わりに、それを文字列として割り当てるだけです: Kernel.txt
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;
それで十分なはずです。また、 LINEループを離れることに注意してください。ファイルの名前を変更したら、他の行も確認する必要はありません。