Unix命令用于查找和替换字符串并列出已替换字符串的所有文件

时间:2014-05-01 02:42:58

标签: unix sed

我需要在当前目录中从名称file_ *开始替换所有文件中的字符串。

例如:/

cat file_1
test1
test2
test3


cat file_2
test4
test2
test3

我想从当前目录中的两个文件中用test2替换test100

以下命令查找并替换字符串,但不列出已修改的文件。

find . -name '*file_*'|xargs sed -i 's/test2/test100/g'

有人可以帮我解决这个问题吗?我想显示已修改的所有文件名。

谢谢!

1 个答案:

答案 0 :(得分:4)

仅列出实际已修改的文件(假设为Linux):

find . -name '*file_*' -exec sh -c \
  'md5Before=$(md5sum "{}"); 
    sed -i "s/test2/test100/g" "{}";
  [ "$(md5sum "{}")" != "$md5Before" ] && echo "{}"' \;

在OSX上,将md5sum替换为md5并使用-i ""而不只是-i

请注意,在这种情况下,比较上次修改的时间戳(Linux上的stat -c %Y,OSX上的stat -f %m)不是一个选项,因为sed -i重写所有文件,即使他们的内容未被修改。


更新:@Jonathan Leffler建议采用更简洁优雅的替代方案:

find . -name '*file_*' -exec sh -c \
  'grep -l "test2" "{}" && sed -i "s/test2/test100/g" "{}";' \;
  • grep -l列出(输出)输入文件名,但仅在找到匹配项时(并在找到第一次匹配后立即退出)
  • 只有在实际找到匹配项时才会调用(无声)sed -i命令(感谢&&

除了更短(并且更可能更快)之外,增加的优势是不会重写所有文件 - 只有那些实际需要它的文件。

(唯一的缺点是搜索词是重复的,但您可以将其分配给shell变量并将其拼接到两个位置的sed程序中;如果搜索词是复杂的正则表达式,那么事情可能会变得棘手,因为正则表达式的支持因公用事业而异。