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

MOH*_*MED 12 linux bash shell sed

我有以下文件

titi
tata
toto
tata
Run Code Online (Sandbox Code Playgroud)

如果我执行

sed -i "/tat/d" file.txt
Run Code Online (Sandbox Code Playgroud)

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

titi
toto
Run Code Online (Sandbox Code Playgroud)

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

titi
toto
tata
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

dev*_*ull 13

您可以使用双地址格式:

sed '0,/tat/{/tat/d;}' inputfile
Run Code Online (Sandbox Code Playgroud)

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

引用自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.
Run Code Online (Sandbox Code Playgroud)

  • @SLePort 吹毛求疵,但 `sed '0,/tat/{//d}' inputfile` 更短;-) 但是非常感谢您教我有关 `//` 结构的知识。 (3认同)
  • 或者更短的`sed'0,/ tat/{// d;}'inputfile`. (2认同)

fed*_*qui 5

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

$ awk '/tata/ && !f{f=1; next} 1' file
titi
toto
tata
Run Code Online (Sandbox Code Playgroud)

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

awk '...' file > tmp_file && mv tmp_file file
Run Code Online (Sandbox Code Playgroud)

解释

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

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

另一种方法,作者:Tom Fenech

awk '!/tata/ || f++' file
Run Code Online (Sandbox Code Playgroud)

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

  • tata行中未找到。
  • f++是真的。这是棘手的部分:第一次 f 默认为 0,因此首先f++将返回 False 并且不打印该行。从那时起,它将从整数值递增并且为 True。