61

I would like to insert lines into a file in bash starting from a specific line.

Each line is a string which is an element of an array

line[0]="foo"
line[1]="bar"
...

and the specific line is 'fields'

file="$(cat $myfile)"
for p in $file; do
    if [ "$p" = 'fields' ]
        then insertlines()     #<- here
    fi
done
Chris Seymour
  • 83,387
  • 30
  • 160
  • 202
Sadiel
  • 1,344
  • 3
  • 18
  • 33

4 Answers4

106

This can be done with sed: sed 's/fields/fields\nNew Inserted Line/'

$ cat file.txt 
line 1
line 2 
fields
line 3
another line 
fields
dkhs

$ sed 's/fields/fields\nNew Inserted Line/' file.txt 
line 1
line 2 
fields
New Inserted Line
line 3
another line 
fields
New Inserted Line
dkhs

Use -i to save in-place instead of printing to stdout

sed -i 's/fields/fields\nNew Inserted Line/'

As a bash script:

#!/bin/bash

match='fields'
insert='New Inserted Line'
file='file.txt'

sed -i "s/$match/$match\n$insert/" $file
Chris Seymour
  • 83,387
  • 30
  • 160
  • 202
  • When using `sed -i` does this rewrite the entire file but with `sed`'s replacements or is this similar to just opening up the file in a text editor and manually inserting the strings? I ask because I need to do this with a big file and having to write that much over and over again will take forever and wear out my SSDs and HDDs quicker. – leetbacoon Aug 01 '19 at 05:29
  • 2
    What exactly do you expect a text editor to do physically if you open up a file, manually insert the strings and save it? – Marcus Jan 07 '20 at 17:15
  • sed -i is not anymore working. On Solaris11.4 it throws "illegal option -i" – Daniel Horvath Dec 09 '20 at 12:18
16

Or anoter one example with the sed:

Prepare a test.txt file:

echo -e "line 1\nline 2\nline 3\nline 4" > /tmp/test.txt

cat /tmp/test.txt
line 1
line 2
line 3
line 4

Add a new line into the test.txt file:

sed -i '2 a line 2.5' /tmp/test.txt
# sed for in-place editing (-i) of the file: 'LINE_NUMBER a-ppend TEXT_TO_ADD'

cat /tmp/test.txt
line 1
line 2
line 2.5
line 3
line 4
s3n0
  • 596
  • 3
  • 14
7

This is definitely a case where you want to use something like sed (or awk or perl) rather than readling one line at a time in a shell loop. This is not the sort of thing the shell does well or efficiently.

You might find it handy to write a reusable function. Here's a simple one, though it won't work on fully-arbitrary text (slashes or regular expression metacharacters will confuse things):

function insertAfter # file line newText
{
   local file="$1" line="$2" newText="$3"
   sed -i -e "/^$line$/a"$'\\\n'"$newText"$'\n' "$file"
}

Example:

$ cat foo.txt
Now is the time for all good men to come to the aid of their party.
The quick brown fox jumps over a lazy dog.
$ insertAfter foo.txt \
   "Now is the time for all good men to come to the aid of their party." \
   "The previous line is missing 'bjkquvxz.'"
$ cat foo.txt
Now is the time for all good men to come to the aid of their party.
The previous line is missing 'bjkquvxz.'
The quick brown fox jumps over a lazy dog.
$ 
Mark Reed
  • 91,912
  • 16
  • 138
  • 175
-1

sed is your friend:

:~$ cat text.txt 
foo
bar
baz
~$ 

~$ sed '/^bar/\na this is the new line/' text.txt > new_text.txt
~$ cat new_text.txt 
foo
bar
this is the new line
baz
~$ 
oz123
  • 27,559
  • 27
  • 125
  • 187
  • 2
    that won't work; you need a backslash and a newline in the sed command string after the `a`, not a space. – Mark Reed Nov 09 '12 at 22:11