在脚本中,我想查找包含一些文本的文件。我需要知道在其中找到文本的文件,以及在其中找到文本的文件中的整行。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'
。
但如果输出实际上并不含糊,您可能根本不需要这个。例如,如果匹配行不包含冒号,则文件名是一行中直到最后一个冒号的所有内容。如果匹配的行全部以SUCCESS
or开头,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 的知识,就可以解决您的问题。
更改文件命名约定可能是明智之举。