awk / Sed:如何在具有特定文件扩展名的文件中递归查找/替换字符串?

时间:2015-10-31 18:25:35

标签: bash replace awk sed

我需要递归查找并替换.cpp.hpp个文件中的字符串。

查看this question的答案我找到了以下命令:

find /home/www -type f -print0 | xargs -0 sed -i 's/subdomainA.example.com/subdomainB.example.com/g'

将其更改为包含我的文件类型无效 - 未更改任何单个词:

find /myprojects -type f -name *.cpp -print0 | xargs -0 sed -i 's/previousword/newword/g'

帮助表示赞赏。

2 个答案:

答案 0 :(得分:3)

不要为xargs而烦恼;使用-exec主要版本。 (为了便于阅读,分为两行。)

find /home/www -type f -name '*.cpp' \
  -exec sed -i 's/previousword/newword/g' '{}' \;

答案 1 :(得分:2)

chepner's helpful answer建议更简单,更有效地使用find -exec行动,而不是管道xargs。< / p>

除非需要特殊的xargs功能,否则此更改总是值得的,并映射到xargs功能,如下所示:

  • find ... -exec ... {} \;相当于find ... -print0 | xargs -0 -n 1 ...
  • find ... -exec ... {} +相当于find ... -print0 | xargs -0 ...

换句话说:

  • \;终止符为每个匹配的文件/文件夹调用一次目标命令。

  • +终结符一次性调用目标命令 ,将所有匹配的文件/文件夹路径作为单个参数列表提供。

    • 只有在生成的命令行变得太长时才会发生多次调用,这种情况很少见,尤其是在Linux上,getconf ARG_MAX,最大值。命令行长度很大。

对OP的命令进行排查:

由于OP的xargs命令一次性传递所有匹配的文件路径 - 并且每个xargs默认值 end 在命令行中,生成的命令将实际看起来像这样:

  sed -i 's/previousword/newword/g' /myprojects/file1.cpp /myprojects/file2.cpp ...

这可以通过将echo添加到sed来轻松验证 - 但是(概念性地)引用需要它的参数(带有例如嵌入空格的路径)将不会显示(注意{{1} }}):

echo

接下来,在运行实际命令后,使用find /myprojects -type f -name '*.cpp' -print0 | xargs -0 echo sed -i 's/previousword/newword/g' 检查文件的上次修改日期是否已更改:

  • 如果有,但内容没有改变,暗示stat 处理文件,但sed函数调用中的正则表达式没有匹配任何东西。

可以想象在将s(就地编辑)与多个sed版本无法正常工作>文件操作数(虽然我在GNU sed release notes中找不到任何内容) 要对此进行排除,请为每个文件调用-i

如果您仍想使用sed,请添加xargs

-n 1

要使用 find /myprojects -type f -name '*.cpp' -print0 | xargs -0 -n 1 sed -i 's/previousword/newword/g' &#39; find操作,请参阅chepner's answer

使用GNU -exec版本支持使用sed选项更新多个文件 - 至少的情况是这样的 v4.2.2 - 命令的最佳表述是(注意引用-i参数以防止shell过早扩展,并使用终结符*.cpp仅调用+一次):

sed