如何在脚本中安全地使用 grep 的输出?

如何在脚本中安全地使用 grep 的输出?

在脚本中,我想查找包含一些文本的文件。我需要知道在其中找到文本的文件,以及在其中找到文本的文件中的整行。grep是执行此操作的实用程序,但是鉴于可以有,我怎样才能将输出转换为可用的形式:在文件名中?是否有某种我可以使用的--porcelain模式grep,就像git命令经常使用的那样?

示例:我有一个文件夹,里面装满了test-num:1:date:jan-2我想要 grep 的文件。这些文件包含FAILURE:<some reason>or SUCCESS:<some reason>(以及其他内容)。我需要一个脚本来搜索某些原因并存储文件名和原因(整行文本都可以)以供以后处理。输出可以是任何类型的数据结构,只要我可以对其运行代码即可。

答案1

不存在诸如 之类的东西grep --porcelain,在 UNIX 中,处理文件名中的特殊字符始终是事后才想到的。您可以尝试这样的事情,但要以效率为代价:

pattern='some pattern'
for file in ./*; do
    grep -- "$pattern" "$file" | while read -r line; do
        printf 'file: %s, line: %s\n' "$file" "$line"
    done
done

答案2

最近(-ish)版本的 GNU grep 有一个选项-Z可以使输出明确,但它主要针对像grep -lZ … | xargs -0.如果您列出行内容,空字节替换冒号并且行内容仍然以换行符结束,它仍然有效,但是 shell 不擅长处理空字节,因此您将很难解析此输出。

一种简单的解决方案(性能略有下降)是对每个文件单独运行 grep。

另一种解决方案是使用 Perl 或 Python 等语言。 Perl 非常擅长模拟 grep; grep REGEX基本上是perl -ne '/REGEXP/ and print'

但如果输出实际上并不含糊,您可能根本不需要这个。例如,如果匹配行不包含冒号,则文件名是一行中直到最后一个冒号的所有内容。如果匹配的行全部以SUCCESSor开头,FAILURE并且这些单词没有出现在文件名中,那么您可以使用它来定位分隔符等。

1除非用于-z过滤以 null 结尾的记录而不是以换行符结尾的记录,否则 null 既是文件名终止符又是结果终止符;没有-o输出仍然是明确的,交替输出记录是文件名和输出中的匹配记录。

答案3

如何安全地使用 grep 的输出在脚本中?

...输出可以是任何类型数据结构,只要我可以在上面运行代码即可。

Shell 脚本实际上没有数据结构。有数组,但仅此而已 - 将管道输出安全地输入数组并不容易。 (文件名包含换行符。)

最好的方法是运行代码在 shell 脚本中对文件进行操作的方法是仅对文件运行代码,而不是尝试保存文件名以供以后使用。

为此,请使用find

find somedir -type f -exec grep -q somepattern {} \; -exec somecommand {} \;

然而,通过更仔细地阅读你的问题,看起来你实际上并不想运行代码在您的文件中,您只想对某些行进行一些文本处理。在这种情况下,GNU Grep 选项-z可能就是您想要的。再加上 Sed 或 Awk 的知识,就可以解决您的问题。


更改文件命名约定可能是明智之举。

相关内容