我正在尝试编写一个 bash 脚本,仅在以下情况下将文本放在所有子目录中所有文件的开头:
- 该文件不包含该文本
- 该文件包含公司名称、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 -i
为sed -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,对于grep
to dofind
的工作除了它自己的工作之外,您只想在grep
ping 目录时使用它(以便它在其中查找文件,然后在这些文件中查找模式)。*
是一个特殊字符壳,它会在那里触发通配符。您应该确保它被引用,以便*.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