如何在多个文件中搜索字符串并列出所有出现的文件名

如何在多个文件中搜索字符串并列出所有出现的文件名

目录中有许多文件(来自 Java 应用程序的日志 - 每行一个记录),我想列出包含搜索字符串的所有文件名,并列出该字符串在特定文件中的所有出现情况。

到目前为止我一直在使用这个。在这里我得到文件名,下面我得到匹配的行,但我不知道文件名匹配的行来自哪个文件名。

#!/bin/bash
cd ${DIRECTORY}
clear
echo 'WARNINGS'
egrep -l "WARN" * | sort
echo ''
cat * | grep 'WARN'

我需要列出所有文件名(但仅限于包含 WARN 的文件名),并且对于所有这些匹配的文件,显示特定文件中带有 WARN 字符串的所有行。

答案1

一个鲜为人知的事实是,grep当搜索多个文件时,它可以打印它(成功)搜索的文件的名称。这意味着,如果您将其包含/dev/null到要搜索的文件列表中,您将得到您想要的内容:

$ grep "something" /path/to/file
something (and some other thing)

然而:

$ grep "something" /dev/null /path/to/file
/path/to/file:something (and some other thing)

使用它,您可以执行以下操作(的变体):

$ find /path/to/start [-name "<filename pattern>"] \
                       -exec grep '<searchstr>' /dev/null {} \;

这会给你这样的输出:

/path/to/start/file1:<searchstr> foo
/path/to/start/file1:<searchstr> bar
/path/to/start/subdir/file2:foo <searchstr> bar
/path/to/start/subdir/file3:bar <searchstr> foo
...

正如 @ilkkachu 正确指出的那样,我给出的命令将一次将一个文件传递到grep.如果要搜索许多文件,这对系统来说可能是相当繁重的。优化该过程的一种方法是这样写:

$ find /path/to/start [-name "<filename pattern>"] \
                       -exec grep '<searchstr>' /dev/null {} +

wherefind一次将多个文件名传递给 grep,从而产生较小的负载,因为 grep 不那么频繁地调用。您仍然需要指定,/dev/null因为有可能find只找到一个文件。

答案2

当您向 提供多个文件时grep,它会将文件名附加到输出的每一行。另外,这样,您就可以避免猫的经典无用用途。当您使用它时,请避免对 shell 变量名称使用大写字母,因为按照惯例,全局环境变量名称都是大写的,因此如果您也将自己的 shell 变量大写,这可能会导致命名冲突和错误。最后,egrep已被弃用grep -E(但您在这里不需要grep -E),并且在运行其中的内容之前不需要进入目录,但如果这样做,您还应该在执行任何操作之前cd确保工作正常。cd这是脚本的改进版本,可以满足您的需求:

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep 'WARN' "$1"/*

您现在可以运行脚本,并将目标目录名称作为参数:

your_script /path/to/target

例如,/home/terdon/foo在我的系统上指定的目录上运行它会给出:

WARNINGS found in files in directory "/home/terdon/foo":
/home/terdon/foo/file2:WARNING from file2
/home/terdon/foo/file4:WARNING from file4
/home/terdon/foo/file4:WARNING2 from file4
/home/terdon/foo/file5:WARNING from file5

如果您只想显示文件名而不显示路径,您选择cd(但如上所述,如果失败请确保退出cd):

#!/bin/sh

clear
if cd -- "$1"; then
  :
else
  echo "cd to '$1' failed!"
  exit 1
fi

printf 'WARNINGS found in files in directory "%s":\n' "$1"

grep 'WARN' *

或者您可以从输出中删除路径:

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep 'WARN' "$1"/* | sed 's|.*/||'

最后,如果您想确保即使目标目录只有一个文件也能正常工作,如果您使用的是 GNU grep(Linux 上的默认设置),您可以使用-H告诉 grep 始终包含文件名的标志:

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep -H 'WARN' "$1"/* | sed 's|.*/||'

如果您grep不支持-H,请使用巴枯宁的诡计其中包括/dev/null

#!/bin/sh

clear
printf 'WARNINGS found in files in directory "%s":\n' "$1"
grep 'WARN' "$1"/* /dev/null | sed 's|.*/||'

答案3

更好的利用ack在你的Java存储库中。

这将防止在目录或类似目录中搜索.git,因此它更好、更快。

有更多的选择可以比grep这种情况更好。

尝试 (递归地):

ack WARN
ack -l WARN

相关内容