对于大目录,创建一个文件名变量,其中包含包含存储在另一个变量中的文本字符串的行

对于大目录,创建一个文件名变量,其中包含包含存储在另一个变量中的文本字符串的行

我有一个包含超过 150K 文件的目录。我想创建一个包含存储在文本变量中的文本的所有文件的列表,并将该文件列表存储在另一个变量中。

我首先尝试:

searchtext="Subject: Your"
files = $(grep "$searchtext" ./* | awk '{print ($1)}' )

,虽然这适用于目录中的中等数量的文件,但在包含 150K 文件的目录上运行时,它会生成错误“参数列表太长”。 (带 print 的 awk 用于从 grep 结果中仅提取文件名。)

我发现 files=$(grep "$searchtext" ./* | awk '{print ($1)}') 适用于 150K 文件目录,但运行时间几乎需要 90 分钟。

如果文件中存在,$searchtext 字符串将位于文件的开头。所以我想如果 grep 仅限于显示前 30 行文本,我可以大大加快速度。我不确定如何做到这一点,我发现如何递归地 grep 目录中每个文件的前 50 行?并尝试了那里的一些建议。最适合我的任务的是:

searchtext="Subject: Your"
find . -type f -exec head -n 30 {} + | grep "$searchtext"

这在可接受的时间内运行,但它不会输出包含搜索文本的文件的文件名。我尝试了 grep -l,但这会导致错误:“find: head' terminated by signal 13 ". Somewhere it was suggested that the using "\" instead of "+" might be more appropriate. However, that also generates an error: "find: missing argument to-exec' ”。

展望 grep 结果包含文件名时,我预计会出现另一个问题。当我尝试将 grep 输出分配给变量时:

files = $(find . -type f -exec head -n 30 {} + | grep "$searchtext")

我收到错误“ut1.sh:第 16 行:文件:找不到命令”。由于某种原因,变量“files”被解释为命令?我的脚本名称是 ut1.sh 。我之前已经多次以这种方式分配变量,没有出现问题。

我的 bash 版本是 GNU bash,版本 4.1.2(2)-release (x86_64-redhat-linux-gnu)

如何完成工作,我的尝试出了什么问题?

谢谢

答案1

要获取匹配的文件名列表grep,您可以使用-l开关仅获取文件名,无需使用awk来处理输出。在匹配文件的情况下,这也更快,因为grep可以在找到模式一次后停止。

grep -le "$searchtext" ./* 

您可以通过简单的赋值将其输出放入变量中(但带有空格和通配符的文件名会导致问题):

files=$(grep -le "$searchtext" ./* ) 

至于这个:

find . -type f -exec head -n 30 {} + | grep "$searchtext"

这里的管道将find和分开grep,因此您可以有效地连接每个文件的前 30 行(此处丢失文件名的跟踪),然后 grep 结果。grep -l只能告诉您整个输入中是否有任何匹配项。您需要从内部运行一个 shellfind来单独组合每个文件的headgrep

export searchtext
find . -type f -exec sh -c 'head -n 30 "$1" | grep -q "$searchtext" && echo "$1"' sh {} \;

但我们不妨awk这样做。这将仅在前 30 行查找模式 (GNU awk):

awk -vpattern="$searchtext" 'FNR <= 30 && $0 ~ pattern { print FILENAME; nextfile }' *

或使用查找:

find . -type f -exec awk -vpattern="$searchtext" 'FNR <= 4 && $0 ~ pattern { print FILENAME; nextfile }' {} +

答案2

对于bash4.4+ 和 GNU grep

readarray -td '' files < <(grep -rZFle "$searchtext" .)

如果是电子邮件文件,您可能只想在此处的标题中搜索,因为您似乎正在寻找主题。使用 GNU awk

readarray -td '' files < <(
  SEARCH="$searchtext" find . -type f -exec gawk -v ORS='\0' -v RS='\r?\n' '
    $0 == "" {nextfile}
    index($0, ENVIRON["SEARCH"]) {print FILENAME; nextfile}' {} +
)

相关内容