sed 変更 + 対応する perl 構文の報告

sed 変更 + 対応する perl 構文の報告

LinuxとPerlを学ぶ初心者:

(a)代替文字列を検索し、(b)ファイル名パターンを一致させたい。.myfile, (c) サブディレクトリから再帰的に検索し、 (d) 行番号、ファイル名、元の行、変更された行を印刷します。

sed私は使用するバージョンと構文の両方を探していますperl。私はここで出発点を見つけました質問しかし:

まず:sed

必須: パターン一致構文の追加.myfile、再帰的に検索し、行番号を印刷して削除します。w /dev/fd/2- 何をしているのかわかりません。ファイルを出力するのではなく、結果を端末に印刷したいです。注:私はMac OSでVisual Studio Terminalを使用しています。

find . -type f -printf '\n%p:\n' -exec sed -i '/foo/{
h
s//bar/g
H
x
s/\n/ >>> /
w /dev/fd/2
x
}' {} \;

出力:

./file1:
foo stuff >>> bar stuff
more foo >>> more bar

./file2:

./file3:
foo first >>> bar first
third: foo >>> third: bar

第二:パール:

必須: パターン一致構文の追加.myfile、再帰検索。また、行番号の出力も$.間違っています。最初のファイルについては正確ですが、計算を続け、より多くのファイルを検索してもリセットされません(参照:添付のスクリーンショット出力用)。

$ find . -type f | 
   xargs perl -i -ne '$was=$_; chomp($was);
                      s/abc/def/ && print STDERR "$ARGV($.): $was : $_"' 
./foo(1): fooabcbar : foodefbar

答え1

このコードは、stderrに修正を印刷しながら(または経由で)ファイルを内部で変更します(もちろん、-p;の代わりに-n;を使用すると-nファイルが空になるPerlコードの場合)w /dev/fd/2print STDERR

ただし、find . | xargs出力がfind予想される入力形式と互換性がないため、これは誤りですxargs。また、現在の入力行番号をperl含む in は、各ファイルの最後のハンドルを閉じない限り、ファイル間でリセットされないため、次のようにする必要があります。$.ARGV

find . -name '*.myfile' -exec perl -i -pe '
  chomp($was = $_);
  print STDERR "$ARGV($.): $was : $_" if s/abc/def/;
  close ARGV if eof' -- {} +

の場合、sedmacosがstderrをサポートしているかどうかはわかりませんが、Linuxベースの/dev/fd/2システム(macosはLinux btwではありません)でも、w /dev/fd/2stderrがパイプや端末デバイスなどの特定の種類のファイルに移動しない限り、使用は間違っています。-printfGNU実装に固有のものでfindあり、macOSを含む他の実装では見つかりません。

また、それに基づくFreeBSDなどのmacosではなく、内部編集を実行するsed必要があります。行番号を報告する必要がありますが、文字列に挿入するなどの操作はできません。 POSIX準拠の実装ではファイル間でもリセットされません(GNUの場合、または非標準オプションを使用するとリセットされます)。-i ''-ised=sedsed-i-s

.myfile含まれていないファイルを含むすべてのファイルを編集(および交換)しますabc。この問題は次の方法で解決できます。

find . -name '*.myfile' -type f -exec grep -l --null abc {} + |
  xargs -0 perl -i -pe '
  chomp($was = $_);
  print STDERR "$ARGV($.): $was : $_" if s/abc/def/;
  close ARGV if eof' --

Macosにはいくつかの以前のバージョンのGNUに基づくgrepAPIがあります(GNUまたは少なくともFreeBSDに基づいていgrepたため)、そこには(短いバリエーションではありませんが)いくつかのGNUオプションがあります。 GNUのオプションもありますが、残念ながらそのオプションはまだ利用できないため、ファイルが見つからないとエラーが発生します。grep--null-Zxargs-0-rperlfind

そのファイルを変更せずに一致と代替方法のみを印刷したい場合は、次のようにします。

find . -name '*.myfile' -type f -exec perl -nle '
  $was = $_;
  print "$ARGV($.): $was : $_" if s/abc/def/;
  close ARGV if eof' -- {} +

-inplaceがない場合、-n各サイクルの終わりに行が印刷されますn。 onは自動的に実行されます(そして出力を追加するように求められます)。 stderrの代わりにstdoutとして印刷します(stderrに移動するにはコマンド全体をstderrにリダイレクトします。ターミナルの対話型シェルプロンプトで、stdoutとstderrは両方ともターミナルに移動する必要があるため変更します)。p-lchomp$_print\n>&2

関連情報