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


13

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

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

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

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


在我看来,作为SED的一个bug
Hotschke

使用ex和可能有更好的方法,并且:!cp '%' '%.bup'在保存并退出之前有条件地运行(仅在更改文件时)。可能值得研究。
通配符

我在堆栈交换上面写了一个关于我的想法问题vi
通配符

Answers:


6

您可以检查文件的内容,以确保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'

1
我认为您需要在那'{}'之前。\;-exec
Jander

8

Find具有-exec执行任意命令的运算符。更好的-exectest,因此您可以将多个-execs链接在一起,如果早期的命令失败,则以后的命令将不会执行。该字符串{}将替换为当前文件名,并;标记命令的结尾。您应同时引用两者,以避免外壳干扰。

所以:

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

使用裸{}从来没有问题。
amphetamachine

1
@amphetamachine:我也没有,但是手册页建议这样做。可能是csh的事情,或者可能有shell(不是Bash和POSIX){}在进行大括号扩展时扩展为null字符串。
詹德,

4

我查看了手册页,但没有找到直接通过进行操作的任何方法sed,因为我确定您在询问之前就做了。我看到了几种使用grep解决此问题的方法,但我认为最简单的方法是:

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

-r递归
-l打印文件名仅
-Z结尾为null


-1

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

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

您忘记了.作为的第一个参数find。另外,不久前我被告知自己,您实际上不需要引用或转义{}
Kevin

不要生成文件列表并对其执行命令替换。首先find生成一个以换行符分隔的文件列表,然后Shell在任何空格(不仅仅是换行符)处分解该列表,然后Shell将每个单词视为全局模式。仅当您的文件名不包含空格或时,此方法才有效\[?*。本页上的其他答案显示了如何正确执行此操作。
吉尔(Gilles)“所以,别再邪恶了”,

@Kevin .find(至少在Linux上找到find)是不必要的,因为假定没有路径传递参数时使用它。
laebshade
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.