44

我目前在使用 grep 命令时遇到了一些问题。

我找到了只显示 grep 搜索的最后一行的方法:

grep PATERN FILE_NAME | tail -1

我还找到了在多个选定文件中进行 grep 搜索的方法:

find . -name "FILE_NAME" | xargs -I name grep PATERN name

现在我只想获取每个文件的 grep 结果的最后一行。我试过这个:

 find . -name "FILE_NAME" | xargs -I name grep PATERN name | tail -1

这仅返回我希望为每个文件提供最后一个匹配模式的最后一个文件的最后一个值。

4

10 回答 10

44
for f in $(find . -name "FILE_NAME"); do grep PATTERN $f | tail -1; done
于 2013-02-14T23:04:18.913 回答
10

Sort 有一个 uniq 选项,允许您从多行中选择一行。试试这个:

grep PATTERN FILENAMES* | tac | sort -u -t: -k1,1

说明:Grep 将为文件中的每个匹配项返回一行。这看起来像:

$ grep match file*
file1.txt:match
file1.txt:match2
file2.txt:match3
file2.txt:match4

我们想要的是输出中的两行:

$ ???
file1.txt:match2
file2.txt:match4

您可以将其视为一种表,其中第一列是文件名,第二列是匹配项,其中列分隔符是“:”字符。

我们的第一个管道反转输出:

$ grep match file* | tac
file2.txt:match4
file2.txt:match3
file1.txt:match2
file1.txt:match

我们要排序的第二个管道说:拉出第一个唯一行(-u),其中分组的键是第一个(-k1,1,从第 1 列到第 1 列的键),我们将数据拆分为以 ':' 作为分隔符 (-t:) 的列。它也会对我们的输出进行排序!及其输出:

$ grep match file* | tac sort -u -t: -k1,1
file1.txt:match2
file2.txt:match4
于 2020-02-01T17:25:22.067 回答
1

你也可以使用 find 来执行命令:

find . -name "<file-name-to-find>" -exec grep "<pattern-to-match>" "{}" ";" | tail -1

“{}”是文件名,写命令时注意shell globing和expasion

于 2013-02-14T22:59:12.147 回答
1

可以使用 awk 而不是 grep 来替代此方法。Posix 版本会这样写:

awk '(FNR==1)&&s{print s; s=""}/PATTERN/{s=$0}END{if(s) print s}' file1 file2 file3 ...

使用 GNU awk,您可以使用 ENDFILE

awk 'BEGINFILE{s=""}/PATTERN/{s=$0}ENDFILE{if(s) print s}' file1 file2 file3 ...
于 2019-06-12T19:44:08.287 回答
0

您可以从 grep 的 -B(之前)参数开始。例如在比赛前获得 5 行:

duli@i5 /etc/php5/apache2 $ grep -i -B5 timezone php.ini 
[CLI Server]
; Whether the CLI web server uses ANSI color coding in its terminal output.
cli_server.color = On

[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
;date.timezone =
于 2016-01-17T00:47:50.527 回答
0

获取每个文件的最后一行(以文件名为前缀)。然后,根据模式过滤输出。

find . -name "*" -exec tail -v -n1 {} \; | grep "some_string" -B1

在 macOS 上,您必须以稍微不同的方式进行操作

find . -name "*" | xargs tail -1 | grep "some_string" -B1
于 2019-06-12T19:20:56.950 回答
0

晚会晚了 7 年。修改命令行的慢方法:

find . -name "FILE_NAME" | xargs -I name sh -c "grep PATERN name | tail -1"

如果需要在每一行显示文件名:

find . -name "FILE_NAME" | xargs -I name sh -c "grep -H PATERN name | tail -1"
于 2020-02-27T21:32:42.293 回答
-1

有一个不需要循环的解决方案,这给出了 OP 想要的。

find . -type f -exec sh -c "fgrep print {} /dev/null |tail -1" \;

./tway.pl:print map(lambda x : x[1], filter(lambda x : x[0].startswith('volume'), globals().items()))
./txml.py:           print("%s does not exist: %s\n" % (host, error))
./utils.py:print combine_dicts(a, b, operator.mul)
./xml_example.py:print ET.tostring(root, method="text")

与没有tail -1给出每个文件太多行相比,但证明了上述工作。

find . -type f -exec sh -c "fgrep print {} /dev/null" \;

给出:

./tway.pl:print map(lambda x : x[1], filter(lambda x : x[0].startswith('volume'), globals().items()))
./txml.py:           print("%s resolved to --> %s\n" % (host, ip))
./txml.py:           print("%s does not exist: %s\n" % (host, error))
./utils.py:print "a", a
./utils.py:print "b", b
./utils.py:print combine_dicts(a, b, operator.mul)
./xml_example.py:    print ">>"
./xml_example.py:    print ET.tostring(e, method="text")
./xml_example.py:    print "<<"
./xml_example.py:print ET.tostring(root, method="text")

编辑-如果您不希望文件名包含在输出中,请删除 /dev/null 。

于 2013-02-14T23:51:01.873 回答
-1

最快的方法是从文件中获取最后 1 (或更多)行的输出,然后通过 grep 执行该操作。所以 -

tail -1 filenames.* | grep "what you want to grep for"
于 2013-07-17T13:39:01.813 回答
-1

找到最后一行的另一种方法是反转文件并输出第一个匹配项。

find . -name "FILE_NAME" | xargs -I name sh -c 'tac name|sed -n "/PATTERN/{p;q}"'
于 2013-07-17T14:58:40.617 回答