grep 的 A 的倒数

Inverse of grep's A

我知道我可以用 grep-A1 打印匹配项的 "next" 行,但是反过来呢?我是说,"hide the next line after a filter match".

示例:

a
b
c
d
e

cat letters.txt | grep -A1 -v "c" <-- 隐藏 "c" 和 "d"

grep 本身并不(通常)提供此功能,但使用 Awk 或 sed.

就足够简单了
awk '/c/ { skip=1; next }
    skip { skip=0; next } 1' letters.txt

你可以用 sed 这样

sed -ne '/c/{n;d;}; p' letters.txt

这将读取文件 letters.txt。任何与 c 不匹配的行都将被打印,如果 c 匹配,则不打印它,并转到下一行并将其从输出

中删除

使用 GNU sed 可以更容易地获得 N 行,它可以像

sed -ne '/c/,+1d; p;' letters.txt

并且您可以将 1 更改为您喜欢的任何数字。此外,您可以将 -i 标志添加到 sed 以使其在适当的位置修改文件,如果您想这样做的话

使用 awk 还可以:

awk -v s='c' '[=10=] ~ s {getline;next} 1' letters.txt
a
b
e

此答案着眼于一般 解决方案,其中变量 跳过计数。


如果你有 GNU sed 是最简单的解决方案。

可以稍微简化为sed '/c/,+1d',或者,概括为:

regex='c' count=2
sed "/${regex}/,+${count}d" letters.txt  # skips c, d, e

上下文地址的 +<n> 形式与范围 开始的第 <n> 匹配(因此是范围 以下 <n> 行)是 GNU sed 扩展。

注意 $count +1 行被跳过:匹配正则表达式的行 + $countafter.


为了便携性为了更灵活(比如不跳过匹配行本身),使用 :

的通用版本
awk -v regex='c' -v count=2 \
  '[=11=] ~ regex { skip=count; next } --skip >= 0 { next } 1' letters.txt # skips c, d, e

注意 $count +1 行被跳过:匹配正则表达式的行 + $countafter.

  • -v regex='c' -v count=2 定义 awk 个具有指定值的变量。
  • [=26=] ~ regex 匹配感兴趣的行
    • { skip=count; next } 初始化跳过计数并进行到下一行,有效地跳过匹配行;在第二个解决方案中,next 之前的 print 确保它被 跳过。
    • --skip >= 0 减少跳过计数并在它(仍然)>= 0 时采取行动,这意味着应该跳过手头的行。
    • { next } 前进到下一行,有效地跳过当前行
  • 1{ print }常用的shorthand;也就是说,只打印当前行
    • 只有不匹配和未跳过的行才能到达此命令。
    • 1 等同于 { print } 的原因是 1 被解释为布尔模式,根据定义总是计算为真,这意味着其关联的操作(块)无条件执行。由于在这种情况下没有关联操作,awk默认为打印该行。

作为符合 POSIX 的 shell 函数:

# SYNOPSIS
#   matchAndSkip regex skipCount [file]
matchAndSkip() {
  awk -v regex="" -v count="" \
    '[=12=] ~ regex { skip=count; next } --skip >= 0 { next } 1' "${3-/dev/stdin}"
}