unix 在脚本中查找需要满足条件的组合并对所有找到的文件执行某些操作

unix find in script which needs to met a combination of condiations and execute something for all found files

假设我们有以下文件和目录:

-rw-rw-r--.   a.c
-rw-rw-r--.   a.cpp
-rw-rw-r--.   a.h
-rw-rw-r--.   a.html
drwxrwxr-x.   dir.c
drwxrwxr-x.   dir.cpp
drwxrwxr-x.   dir.h

我想对满足以下条件的所有文件执行grep(它也应该在子目录中查找):

在找到的文件上,执行 grep 并打印 grep 找到的文件名。

但这最终会变成一个很长的命令,其中有很多重复,例如:

 find . -name '*.c' -type f -exec grep hallo {} \; -print -o -name '*.cpp' -type f -exec grep hallo {} \; -print -o -name '*.h' -type f -exec grep hallo {} \; -print

是否可以对条件进行分组以消除重复,或者是否有任何其他可能的简化?

我的系统是 Fedora 33,有 GNU grep、GNU find 和 bash 可用。

您可以使用 regex/regextype 代替名称,因此:

find . -regextype "posix-extended" -regex "^.*\.((c)|(cpp)|(h))$" -exec grep hallo '{}' \;
  1. 使用 Bash 的 extglobglobstar 特殊选项:

    shopt +s extglob globstar
    grep -s regex **/*.+(cpp|c|h)
    

    您可以将第一行放在 ~/.bashrc 中,这样您就不需要在每个 shell 中手动启用它们的选项。 如果您碰巧有带有这些扩展名的目录,Grep 会在没有 -s 标志的情况下抱怨。

  2. 在 GNU Find 中,使用 -regex 选项使其更容易:

    find . -type f -regex '.*\.\(c\|h\|cpp\)' -exec grep regex {} +
    find . -type f -regextype awk -regex '.*\.(c|h|cpp)' -exec grep regex {} +
    

    More on Find's regextypes.

  3. 仅使用 POSIX 工具:

    find . -type f \( -name '*.[ch]' -o -name '*.cpp' \) -exec grep regex {} +