awk 打印除匹配之前的所有行

awk 打印除匹配之前的所有行

我有这个文件

john
robert
rose*
ann*
charles
david
liz*
louis
wendy*
kate*
mandy*
paul

我想打印除 '*' 之前的行之外的所有行所以所需的输出是:

john
rose*
ann*
charles
liz*
wendy*
kate*
mandy*
paul

我尝试过:

awk '/\*/ {f=1}; (!f &&NR > 1) {print p}; {p=$0;f=0} END {print p}' file

它生成输出

john
ann*
charles
liz*
mandy*
paul

代码有什么问题吗?

答案1

rose**是( )之前的一行,ann*因此您的标准I want to print all lines except those lines before '*'与您的预期输出不匹配,并且您的代码似乎执行您所说的操作。

要改为打印包含*和/或不包含包含的行的所有行*,从而获得您显示的预期输出将是:

$ awk '(NR>1) && ((p ~ /\*/) || !/\*/){print p} {p=$0} END{print p}' file
john
rose*
ann*
charles
liz*
wendy*
kate*
mandy*
paul

答案2

这主要只是为了我个人的享受。

sed解决同样问题的命令:

sed -e 'N' -e '/[^*]$/P' -e '/[*]\n.*[*]$/P' -e '$!D' -e 's/.*\n//' file

这会在编辑缓冲区中保留来自输入的两行。下一行使用 添加到编辑缓冲区N,并通过 插入的文字换行符与现有数据分隔sed

*如果缓冲区末尾没有,则缓冲区的初始部分会打印P。如果后面有一个未加星号的行,这就是输出一行的内容。

如果缓冲区包含*后跟文字换行符(即缓冲区的第一部分以**缓冲区末尾有一个;然后第一部分打印为P.这就是输出一条加星号的行,即使它后面跟着另一条加星号的行。

D除非我们到达末尾,否则将删除缓冲区的初始部分。该D命令还会自动使脚本从第一条指令开始(但不会清空整个编辑缓冲区或自动读取另一行输入,就像d会做的那样)。

如果我们到达s最后的命令,我们已经读取了最后一行,并且最后两行位于缓冲区中。其中第一行应该已经被打印(或没有),所以我们只需要确保在允许打印剩余的最后一行之前删除它。

更短的变体:

sed -e '$q' -e 'N' -e '/[^*]$/P' -e '/[*]\n.*[*]$/P' -e 'D' file

这依赖于这样一个事实:D最后的无条件命令也会修剪掉编辑缓冲区中保留的倒数第二行,并且我们接受最终迭代,该迭代被$q脚本开头的 缩短,导致脚本在之后终止打印最后一行。

答案3

如果可以sed接受的话

sed '/\*$/!{$!N;//!P;D;}' file

对于不以 结尾的行*:读取Next 行,如果仍然没有匹配,则打印第一行。D删除第一行并重复该过程。

相关内容