搜索存在两个不同单词的文本文件(任意顺序、任意行)

Cha*_*son 20 grep find search

我正在寻找一种方法来搜索在同一文件中存在两个单词实例的文件。到目前为止,我一直在使用以下内容来执行搜索:

find . -exec grep -l "FIND ME" {} \;
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是,如果“FIND”和“ME”之间没有一个空格,则搜索结果不会产生文件。我如何调整以前的搜索字符串,其中“FIND”和“ME”都存在于文件中,而不是“FIND ME”?

我正在使用 AIX。

Sté*_*las 26

使用 GNU 工具:

find . -type f  -exec grep -lZ FIND {} + | xargs -r0 grep -l ME
Run Code Online (Sandbox Code Playgroud)

您可以标准地执行以下操作:

find . -type f -exec grep -q FIND {} \; -exec grep -l ME {} \;
Run Code Online (Sandbox Code Playgroud)

但是grep每个文件最多会运行两个s。为了避免运行那么多greps 并且仍然是可移植的,同时仍然允许文件名中的任何字符,你可以这样做:

convert_to_xargs() {
  sed "s/[[:blank:]\"\']/\\\\&/g" | awk '
    {
      if (NR > 1) {
        printf "%s", line
        if (!index($0, "//")) printf "\\"
        print ""
      }
      line = $0
    }'
    END { print line }'
}

export LC_ALL=C
find .//. -type f |
  convert_to_xargs |
  xargs grep -l FIND |
  convert_to_xargs |
  xargs grep -l ME
Run Code Online (Sandbox Code Playgroud)

想法是将 的输出find转换为适合 xargs 的格式(期望空格(C语言环境中的 SPC/TAB/NL ,其他语言环境中的 YMMV)分隔的单词列表,其中单引号、双引号和反斜杠可以转义空格和每个其他)。

通常您不能对 的输出进行后处理find -print,因为它用换行符分隔文件名,并且不会转义在文件名中找到的换行符。例如,如果我们看到:

./a
./b
Run Code Online (Sandbox Code Playgroud)

我们有没有办法知道它是否是所谓的一个文件b在一个名为目录a<NL>.,或者如果它的两个文件a,并b在当前目录中。

通过使用.//., 因为//不能以其他方式出现在作为输出的文件路径中find(因为没有空名称的目录这样的东西并且/不允许在文件名中),我们知道如果我们看到一行包含//,那就是新文件名的第一行。所以我们可以使用该awk命令来转义所有换行符,但那些行之前的字符除外。

如果我们以上面的例子为例,find在第一种情况下(一个文件)会输出:

.//a
./b
Run Code Online (Sandbox Code Playgroud)

哪个 awk 转义为:

.//a\
./b
Run Code Online (Sandbox Code Playgroud)

所以这xargs将其视为一个论点。在第二种情况下(两个文件):

.//a
.//b
Run Code Online (Sandbox Code Playgroud)

哪个awk会保持原样,所以xargs看到两个论点。

您需要LC_ALL=Cso sed, awk(以及 的某些实现xargs)适用于任意字节序列(即使在用户的语言环境中不会形成有效字符),以将空白定义简化为仅 SPC 和 TAB 并避免不同解释的问题字符的编码包含不同实用程序的反斜杠编码。


小智 11

如果文件是在一个目录和其名称不包含空格,制表符,换行符*?也不是[字符,且不要下手-,也没有.,这将让包含ME的文件列表,然后缩小下来的那些还包含 FIND。

grep -l FIND `grep -l ME *`
Run Code Online (Sandbox Code Playgroud)