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/2
。print 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' -- {} +
の場合、sed
macosがstderrをサポートしているかどうかはわかりませんが、Linuxベースの/dev/fd/2
システム(macosはLinux btwではありません)でも、w /dev/fd/2
stderrがパイプや端末デバイスなどの特定の種類のファイルに移動しない限り、使用は間違っています。-printf
GNU実装に固有のものでfind
あり、macOSを含む他の実装では見つかりません。
また、それに基づくFreeBSDなどのmacosではなく、内部編集を実行するsed
必要があります。行番号を報告する必要がありますが、文字列に挿入するなどの操作はできません。 POSIX準拠の実装ではファイル間でもリセットされません(GNUの場合、または非標準オプションを使用するとリセットされます)。-i ''
-i
sed
=
sed
sed
-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に基づくgrep
APIがあります(GNUまたは少なくともFreeBSDに基づいていgrep
たため)、そこには(短いバリエーションではありませんが)いくつかのGNUオプションがあります。 GNUのオプションもありますが、残念ながらそのオプションはまだ利用できないため、ファイルが見つからないとエラーが発生します。grep
--null
-Z
xargs
-0
-r
perl
find
そのファイルを変更せずに一致と代替方法のみを印刷したい場合は、次のようにします。
find . -name '*.myfile' -type f -exec perl -nle '
$was = $_;
print "$ARGV($.): $was : $_" if s/abc/def/;
close ARGV if eof' -- {} +
-i
nplaceがない場合、-n
各サイクルの終わりに行が印刷されますn
。 onは自動的に実行されます(そして出力を追加するように求められます)。 stderrの代わりにstdoutとして印刷します(stderrに移動するにはコマンド全体をstderrにリダイレクトします。ターミナルの対話型シェルプロンプトで、stdoutとstderrは両方ともターミナルに移動する必要があるため変更します)。p
-l
chomp
$_
print
\n
>&2