Grep 目录并返回包含行号的列表

Grep 目录并返回包含行号的列表

我目前正在尝试更多地了解 bash 脚本和所有这些有趣的东西,我拼凑了这个小命令:

find $path | xargs grep -n $pattern | awk '{print $1}'

虽然这确实有效,但我想知道我是否在重新发明轮子。有没有更好的方法来搜索目录、grep 文件中的模式并返回包含行号的列表?

答案1

许多grep变体都实现了递归选项。例如,GNU grep

-R, -r, --recursive
          Read all files under each directory, recursively; this is equivalent to the -d recurse option.

然后您可以删除find

grep -n -r $pattern $path | awk '{ print $1 }'

但这保留的不仅仅是行号。awk正在打印第一列。这个例子

src/main/package/A.java:3:import java.util.Map;
src/main/package/A.java:5:import javax.security.auth.Subject;
src/main/package/A.java:6:import javax.security.auth.callback.CallbackHandler;

将被打印为

src/main/package/A.java:3:import
src/main/package/A.java:5:import
src/main/package/A.java:6:import

注意:import每一行中的 。您可能想用来sed过滤输出。

由于 a:可能出现在文件名中,因此您可以使用-Zgrep 选项在文件名后输出 nul 字符 (\0)。

grep -rZn $pattern $path | sed -e "s/[[:cntrl:]]\([0-9][0-9]*\).*/:\1/" 

使用与之前相同的示例将产生

src/main/package/A.java:3
src/main/package/A.java:5
src/main/package/A.java:6

答案2

对于第一部分,请注意,仅当文件名中xargs没有空格字符时才有效。\'"如何在linux目录的全部内容中搜索单词寻求解释和替代方案。

另外,始终在变量替换两边加上双引号:"$path"。如果没有双引号,shell 会扩展 值中的空格和通配符$path,因此如果该文件名中包含空格或通配符,则使用不带引号的它会中断。这同样适用$pattern(只是为了笑,尝试省略引号并在包含名为和h*的文件的目录中搜索)。hihello

如果您的版本grep可以-r选择递归地遍历目录,则不需要find这里。该-r选项适用于 Linux、FreeBSD、Mac OS X 和 Cygwin 等。否则:

find "$path" -type f -exec grep -Hn "$pattern" {} + | awk -F: '{print $1 ":" $2}'

awk也修复了上面的调用,以便它仅打印文件名和行号。我还将-H选项传递给grep, 以确保它始终打印文件名,即使碰巧只有一个文件。此代码假设您的文件名不包含:换行符;如果可能的话,事情就会变得复杂,你最好要么依赖 GNU grep 的-Z选项或单独处理文件:

find "$path" -type f -exec sh -c 'for x; do grep -n "$0" <"$x" | awk -v fn="$x" -F: 'print fn ":" $1'; done' "$pattern" {} +

答案3

我会摆脱grep并使用awk

find $path -type f -print0 | xargs -0 awk "/$pattern/{print FILENAME,FNR}"

但使用grepand cut

find $path -type f -print0 | xargs -0 grep -nH "$pattern" | cut -d: -f1,2

包含该-type f子句,这样您在尝试搜索(在 grep 或 awk 中)非常规文件类型(符号链接、目录、套接字)时就不会出现错误。如果您在另一个程序应该从管道或套接字读取数据时,那么您可能会弄乱该程序。

find ... -print0 | xargs -0解决了文件名中存在空格的问题。它并非在每个 UNIX 系统上都可用,但在大多数系统上都可用。

答案4

也检查-c-n有用的选项。

相关内容