行の変更、削除、挿入、またはファイルの先頭への追加により、ファイルの内容を変更したい。 Perlでこれを行うにはどうすればよいですか?
これは 公式FAQ からの 質問 です。 perlfaqをStack Overflowにインポートする です。
(これは 公式のperlfaqの回答 であり、その後の編集を除く)
テキストファイルから行を挿入、変更、または削除する基本的な考え方には、変更を加えたいポイントまでファイルを読み取って印刷し、変更を加えてから、残りのファイルを読み取って印刷することが含まれます。 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 $_;
}
何らかの奇妙な理由で、行ごとに処理するのではなく、ファイル全体を一度に表示したい場合は、メモリに収まる限り、それを丸canみすることができます!
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のバックアップを作成するには、-iに追加するファイル拡張子を付けます。
Perl -pi.bak -e 's/Fred/Barney/' inFile.txt
5行目のみを変更するには、テストチェック$.
、入力行番号を追加し、テストが合格した場合にのみ操作を実行します。
Perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt
特定の行の前に行を追加するには、Perlが$_
を出力する前に行(または行!)を追加できます。
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