「sed」内部変更を報告する方法

「sed」内部変更を報告する方法

sed内部文字列置換を使用するとき(以前のファイルと新しいファイルの違いに依存せずに)変更を報告する方法はありますか?

たとえば、コマンドラインを変更する方法は次のとおりです。

find . -type f | xargs sed -i 's/abc/def/g'

では、変更はすぐに表示されますか?

答え1

システムでサポートされている場合は、sedswフラグを一緒に使用できます/dev/stderr。たとえば、次のように入力します。/dev/tty/dev/fd/2file

foo first
second: missing
third: foo
none here

走る

sed -i '/foo/{
s//bar/g
w /dev/stdout
}' file

出力:

bar first
third: bar

file内容は次のように変更されましたが、

bar first
second: missing
third: bar
none here

したがって、あなたの場合は、以下を実行してください。

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

ファイルをその場で編集し、以下を出力します。

./ファイル 1:
バーのもの
もっとバー

./ファイル2:

./ファイル 3:
バー最初
3番目:バー

次のように印刷することもできますoriginal line >>> modified line

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

ファイルを所定の位置で編集して出力します。

./ファイル 1:
fooのもの>>>バーのもの
もっとfoo >>>もっとバー

./ファイル2:

./ファイル 3:
foo まず >>> bar まず
3番目:foo >>> 3番目:bar

答え2

p最初のステップでは、rint操作を使用して2つのステップでこれを実行できます。

find . -type f | xargs sed --quiet 's/abc/def/gp'

ここで、--quietsed はすべての行を表示せず、psuffix は代替項目に一致する行のみを表示します。

sed が表示しない制限があります。どのファイルが変更されていますが、これをより複雑に変更すると確実に解決できます。

答え3

私はこれが可能だとは思いませんが、回避策は代わりにPerlを使用することです。

find . -type f -exec perl -i -pe 's/abc/def/ && print STDERR' {} +

これは印刷されます変更標準エラーの行です。たとえば、

$ cat foo
fooabcbarabc
blah blah
$ find . -type f -exec perl -i -pe 's/abc/def/ && print STDERR' {} +
foodefbarabc
$ cat foo
foodefbarabc
blah blah

より複雑にするために、行番号、ファイル名、元の行、変更された行を印刷することもできます。

$ find . -type f -exec perl -i -pe ' 
   $was=$_; chomp($was);
   s/abc/def/ && print STDERR "$ARGV($.): $was : $_"
   close ARGV if eof' {} +
./foo(1): fooabcbarabc : foodefbarabc

各ファイル間でリセットがclose ARGV if eof必要であることに注意してください$.

最初の行だけでなく、各行に表示されるすべての項目を置き換えるには、演算子gにフラグを追加します。s///

答え4

私は@terdonの解決策が好きです。 Perlはこれに便利です。

調整されたバージョンは次のとおりです。

  • 一致する文字列を持たないファイルは変更しようとしません。
  • 変更されたファイルの以前のバージョンをバックアップします(.bakバージョンの作成)。
  • 各ファイル/変更されていない行を一覧表示して読みやすくするために、その行の古いバージョンと新しいバージョンをインデントして下に配置します。

パスワード

find /tmp/test -type f ! -name "*.bak" -exec grep -l '/opt/gridmon' {} \; | xargs -L1 perl -ni'.bak' -e'$old=$_; s/\/opt\/gridmon/~/g && print STDERR "$ARGV($.):\n\tOLD:$old\tNEW:$_"'

出力例

/tmp/test/test4.cfg(13):
    OLD:    ENVFILE /opt/gridmon/server/etc/gridmonserver.cfg
    NEW:    ENVFILE ~/server/etc/gridmonserver.cfg
/tmp/test/test4.cfg(24):
    OLD:    ENVFILE /opt/gridmon/server/etc/gridmonserver.cfg
    NEW:    ENVFILE ~/server/etc/gridmonserver.cfg

関連情報