我正在寻找一种方法来搜索在同一文件中存在两个单词实例的文件。到目前为止,我一直在使用以下内容来执行搜索:
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。为了避免运行那么多grep
s 并且仍然是可移植的,同时仍然允许文件名中的任何字符,你可以这样做:
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=C
so sed
, awk
(以及 的某些实现xargs
)适用于任意字节序列(即使在用户的语言环境中不会形成有效字符),以将空白定义简化为仅 SPC 和 TAB 并避免不同解释的问题字符的编码包含不同实用程序的反斜杠编码。
小智 11
如果文件是在一个目录和其名称不包含空格,制表符,换行符*
,?
也不是[
字符,且不要下手-
,也没有.
,这将让包含ME的文件列表,然后缩小下来的那些还包含 FIND。
grep -l FIND `grep -l ME *`
Run Code Online (Sandbox Code Playgroud)