删除包含匹配的第一行之前的所有行?

删除包含匹配的第一行之前的所有行?

使用正则表达式字符串,如何删除包含匹配项的第一行之前的所有行?例如我怎样才能改变这个:

lost
load
linux
loan
linux

进入这个:

linux
loan
linux

我试过:

echo "lost
load
linux
loan
linux" | sed -e 's/.*^li.*$//g'

但它返回这个,没有改变任何东西:

lost
load
linux
loan
linux

我想让它工作,这样当没有匹配时它就不会输出任何内容。

答案1

一种方式,POSIXly:

$ echo "lost
load
linux
loan
linux" | sed -e/linux/\{ -e:1 -en\;b1 -e\} -ed

或更短:

sed -n '/linux/,$p'

甚至更短:

sed '/linux/,$!d'

对于想知道为什么我更喜欢较长版本而不是较短版本的读者,较长版本只会对文件的其余部分执行 I/O,而如果第二个地址是正则表达式,则使用范围会影响性能,并且正则表达式会尝试匹配超出必要的范围。

考虑:

$ time seq 1000000 | sed -ne '/^1$/{' -e:1 -en\;b1 -e\}
=====
JOB sed -e '/^1$/,$d'
87%    cpu
0.11s real
0.10s user
0.00s sys

和:

$ time seq 1000000 | sed -e '/^1$/,/1000000/d'
=====
JOB sed -e '/^1$/,/1000000/d'
96%    cpu
0.24s real
0.23s user
0.00s sys

你可以看到两个版本之间的差异。对于复杂的正则表达式,这将会有很大的不同。

答案2

这很容易清楚地做到awk

echo "lost
load
linux
loan
linux" | awk '
    /^li/ { found = 1 }
    found { print }'

found是一个变量,具有任意选择的、不言自明的名称。当程序遇到与正则表达式匹配的输入行时,它就会被设置。 (变量最初默认为 null,这在功能上相当于 0 或 FALSE。)因此输入行在^li模式匹配之后打印,而不是之前。打印输入的第三行(第一linux行),因为条件打印语句位于查找模式并设置标志的语句之后。如果您想从第四行开始打印(该行第一linux行),只需颠倒两个语句的顺序即可。

如果没有输入行与正则表达式匹配,则永远不会设置该标志,并且不会打印任何内容。

正如我所说,标志变量的名称是任意的;f如果需要,您可以使用更短的内容(例如, )。 And{ print }是默认操作,因此您可以将其省略。所以,如果你不关心清晰度,你可以将上面的内容缩短为

echo "lost
load
linux
loan
linux" | awk '/^li/{f=1}f'

答案3

另外两个 awk 解决方案:

它们都found在看到第一个正则表达式匹配时设置一个标志,并在设置该标志时进行打印。

echo "lost
load
linux
loan
linux" | awk 'BEGIN {found = 0} {if (found || $0 ~ /linux/) {found = 1; print}}'

这个有点长,但没有found再次设置标志。

echo "lost
load
linux
loan
linux" | awk 'BEGIN {found = 0} {if (found) {print} else if ($0 ~ /linux/) {found = 1; print}}'

答案4

您可以使用前任在批处理模式下直接编辑文件。 (如果您想在实际更改文件之前查看输出文件是什么,请将 替换为x%p

printf '%s\n' 'a' 'linux' '.' '1,/linux/-1d' '$d' 'x' | ex -s file
  1. a, linux, writes在末尾.添加一行。linux
  2. 1,/linux/-1d删除区间 [文件的第一行,第一个之前的行linux] 中的行;
  3. $d删除步骤 1 中人工插入的行。
  4. x写入更改并退出。

更直接的方法(参见编辑历史中的第一个版本) 如果没有匹配项,文件将保持不变。这会根据需要清空文件(这就是奇怪的步骤 1 的原因)。

$ cat file1
lost
load
linux
loan
linux
$ printf '%s\n' a linux . 1,/linux/-1d '$d' x | ex -s file1
$ cat file1
linux
loan
linux
$ cat file2
lost
load
loan
$ printf '%s\n' a linux . 1,/linux/-1d '$d' x | ex -s file2
$ cat file2  #file2 is empty

相关内容