我试图找到一种方法来确定文件的名称,这些文件的str1和str2可能位于文件的不同部分。 grep str1 | grep str2将无法工作,因为grep str2将在包含str1的行上运行。 我可以获得包含str1的文件列表,并再次获得包含str2的文件列表,然后查找交集但效率低下。 一种更有效的方法是使grep str1输出一个文件列表,然后让grep str2对它进行操作,但这意味着grep将一遍又一遍地打开,读取和关闭同一个文件。 也许最理想的方法是打开一个文件,grep为str1和str2,然后确定文件是否包含str1和str2,但我无法创建这样的命令。 我想它看起来应该和这个发现相似。 -name“*” - exec grep“str1”&& grep“str2”{} \;但这在语法上并不正确
答案 0 :(得分:2)
使用GNU awk(gawk):
awk -v RS='\0' -v str1="$str1" -v str2="$str2" '
index($0,str1) && index($0,str2) { print FILENAME; nextfile }
' file1 file2 filen
任何awk:
awk -v str1="$str1" -v str2="$str2" '
FNR == 1 { found[1] = found[2] = 0 }
index($0,str1) { found[1]++ }
index($0,str2) { found[2]++ }
found[1] && found[2] { files[FILENAME] }
END { for (file in files) print file }
' file1 file2 filen
答案 1 :(得分:0)
您对
的评论使grep str1输出一个文件列表,然后让grep str2对该文件进行操作
解决方案让它听起来比实际情况要糟糕得多:每个文件至少会被第一个grep
打开一次, 包含str1的每个文件都会再打开一次到第二个grep
。不是那么糟糕,当然不是“一遍又一遍地打开,阅读和关闭同一个文件”。最多两次,有时只一次。如果你的效率更高,我可以根据perl
给你一个答案,但这可能不值得。你实际上两次打开文件有困难吗?
-l
的{{1}}参数为您提供仅文件的名称。因此grep
将列出内部某处grep -l str1 files…
的所有文件。然后用str1
重复一遍。结果将是:
str2
最后的grep -l str1 files… | xargs grep -l str2 /dev/null
是一个技巧,因此如果没有文件与/dev/null
匹配,那么第二个str1
不会卡在grep
上1}}。
如果您使用的是GNU grep和findutils,那么使用stdin
和-Z
选项-0
和grep
可以更安全。
xargs
答案 2 :(得分:0)
我认为awk更适合这项任务。这是你可以做到的一种方式:
awk -v str1="$str1" -v str2="$str2" '
FNR == 1 { m1 = m2 = 0 }
index($0, str1) { m1 = 1 }
index($0, str2) { m2 = 1 }
m1 && m2 { print FILENAME; nextfile }' file1 file2 filen
这假定$str1
和$str2
设置为您要搜索的字符串。解决方案在一次传递中进行匹配,并在找到两个字符串后立即退出。
略微优化的版本:
awk -v str1="$str1" -v str2="$str2" '
FNR == 1 { m1 = m2 = 0 }
!m1 && index($0, str1) { m1 = 1 }
!m2 && index($0, str2) { m2 = 1 }
m1 && m2 { print FILENAME; nextfile }' file1 file2 filen
在下面的评论中添加了 Ed Morton 提到的错误修正和优化。另请注意,旧版本的awk中nextfile
语句可能存在一些可移植性问题,请参阅GNU awk appendix B中有关该主题的讨论。 POSIX标准中nextfile
语句已accepted for inclusion,因此将来应更广泛地使用。
答案 3 :(得分:-1)
尝试使用(str1.*str2|str2.*str1)
之类的正则表达式。我不确定,您可能需要使用egrep
代替grep
答案 4 :(得分:-2)
如果str1发生在str2之前,那么你可以使用
find . -name "str1*str2"