Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change the first occurrence of a line containing a pattern?

Tags:

sed

I need to find the line with first occurrence of a pattern, then I need to replace the whole line with a completely new one.

I found this command that replaces the first occurrence of a pattern, but not the whole line:

sed -e "0,/something/ s//other-thing/" <in.txt >out.txt

If in.txt is

one two three
four something 
five six
something seven

As a result I get in out.txt:

one two three
four other-thing
five six
something seven

However, when I try to modify this code to replace the whole line, as follows:

sed -e "0,/something/ c\COMPLETE NEW LINE" <in.txt >out.txt

This is what I get in out.txt:

COMPLETE NEW LINE
five six
something seven

Do you have any idea why the first line is lost?

like image 367
JulioSergio Avatar asked Jul 12 '20 04:07

JulioSergio


People also ask

Which is the correct command to replace the first occurrence?

Basically use grep to print the first occurrence and stop there. Additionally print line number ie 5:line . Pipe that into sed and remove the : and anything after so you are just left with a line number. Pipe that into sed which adds s/.

How do I match only the first occurrence of a pattern?

4.11. How do I match only the first occurrence of a pattern? (1) The general solution is to use GNU sed or ssed, with one of these range expressions. The first script ("print only the first match") works with any version of sed: (2) If you cannot use GNU sed and if you know the pattern will not occur on the first line, this will work:

How do I print only the first occurrence of a line?

Basically use grep to print the first occurrence and stop there. Additionally print line number ie 5:line. Pipe that into sed and remove the : and anything after so you are just left with a line number.

Is there a way to hold the pattern on the first line?

Still another solution, using a flag in the hold space. This is portable to all seds and works if the pattern is on the first line:

Why does 1//not match the first occurrence of a range?

When that happens, range address 1,//, which normally finds the first occurrence starting from line 2, will not match, and the range will not be processed, because the address is evaluated when the current line is already 2. Conversely, if there's no match on the 1st line, 1,// will be entered, and will find the true first match.


2 Answers

The c\ command deletes all lines between and inclusive the first matching address through the second matching address, when used with 2 addresses, and prints out the text specified following the c\ upon matching the second address. If there is no line matching the second address in the input, it just deletes all lines (inclusively) between the first matching address through the last line. Since you want to replace one line only, you shouldn't use the c\ command on an address range. The c\ is immediately followed by a new-line character in normal usage. The 0,/regexp/ address range is a GNU sed extension, which will try to match regexp in the first input line too, which is different from 1,/regexp/ in that aspect. So, the correct command in GNU sed could be

sed '0,/something/{/something/c\
COMPLETE NEW LINE
}' < in.txt

or simplified as pointed out by Sundeep

sed '0,/something/{//c\
COMPLETE NEW LINE
}' < in.txt

or a one-liner,

sed -e '0,/something/{//cCOMPLETE NEW LINE' -e '}' < in.txt

if a literal new-line character is not desirable.

This one-liner also works as pointed out by potong:

sed '0,/something/!b;//cCOMPLETE NEW LINE' in.txt
like image 99
M. Nejat Aydin Avatar answered Jan 03 '23 16:01

M. Nejat Aydin


This might work for you (GNU sed):

sed '1!b;:a;/something/!{n;ba};cCOMPLETE NEW LINE' file

Set up a loop that will only operate from the first line.

Within in the loop, if the key word is not found in the current line, print the current line, fetch the next and repeat until the end of the file or a match is found.

When a match is found, change the contents of the current line to the required result.

N.B. The c command terminates any further processing of sed commands in the same way the d command does.

If there are lines in the input following the key word match, the negation of address at the start of the sed cycle will capture these lines and result in their printing and no further processing.

An alternative:

sed 'x;/./{x;b};x;/something/h;//cCOMPLETE NEW LINE' file

Or (specific to GNU and bash):

sed $'0,/something/{//cCOMPLETE NEW LINE\n}' file
like image 43
potong Avatar answered Jan 03 '23 18:01

potong