How to report "sed" in-place changes

You could do it in two passes using the print action on the first pass with:

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

where --quiet makes sed not show every line and the p suffix shows only lines where the substitution has matched.

This has the limitation that sed will not show which files are being changed which of course could be fixed with some additional complexity.


You could use sed's w flag with either /dev/stderr, /dev/tty, /dev/fd/2 if supported on your system. E.g. with an input file like:

foo first
second: missing
third: foo
none here

running

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

outputs:

bar first
third: bar

though file content was changed to:

bar first
second: missing
third: bar
none here

So in your case, running:

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

will edit the files in-place and output:

./file1:
bar stuff
more bar

./file2:

./file3:
bar first
third: bar

You could also print something like original line >>> modified line e.g.:

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

edits the files in-place and outputs:

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

./file2:

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

I don't think that's possible, but a workaround might be to use perl instead:

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

This will print the altered lines to standard error. For example:

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

You can also make this slightly more complex, printing the line number, file name, original line and changed line:

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