24

UPDATED:

Using sed, how can I insert (NOT SUBSTITUTE) a new line on only the first match of keyword for each file.

Currently I have the following but this inserts for every line containing Matched Keyword and I want it to only insert the New Inserted Line for only the first match found in the file:

sed -ie '/Matched Keyword/ i\New Inserted Line' *.*

For example:

Myfile.txt:

Line 1
Line 2
Line 3
This line contains the Matched Keyword and other stuff
Line 4
This line contains the Matched Keyword and other stuff
Line 6

changed to:

Line 1
Line 2
Line 3
New Inserted Line
This line contains the Matched Keyword and other stuff
Line 4
This line contains the Matched Keyword and other stuff
Line 6
SSS
  • 2,344
  • 8
  • 22
  • 27
  • Possible duplicate of [this question](http://stackoverflow.com/q/148451/1086804) - you may be able to adapt it by using newline and backreferences. See also [this sed guide](http://www.linuxtopia.org/online_books/linux_tool_guides/the_sed_faq/sedfaq4_004.html) – Preet Kukreti Apr 02 '12 at 02:18
  • Does this answer your question? [How to use sed to replace only the first occurrence in a file?](https://stackoverflow.com/questions/148451/how-to-use-sed-to-replace-only-the-first-occurrence-in-a-file) – rogerdpack Jan 02 '20 at 23:37

4 Answers4

22

You can sort of do this in GNU sed:

sed '0,/Matched Keyword/s//New Inserted Line\n&/'

But it's not portable. Since portability is good, here it is in awk:

awk '/Matched Keyword/ && !x {print "Text line to insert"; x=1} 1' inputFile

Or, if you want to pass a variable to print:

awk -v "var=$var" '/Matched Keyword/ && !x {print var; x=1} 1' inputFile

These both insert the text line before the first occurrence of the keyword, on a line by itself, per your example.

Remember that with both sed and awk, the matched keyword is a regular expression, not just a keyword.

UPDATE:

Since this question is also tagged , here's a simple solution that is pure bash and doesn't required sed:

#!/bin/bash

n=0
while read line; do
  if [[ "$line" =~ 'Matched Keyword' && $n = 0 ]]; then
    echo "New Inserted Line"
    n=1
  fi
  echo "$line"
done

As it stands, this as a pipe. You can easily wrap it in something that acts on files instead.

Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
ghoti
  • 45,319
  • 8
  • 65
  • 104
13

If you want one with sed*:

sed '0,/Matched Keyword/s//Matched Keyword\nNew Inserted Line/' myfile.txt

*only works with GNU sed

Squazic
  • 3,670
  • 3
  • 26
  • 40
  • 2
    This doesn't do anything for me at all. – Graham Apr 02 '12 at 03:37
  • 5
    Ah, your solution is apparently specific to GNU sed. Though it's still wrong, alas. – Graham Apr 02 '12 at 03:39
  • Works for me with `GNU sed version 4.2.1`. @Squazic, maybe you want to qualify your answer. Good luck to all. – shellter Apr 02 '12 at 04:21
  • This worked for me. I just swapped the Matched Keyword with the New Inserted Line since I wanted the insertion to occur before the Matched Keyword. Thanks everyone for your inputs. – SSS Apr 02 '12 at 16:05
9

This might work for you:

sed -i -e '/Matched Keyword/{i\New Inserted Line' -e ':a;n;ba}' file

You're nearly there! Just create a loop to read from the Matched Keyword to the end of the file.

After inserting a line, the remainder of the file can be printed out by:

  1. Introducing a loop place holder :a (here a is an arbitrary name).
  2. Print the current line and fetch the next into the pattern space with the ncommand.
  3. Redirect control back using the ba command which is essentially a goto to the a place holder. The end-of-file condition is naturally taken care of by the n command which terminates any further sed commands if it tries to read passed the end-of-file.

With a little help from bash, a true one liner can be achieved:

sed $'/Matched Keyword/{iNew Inserted Line\n:a;n;ba}' file

Alternative:

sed 'x;/./{x;b};x;/Matched Keyword/h;//iNew Inserted Line' file

This uses the Matched Keyword as a flag in the hold space and once it has been set any processing is curtailed by bailing out immediately.

potong
  • 55,640
  • 6
  • 51
  • 83
  • ummm, yea, can you give a fully working example as I'm not sure how to create this "loop" in a sed oneline expression. – johnnyB Oct 29 '13 at 20:15
0

If you want to append a line after first match only, use AWK instead of SED as below

awk '{print} /Matched Keyword/ && !n {print "New Inserted Line"; n++}' myfile.txt

Output:

Line 1
Line 2
Line 3
This line contains the Matched Keyword and other stuff
New Inserted Line
Line 4
This line contains the Matched Keyword and other stuff
Line 6
Zaheer
  • 66
  • 2
  • 7