「sed」インプレース変更を報告する方法


23

sedインプレースで文字列を置き換えるために使用する場合、(古いファイルと新しいファイルの差分に依存せずに)変更を報告する方法はありますか?

たとえば、コマンドラインをどのように変更できますか

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

その場で行われた変更を見ることができますか?

回答:


15

あなたは使用することができますsedwいずれかでフラグを/dev/stderr/dev/tty/dev/fd/2お使いのシステムでサポートされている場合。たとえば、次のfileような入力を使用します。

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
}' {} \;

ファイルをその場で編集して出力します:

./file1:
バーのもの
より多くのバー

./file2:

./file3:
バーファースト
第三:バー

次のようなものも印刷できます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
}' {} \;

ファイルをその場で編集して出力します:

./file1:
fooのもの>>>バーのもの
more foo >>> more bar

./file2:

./file3:
foo first >>> bar first
3番目:foo >>> 3番目:bar

16

p最初のパスでrintアクションを使用して2つのパスでそれを行うことができます:

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

ここで--quiet、sedはすべての行を表示せず、p接尾辞は置換が一致した行のみを表示します。

これには、sedがどのファイルが変更されているかを表示ないという制限があります。もちろん、これは多少の複雑さを加えて修正できます。


2つのパスが必要なので、私が望んでいたことはできませんが、このpのことを学んだばかりで非常に役立つので投票しています。特に、あなたが言ったように、ファイルも印刷された場合。何かfor x in `find . -type f`; do echo ///File $x: ; sed --quiet 's/abc/def/gp' $x; done
-ricab

@mswたくさんのsed表現がありますが/gp、それぞれについては書きたくありません。グローバルに設定する方法は?
-alhelal

8

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

find . -type f | xargs perl -i -ne 's/abc/def/ && print STDERR' 

これにより、変更された行が標準エラーに出力されます。例えば:

$ cat foo
fooabcbar
$ find . -type f | xargs perl -i -ne 's/abc/def/ && print STDERR' 
foodefbar

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

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

+1 $ARGV操作対象のファイルの名前にも使用できます。
ジョセフR.

@JosephR。良い点、追加されました。
テルドン

おかげで、おそらく役に立つでしょう(自分でテストしませんでした)。sedを使用しないので選択していません。したがって、質問に正確に答えていません。
ricab

@ricabは問題ありません。実際に質問に答えない限り、答えを受け入れないでください。ただし、このような単純なものについてperlは、構文はの構文に非常に似てsedいるため、実際にを使用して求めることができるとは思いませんsed
テルドン

3

現在のパターンをファイルに書き込むwフラグを使用することができます。したがって、それを代替コマンドに追加することで、連続した置換をファイルに報告し、ジョブの完了後に印刷できます。また、置き換えられた文字列をgrepで色付けすることも好きです。

sed -i -e "s/From/To/gw /tmp/sed.done" file_name
grep --color -e "To" /tmp/sed.done

wとそのファイル名の間にスペースが1つだけあることに注意してください。

diffはsedで作成されたものではない場合でも変更を示す場合があるため、これはdiffよりも優れています。


ちょうどそれをテストし、sedはそれが従属する行のみを書き込みますsed.done。元のファイルで「へ」との行は、そのために印刷されていないsed.doneあなたときので、grep "To" sed.doneあなただけの行が表示されますされていることで変更をsed。それがあなたが目指しているものである場合、それが置換される前にファイル元の行が表示されません
...-aairey

1

私は@terdonソリューションが好きです-perlはこれに適しています。

これが私の調整バージョンです:

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

コード

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.