perlfaq5の回答から、ファイルの行を変更、削除、挿入したり、ファイルの先頭に追加したりするにはどうすればよいですか?
ファイルの行を変更、削除、挿入したり、ファイルの先頭に追加したりするにはどうすればよいですか?
(brian d foyによる寄稿)
テキストファイルから行を挿入、変更、または削除する基本的な考え方は、変更を加えたいポイントまでファイルを読み取って印刷し、変更を加えてから、ファイルの残りの部分を読み取って印刷することです。Tie :: Fileなどのモジュールはそれを偽造することができますが、Perlは行へのランダムアクセスを提供しません(特にレコード入力セパレーター$ /は可変であるため)。
これらのタスクを実行するPerlプログラムは、ファイルを開き、その行を印刷してからファイルを閉じるという基本的な形式を取ります。
open my $in, '<', $file or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";
while( <$in> )
{
print $out $_;
}
close $out;
その基本的なフォーム内に、行を挿入、変更、または削除するために必要な部分を追加します。
行を先頭に追加するには、既存の行を印刷するループに入る前に、それらの行を印刷します。
open my $in, '<', $file or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";
print $out "# Add this line to the top\n"; # <--- HERE'S THE MAGIC
while( <$in> )
{
print $out $_;
}
close $out;
既存の行を変更するには、whileループ内の行を変更するコードを挿入します。この場合、コードは「perl」のすべての小文字バージョンを検索し、それらを大文字にします。すべての行で発生するため、すべての行でそれを実行することになっていることを確認してください。
open my $in, '<', $file or die "Can't read old file: $!";
open my $out, '>', "$file.new" or die "Can't write new file: $!";
print $out "# Add this line to the top\n";
while( <$in> )
{
s/\b(perl)\b/Perl/g;
print $out $_;
}
close $out;
特定の行のみを変更するには、入力行番号$。が役立ちます。まず、変更したい行までの行を読んで印刷します。次に、変更したい1行を読み、変更して印刷します。その後、残りの行を読み、それらを印刷します。
while( <$in> ) # print the lines before the change
{
print $out $_;
last if $. == 4; # line number before change
}
my $line = <$in>;
$line =~ s/\b(perl)\b/Perl/g;
print $out $line;
while( <$in> ) # print the rest of the lines
{
print $out $_;
}
行をスキップするには、ループコントロールを使用します。この例の次はコメント行をスキップし、最後はENDまたはDATAのいずれかに遭遇するとすべての処理を停止します。
while( <$in> )
{
next if /^\s+#/; # skip comment lines
last if /^__(END|DATA)__$/; # stop at end of code marker
print $out $_;
}
同じようなことをして、nextを使用して特定の行を削除し、出力に表示したくない行をスキップします。この例では、5行ごとにスキップします。
while( <$in> )
{
next unless $. % 5;
print $out $_;
}
奇妙な理由で、ファイルを1行ずつ処理するのではなく、ファイル全体を一度に表示したい場合は、ファイルを丸呑みすることができます(すべてをメモリに収めることができる限り)。
open my $in, '<', $file or die "Can't read old file: $!"
open my $out, '>', "$file.new" or die "Can't write new file: $!";
my @lines = do { local $/; <$in> }; # slurp!
# do your magic here
print $out @lines;
File::SlurpやTie::Fileなどのモジュールもこれに役立ちます。ただし、可能であれば、ファイル全体を一度に読み取ることは避けてください。Perlは、プロセスが終了するまで、そのメモリをオペレーティングシステムに戻しません。
Perlワンライナーを使用してファイルをインプレースで変更することもできます。以下は、inFile.txtのすべての「Fred」を「Barney」に変更し、ファイルを新しい内容で上書きします。-pスイッチを使用すると、Perlは-eで指定したコードの周りにwhileループをラップし、-iはインプレース編集をオンにします。現在の行は$です。-pを使用すると、Perlはループの最後に$の値を自動的に出力します。詳細については、perlrunを参照してください。
perl -pi -e 's/Fred/Barney/' inFile.txt
inFile.txtのバックアップを作成するには、-iaファイル拡張子を付けて追加します。
perl -pi.bak -e 's/Fred/Barney/' inFile.txt
5行目のみを変更するには、入力行番号である$。をチェックするテストを追加し、テストに合格した場合にのみ操作を実行します。
perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt
特定の行の前に行を追加するには、Perlが$ _を出力する前に1行(または複数行!)を追加できます。
perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt
現在の行はループの最後に出力されるため、ファイルの先頭に行を追加することもできます。
perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt
すでにファイルにある行の後に行を挿入するには、-nスイッチを使用します。ループの最後に$_を出力しないことを除けば、-pと同じです。したがって、自分でそれを行う必要があります。この場合、最初に$ _を印刷してから、追加する行を印刷します。
perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt
行を削除するには、必要な行だけを印刷します。
perl -ni -e 'print unless /d/' inFile.txt
... or ...
perl -pi -e 'next unless /d/' inFile.txt