![打印最后一个分隔符之后的所有数据](https://linux22.com/image/222834/%E6%89%93%E5%8D%B0%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E5%88%86%E9%9A%94%E7%AC%A6%E4%B9%8B%E5%90%8E%E7%9A%84%E6%89%80%E6%9C%89%E6%95%B0%E6%8D%AE.png)
如何打印文件中最后一个分隔符之后的所有数据?文件数据如下:
data1
data2
######################
data3
data4
######################
data5
data6
我想打印:
data5
data6
因为 ###################### 是分隔符。
*
行数未知。
我试过:
$ cat file | awk -F "#" '{print $NF}'
但输出是:
data1
data2
data3
data4
data5
data6
答案1
使用awk
with tac
(有些系统也有tail -r
这样的功能):
$ tac file | awk '/^#+$/{exit} 1' | tac
data5
data6
tac
或者如果您还没有tac
/ ,则编写您自己的类似函数tail -r
(这里假设 acat
支持非标准-n
选项,如果您没有,则使用awk -v OFS='\t' '{print NR, $0}'
而不是cat -n
):
$ mytac() { cat -n -- "$@" | sort -rn | cut -f2-; }
$ mytac file | awk '/^#+$/{exit} 1' | mytac
data5
data6
awk
或者如果您没有tac
并且不想编写自己的,则单独使用任何一个:
$ awk '{rec=rec $0 ORS} /^#+$/{rec=""} END{printf "%s", rec}' file
data5
data6
或者,如果您的文件足够小,可以一次将所有内容读入内存,则使用 GNUawk
进行多字符:RS
$ awk -v RS='^$' -v ORS= -F'(^|\n)#+(\n|$)' '{print $NF}' file
data5
data6
或者再次使用 GNU awk 进行多字符 RS 并保留 END 部分最后 $0 的值:
$ awk -v RS='(^|\n)#+(\n|$)' -v ORS= 'END{print}' file
data5
data6
无论输入是存储在文件中还是来自管道,上述所有内容都将起作用,因为它只读取输入一次。如果它存储在文件中(因此可以读取两次),您可以使用各种工具组合获得许多其他选项,例如:
$ tail -n +"$(awk '/^#+$/{n=NR} END{print n+1}' file)" file
data5
data6
1 但请注意,对于不可查找的文件(例如管道),输入需要通过tac
/ tail -r
/临时存储sort
在内存中或可能在临时文件中。在某些系统上,tail -r
它愿意存储的数量(在内存中)的限制相对较低。
答案2
使用 GNU awk
:
awk 'BEGIN{FS="######################\n"; RS=""} {print $NF}' file
输出:
数据5 数据6
$NF
包含最后一列。
答案3
这是一个奇特的单线:
tail -n+$(( $(grep -nF '######################' test.txt | tail -1 | cut -d: -f1) + 1)) test.txt
以及更合理的单独解释
last_delimiter_line=$(grep -nF '######################' test.txt | tail -1 | cut -d: -f1)
data_line_num=$((last_delimiter_line + 1))
tail -n+$data_line_num test.txt
- 搜索
grep
文件中的所有分隔符并打印每个匹配项及其找到的行号。 - 删除
tail
除最后一场比赛之外的所有比赛 - 提取
cut
找到的最后一个分隔符的行号,该行号存储在last_delimiter_line
- 要打印的第一行在后面
last_delimiter_line
并存储在data_line_num
- 最后一个
tail
命令从 test.txt 行开始打印任何内容data_line_num