首页 > 解决方案 > 如何在不使用 tac 的情况下从下到上搜索文件中的匹配字符串?

问题描述

我需要遍历一个文件,从文件底部开始,直到我到达出现“2021-04-04”的第一个日期,然后返回该日期。我不想从头开始,一直到第一行,因为每个文件中有数千行。

示例文件内容:

random text on first line
random text on second line
2021-01-01
random text on fourth line
2021-02-03
random text on sixth line
2021-03-03
2021-04-04
Random text on ninth line

tac在 MacOS 上不可用,所以我无法使用它。

标签: shellgrep

解决方案


“千行”不算什么,一眨眼就处理完了。一旦你进入数以千万计的行,那么如果有必要,你就可以开始考虑提高性能。

所有你需要的是:

awk '/[0-9]{4}(-[0-9]{2}){2}/{line=$0} END{if (line!="") print line}' file

5s这是第 3 次运行时间比较,用于在由 生成的 100000 行文件中查找包含 2 个或更多连续的最后一行seq 100000 > file100k,即目标字符串距输入文件末尾仅 45 行,有和没有tac

$ time awk '/5{2}/{line=$0} END{if (line!="") print line}' file100k
99955

real    0m0.056s
user    0m0.031s
sys     0m0.000s

$ time tac file100k | awk '/5{2}/{print; exit}'
99955

real    0m0.056s
user    0m0.015s
sys     0m0.030s

如您所见,两者都在几分之一秒内运行,并且 usingtac并没有提高执行速度。切换到 tac+grep 也不会让它更快,它仍然只需要 1/20 秒:

$ time tac file100k | grep -m1 '5\{2\}'
99955

real    0m0.057s
user    0m0.015s
sys     0m0.015s

但是,如果您将来确实需要它,tac如果您没有它,这里是如何实现高效的:

$ mytac() { cat -n "${@:--}" | sort -k1,1rn | cut -d$'\t' -f2-; }

$ seq 5 | mytac
5
4
3
2
1

上面的mytac()函数只是将行号添加到输入中,对它们进行反向排序,然后再次删除它们。如果您cat不必-n添加行号,那么您可以使用nl它(如果有的话)或awk -v OFS='\t' '{print NR, $0}'将始终工作。


推荐阅读