Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove only the first occurrence of a line in a file using sed

I have the following file

titi
tata
toto
tata

If I execute

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

It will remove all the lines containing tat. The command returns:

titi
toto

but I want to remove only the first line that occurs in the file containing tat:

titi
toto
tata

How can I do that?

like image 390
MOHAMED Avatar asked May 16 '14 13:05

MOHAMED


People also ask

How do you delete a line in a file using sed?

To delete a line, we'll use the sed “d” command. Note that you have to declare which line to delete. Otherwise, sed will delete all the lines.

What is I flag in sed?

The I flag allows to match a pattern case insensitively. Usually i is used for such purposes, grep -i for example. But i is a command (discussed in append, change, insert chapter) in sed , so /REGEXP/i cannot be used. The substitute command does allow both i and I to be used, but I is recommended for consistency.

How do you insert a first line using sed?

Use sed 's insert ( i ) option which will insert the text in the preceding line.


2 Answers

You could make use of two-address form:

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

This would delete the first occurrence of the pattern.

Quoting from 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.
like image 169
devnull Avatar answered Sep 29 '22 12:09

devnull


If you can use awk, then this makes it:

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

To save your result in the current file, do

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

Explanation

Let's activate a flag whenever tata is matched for the first time and skip the line. From that moment, keep not-skipping these lines.

  • /tata/ matches lines that contain the string tata.
  • {f=1; next} sets flag f as 1 and then skips the line.
  • !f{} if the flag f is set, skip this block.
  • 1, as a True value, performs the default awk action: {print $0}.

Another approach, by Tom Fenech

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

|| stands for OR, so this condition is true, and hence prints the line, whenever any of these happens:

  • tata is not found in the line.
  • f++ is true. This is the tricky part: first time f is 0 as default, so first f++ will return False and not print the line. From that moment, it will increment from an integer value and will be True.
like image 23
fedorqui 'SO stop harming' Avatar answered Sep 29 '22 12:09

fedorqui 'SO stop harming'