我有这个文件
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
对于不以 结尾的行*
:读取N
ext 行,如果仍然没有匹配,则打印第一行。D
删除第一行并重复该过程。