如何使用sed仅删除文件中第一次出现的行

时间:2014-05-16 13:49:12

标签: linux bash shell sed

我有以下文件

titi
tata
toto
tata

如果我执行

sed -i "/tat/d" file.txt

它将删除包含tat的所有行。该命令返回:

titi
toto

但我只想删除包含tat的文件中出现的第一行:

titi
toto
tata

我该怎么做?

6 个答案:

答案 0 :(得分:13)

您可以使用双地址格式:

sed '0,/tat/{/tat/d;}' inputfile

这将删除第一次出现的模式。

引自info sed

 A line number of `0' can be used in an address specification like
 `0,/REGEXP/' so that `sed' will try to match REGEXP in the first
 input line too.  In other words, `0,/REGEXP/' is similar to
 `1,/REGEXP/', except that if ADDR2 matches the very first line of
 input the `0,/REGEXP/' form will consider it to end the range,
 whereas the `1,/REGEXP/' form will match the beginning of its
 range and hence make the range span up to the _second_ occurrence
 of the regular expression.

答案 1 :(得分:3)

如果你可以使用awk,那么这就是:

$ awk '/tata/ && !f{f=1; next} 1' file
titi
toto
tata

要将结果保存在当前文件中,请执行

awk '...' file > tmp_file && mv tmp_file file

解释

让我们在第一次匹配tata时激活一个标志并跳过该行。从那一刻开始,不要跳过这些界限。

  • /tata/匹配包含字符串tata
  • 的行
  • {f=1; next}将标记f设置为1,然后跳过该行。
  • !f{}如果设置了标记f,请跳过此块。
  • 1,作为True值,执行默认的awk操作:{print $0}

另一种方法,Tom Fenech

awk '!/tata/ || f++' file

||代表OR,所以这个条件为真,因此只要发生任何这些情况,就会打印该行:

    在行中找不到
  • tata
  • f++是真的。这是棘手的部分:第一次f默认为0,因此第一个f++将返回False而不打印该行。从那一刻开始,它将从整数值开始增加,并且将为True。

答案 2 :(得分:2)

以下是使用sed

进行此操作的一种方法
sed ':a;$!{N;ba};s/\ntat[^\n]*//' file
titi
toto
tata

答案 3 :(得分:1)

以下是执行此操作的一般方法:

$ cat file
     1  titi
     2  tata
     3  toto
     4  tata
     5  foo
     6  tata
     7  bar
$
$ awk '/tat/{ if (++f == 1) next} 1' file
     1  titi
     3  toto
     4  tata
     5  foo
     6  tata
     7  bar
$
$ awk '/tat/{ if (++f == 2) next} 1' file
     1  titi
     2  tata
     3  toto
     5  foo
     6  tata
     7  bar
$
$ awk '/tat/{ if (++f ~ /^(1|2)$/) next} 1' file
     1  titi
     3  toto
     5  foo
     6  tata
     7  bar

请注意,通过上述方法,您可以跳过您喜欢的RE的任何事件(第1,第2,第1和第2,无论如何),并且您只指定RE一次(而不是必须为某些RE复制它)替代解决方案)。

清晰,简单,明显,易于维护,可扩展等......

答案 4 :(得分:1)

这可能适合你(GNU sed):

sed '/pattern/{x;//!d;x}' file

正常打印除包含图案的行以外的所有行。否则,如果该行包含模式并且保持空间不存在(第一次出现),则删除该行。

答案 5 :(得分:-1)

您可以找到第一个与grep匹配的行号,并将其传递给sed进行删除。

sed "$((grep -nm1 tat file.txt || echo 1000000000:) | cut -f 1 -d:) d" file.txt

grep -ncut相结合,找到要删除的行号。 grep -m1确保最多找到一个行号。 echo处理没有匹配的情况,以便不返回空结果。 sed "[line number] d"删除该行。