如果 "file" 具有空分隔项,如何使用 "grep -f file"?

How to use "grep -f file" if "file" has null-delimited items?

我需要从存在于 data1 中的众多文件(data2data3、...)中找到以空分隔的项目。需要完全匹配。

data1 中的项目也用 null 分隔之前,grep -f data1 data2 data3 ... 一切正常。

  1. 只使用换行符 - ok:

    $ cat data1
    1234
    abcd
    efgh
    5678
    $ cat data2
    1111
    oooo
    abcd
    5678
    $ grep -xFf data1 data2
    abcd
    5678
    
  2. data2 包含空分隔项 - ok-z 使用时:

    $ printf '1111[=13=]oooo[=13=]abcd[=13=]05678' > data2
    $ grep -zxFf data1 data2 | xargs -0 printf '%s\n'
    abcd
    5678
    
  3. 现在 data1data2 都包含空分隔项 - 失败-z 选项似乎不适用于 -f:

    指定的文件
    $ printf '1234[=14=]abcd[=14=]efgh[=14=]05678' > data1
    $ grep -zxFf data1 data2 | xargs -0 printf '%s\n'
    
    $
    

问题是我确实需要两个文件 来包含空分隔项。 明显的解决方法可能是(例如)一个很好的旧 while 循环:

while IFS= read -rd '' line || [[ $line ]]; do
    if grep -zqxF "$line" data2; then
        printf '%s\n' "$line"
    fi
done < data1

但是因为我有很多包含很多项目的文件,这会很慢!有没有更好的办法(我不坚持用grep)?

由于订单保留并不重要,您正在尝试匹配精确的字符串,并且您有可用的 GNU 工具,而不是使用 fgrep 我建议 comm -z.

$ printf '%s[=10=]' 1111 oooo abcd 005678 >data2
$ printf '%s[=10=]' 1234 abcd efgh 005678 >data
$ comm -z12 <(sort -uz <data) <(sort -uz <data2) | xargs -0 printf '%s\n'
005678
abcd

如果您首先生成排序的文件(因此可以省略 sort 操作),这也将具有非常好的内存和性能特征。

(虽然以下可能不是针对这种特殊情况的最佳解决方案,但我还是添加了它,以防它有助于将来 reader 遇到类似问题。请参阅下面的 gawk 解决方案这可能对这个用例有用。)

grep 将换行符硬连接为模式终止符。即使您使用 -e pattern,模式字符串中的换行符也会导致 grep 将选项处理为指定多个模式,而不是包含换行符的单个模式。

但是,如果您的 NUL 分隔模式不包含换行符,您可以使用 Gnu xargssed 构造一个适当的 grep 调用 -e命令行参数:

sed -z 's/^/-e/' data | xargs -0 grep -zF data2 ...

(这是有效的,因为 Gnu grep 重新排列了命令行参数,所以可以将要搜索的文件放在模式之前。这对许多其他 grep 实现不起作用。 )

据我所知,对于可能包含换行符的模式没有解决方法。 grep -Egrep -F 不识别 ascii 转义序列,并且会从包含换行符的模式中默默地创建多个模式。 grep -P(另一个使用 PCRE regexen 的 Gnu 扩展)将正确处理嵌入的换行符或 ascii 转义符,但只允许单一模式。


不排序的全行 NUL 终止匹配

如果您只对精确的、完整的“行”匹配感兴趣 (-Fx),您可以使用 Gnu Awk 脚本而不是对输入和模式进行排序。对于无法放入内存的非常大的输入,这可能是一个胜利;使用外部临时文件进行排序可能会非常昂贵。 Awk 解决方案使用散列 table,因此不需要排序。 (同样,这可能不适用于所有 Awk,因为它依赖于将 RS 设置为 NUL。)

awk -v RS=`[=11=]` 'NR==FNR{p[[=11=]] = 1; next;} [=11=] in p' data data2 ...