我有以下文件
titi
tata
toto
tata
如果我执行
sed -i "/tat/d" file.txt
它将删除包含tat
的所有行。该命令返回:
titi
toto
但我只想删除包含tat
的文件中出现的第一行:
titi
toto
tata
我该怎么做?
答案 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}
。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 -n
与cut
相结合,找到要删除的行号。 grep -m1
确保最多找到一个行号。 echo
处理没有匹配的情况,以便不返回空结果。 sed "[line number] d"
删除该行。