如何报告“ sed”就地变更


23

sed用于就地替换字符串时,是否有办法使其报告所做的更改(不依赖于新旧文件的差异)?

例如,如何更改命令行

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

这样我就可以看到正在进行的更改?

Answers:


15

如果系统支持,则可以将sedw标志与/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
}' {} \;

将就地编辑文件并输出:

./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的东西>>> bar的东西
更多foo >>> more bar

./file2:

./file3:
foo首先>>> bar首先
第三名:foo >>>第三名:bar

16

您可以在p第一遍中使用rint动作在两遍中完成此操作:

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

其中--quietmake sed不显示每一行,p后缀仅显示替换匹配的行。

这具有的sed不会显示限制被更改的文件,当然这可能是固定的一些额外的复杂性。


由于您需要两次通过,所以它并不能完全满足我的要求,但是我之所以投票,是因为我刚刚学到了这件事,它非常有用。尤其是如您所说,如果文件也已打印。像for x in `find . -type f`; do echo ///File $x: ; sed --quiet 's/abc/def/gp' $x; done
ricab

@msw我有很多sed表达,我不想/gp为每一个写。如何设置全局?
alhelal '18

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.13年

@JosephR。好点,补充。
terdon

谢谢,这可能会有所帮助(我自己没有测试过)。我没有选择,因为它不使用sed,所以它不能完全回答问题。
ricab 2013年

@ricab很好,除非它确实回答了您的问题,否则您不应该接受答案。请记住,尽管对于像这样的简单事情,perl的语法与的语法非常相似sed,但我认为您所要求的实际上并没有可能sed
terdon

3

可以使用w标志将当前模式写入文件。因此,通过将其添加到替代命令中,我们可以将连续的替代报告给文件,并在作业完成后将其打印出来。我也想用grep为替换的字符串着色。

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

注意,w及其文件名之间只能有一个空格。

这甚至比diff更好,因为diff也可能显示更改,即使它们不是由sed进行的。


刚刚测试过,sed只写了它所引用的行sed.done。因此,原始文件中带有“ To”的行不会被打印到sed.done,因此当您grep "To" sed.done只看到更改的行时sed。如果这是您要针对的,那么在替换之前,您不会在文件中看到原始行
。– aairey

1

我喜欢@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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.