如何执行 sed 就地替换,仅创建已更改文件的备份?

如何执行 sed 就地替换,仅创建已更改文件的备份?

我运行以下命令来替换当前工作目录中所有文件中使用的术语:

$ find . -type f -print0 | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

这执行了单词替换,但它也创建了.bup从未包含该字符串的文件的文件Ms. Johnson

如何执行替换而不创建所有这些不必要的备份?

答案1

Find 有一个-exec执行任意命令的运算符。更好的是,-exec是一个测试,因此您可以将多个-exec命令链接在一起,如果较早的命令失败,则后面的命令将不会被执行。该字符串{}将替换为当前文件名,并;标记命令的结束。您应该引用两者以避免 shell 干扰。

所以:

find . -type f \
    -exec grep -q 'Ms. Johnson' '{}' \; \
    -exec sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g' '{}' \;

答案2

您可以检查文件的内容以确保在sed对其进行操作时会发生替换:

find . \
    -type f \
    -exec grep -q 'Ms. Johnson' {} \; \
    -print0 |
xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

如果你想真正做到聪明,你可以find完全放弃使用:

grep -Z -l -r 'Ms. Johnson' |
    xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

答案3

我查看了手册页,没有看到任何直接通过 执行此操作的方法sed,正如我确信您在询问之前所做的那样。我看到有几种使用 grep 解决这个问题的方法,但我认为最简单的是:

grep -rlZ "Ms. Johnson" . | xargs -0 sed -i'.bup' -e's/Ms. Johnson/Mrs. Melbin/g'

-r递归
-l打印文件名仅以
-Z空结尾的名称

答案4

似乎您需要首先构建与您的搜索词匹配的文件列表。

search="test"
for match in $(find -type f -exec grep -l $search "{}" \;)
do sed -i'.bup' -e "/$search/ s/$search/Mrs. Melbin/g" "$match"
done

相关内容