当使用sed
就地替换字符串时,有没有办法让它报告它所做的更改(而不依赖于新旧文件的差异)?
例如,如何更改命令行
find . -type f | xargs sed -i 's/abc/def/g'
这样我就可以看到即时所做的更改?
答案1
如果您的系统支持,您可以将sed
sw
标志与 , 一起/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
}' {} \;
将就地编辑文件并输出:
./文件1: 酒吧的东西 更多酒吧 ./文件2: ./文件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 >>> 更多 bar ./文件2: ./文件3: foo 首先 >>> bar 首先 第三:foo >>> 第三:bar
答案2
p
您可以在第一遍中使用 rint 操作分两遍完成:
find . -type f | xargs sed --quiet 's/abc/def/gp'
where--quiet
使 sed 不显示每一行,p
后缀仅显示替换匹配的行。
这有 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