在包含A、B、C...但不包含Z的文件中使用grep正则表达式

4
花了几个小时尝试自己回答这个问题,使用这个问题的部分答案;所以如果已经回答过了,我很抱歉,但是将我能找到的部分解决方案组合起来以正确执行此搜索似乎超出了我的能力范围。
我要做的事情:在目录中搜索包含多个唯一字符串(任意顺序,任何位置)的文件,但不包含文件中的另一个特定字符串。
以下是我迄今为止的搜索:
pcregrep -riM '^(?=.*uniquestringA)(?=.*uniquestringB)(?=.*uniquestringC)(?=.*uniquestringD)(?=.*uniquestringE).*$' . 
| xargs grep -Li 'uniquestringZ'

我意识到这是非常、非常错误的,因为我似乎甚至不能让多行搜索在忽略字符串出现顺序时正常工作。
非常感谢任何帮助。
2个回答

2
如果你的grep拥有lookaheads,你应该可以这样做:
^(?!.*Z)(?=.*A)(?=.*B)(?=.*C)(.*)$

点击查看实例

有了这个文件:

$ cat /tmp/grep_tgt.txt
A,B,C      # should match
A,B,C,D    # should match
A,C,D      # no match, lacking upper b
A,B,C,Z    # no match, has upper z

您可以使用Perl一行命令:
$ perl -ne 'print if /^(?!.*Z)(?=.*A)(?=.*B)(?=.*C)(.*)$/' /tmp/grep_tgt.txt
A,B,C      # should match
A,B,C,D    # should match

带有文件名:

$ find . -type f
./.DS_Store
./A-B-C
./A-B-C-Z
./A-C-D
./sub/A-B-C-D

您可以使用perl过滤文件名:
$ find . -type f | perl -ne 'print if /^(?!.*Z)(?=.*A)(?=.*B)(?=.*C)(.*)$/'
./A-B-C
./sub/A-B-C-D

如果您想读取文件内容以测试模式(如grep),则可以执行以下操作:
$ find . -type f | xargs perl -ne 'print "$ARGV: $&\n" if /^
(?!.*Z)(?=.*A)(?=.*B)(?=.*C)(.*)$/'
./1.txt: A B C     # should match
./2.txt: A,B,C,D    # should match

我将四个文件放在一个目录中(1.txt..4.txt),其中1.txt和2.txt的文本相匹配。


对我来说,^(?!.*Z)(?=.A)(.)$ 看起来运行良好,但是一旦我添加第二个条件以包括搜索,即使我只是搜索 ^(?=.*A)(?=.B)(.)$,它也返回了空值。这是使用 pcregrep 进行的,我之前已经成功地执行过负向先行断言。 - Asterdahl
我可以尝试您建议的搜索,但我感觉perl只是在运行文件名本身而不是内容?如果我将其缩减为单个术语(?!.*Z)或(?=.*A),我只会得到结果,但从未超过一个。我知道文件内容有多个这些字符串,但名称只有一个。 - Asterdahl
哦——是的,我以为你只想在文件名上使用它。你可以使用相同类型的Perl,但只需使用xargs来调用Perl。您可以使用Perl和一个非常强大的grep。试试看吧。 - dawg
@thatotherguy的答案最终奏效了,但还是谢谢您。我没有考虑使用perl来过滤结果,在将来我会尝试一下,看能否获得更快的结果。 - Asterdahl

1
虽然需要进行大量的grep调用,但你可以用简单且符合POSIX标准的方式,使用findgrep将其写出:
find . -type f \
  -exec grep -q "stringA" {} \; \
  -exec grep -q "stringB" {} \; \
  -exec grep -q "stringC" {} \; \
  -exec grep -q "stringD" {} \; \
  ! -exec grep -q "stringZ" {} \; \
  -print  # or whatever to do with matches

有点慢,但我没想到会找到一个超快的解决方案,它运行得非常好。 - Asterdahl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接