如果满足条件,Bash 脚本将文本放在所有文件的开头

如果满足条件,Bash 脚本将文本放在所有文件的开头

我正在尝试编写一个 bash 脚本,仅在以下情况下将文本放在所有子目录中所有文件的开头:

  1. 该文件不包含该文本
  2. 该文件包含公司名称、River 一词或 Systems 一词

这是我到目前为止所拥有的:

for i in $(find -name *.cpp -type f -print)
do 
if ! grep -r 'This document contains technical data' $i && grep -r 'company name' $1 || grep-r 'River' $i || grep -r 'Systems' $i; then
#add text

现在,不包含任何关键字的文件不会被更改(如预期),但对于已经包含文本和关键字的文件,它们会被更改。我尝试在 || 周围使用 []声明,但结果是一样的。有什么建议么?

答案1

find . -name '*.cpp' -type f \
  ! -exec grep -qF 'This document contains technical data' {} ';' \
  -exec grep -qFe River -e 'company name' -e Systems {} ';' \
  -exec sed -i '1i\
This document contains technical data' {} +

(替换sed -ised -i ''FreeBSD/macos' sed

grep或者使用 GNU和 GNU更有效xargs

grep --include='*.cpp' -rFlZ -e River -e 'company name' -e Systems . |
  xargs -r0 grep -FLZ 'This document contains technical data' |
  xargs -r0 sed -i '1i\
This document contains technical data.'

关于您的尝试的一些注意事项:

  • find -print的输出无法进行后处理
  • 参数扩展必须在中引用bash
  • -r(GNU 扩展),用于递归的grep,对于grepto dofind的工作除了它自己的工作之外,您只想在grepping 目录时使用它(以便它在其中查找文件,然后在这些文件中查找模式)。
  • *是一个特殊字符,它会在那里触发通配符。您应该确保它被引用,以便*.cpp将文字传递给find.
  • 如果您想检查某个模式是否可以在文件中匹配,而不需要查看它匹配的所有行,请使用该-q选项。它不仅会跳过打印,而且由于grep不再查看第一个匹配项,因此效率更高。-l-L(GNU 扩展)具有相同的优化。如果找到模式,前者打印文件的路径,如果未找到模式,则打印后者。
  • 要搜索F固定字符串(而不是进行正则表达式匹配),请使用该-F选项,然后您不需要转义正则表达式运算符。
  • 无需执行grep foo file || grep bar file(或使用find, '(' -exec grep -q foo {} ';' -o -exec grep -q bar {} ';' ')'),grep可以在一个中找到多个模式或者时尚一气呵成grep -e foo -e bar file其他方法
  • 请注意grep -F River也匹配Riverside或。您可以添加仅匹配的选项WindRiver-w所有的单词(其中单词必须由非单词字符分隔,单词字符是数字或下划线,非单词字符是其他字符)。

答案2

当我用另一个 if 语句替换 && 后,这就起作用了:

if ! grep -r 'This document contains technical data' $i; then
  if grep -r 'company name' $1 || grep-r 'River' $i || grep -r 'Systems' $i; then
     #add text
  fi
fi

相关内容