1

How do insert lines of text into file after a particular line in unix ?

Background: The file is an autogenerated textfile but I manually have to edit it every time it is regenerated to add in 4 additional lines after a particular line. I can gurantee that this line will always be in the file but I cannot guarantee excalty what line it will be on so I want the additional lines to be added on the basis of the position of this line rather than adding to a fixed rownumber. I want to automate this process as it is part of my build process.

I'm using Mac OSX so I can make use of unix comand line tools, but Im not very familiar with such tools and cannot work out how to do this.

EDIT

Thanks for the solution, although I havent managed to get them working yet:

I tried Sed solution

sed -i '/<string>1.0</string>/ a <key>CFBundleHelpBookFolder</key>\
<string>SongKongHelp</string>\
<key>CFBundleHelpBookName</key>\
<string>com.jthink.songkong.Help</string>
' /Applications/SongKong.app/Contents/Info.plist

but get error

sed: 1: "/Applications/SongKong. ...": invalid command code S

and I tried the bash solution

#!/bin/bash

    while read line; do
      echo "$line"
      if [[ "$line" = "<string>1.0</string>"]]; then
        cat mergefile.txt    # or echo or printf your extra lines
      fi
    done < /Applications/SongKong.app/Contents/Info.plist

but got error

./buildosx4.sh: line 5: syntax error in conditional expression: unexpected token `;'
./buildosx4.sh: line 5: syntax error near `;'
./buildosx4.sh: line 5: `  if [[ "$line" = "<string>1.0</string>"]]; then'

EDIT 2 Now working, i was missing a space

#!/bin/bash

    while read line; do
      echo "$line"
      if [[ "$line" = "<string>1.0</string>" ]]; then
        cat mergefile.txt    # or echo or printf your extra lines
      fi
    done < /Applications/SongKong.app/Contents/Info.plist
Paul Taylor
  • 13,411
  • 42
  • 184
  • 351

4 Answers4

2

Assuming the marker line contains fnord and nothing else;

awk '1;/^fnord$/{print "foo"; print "bar";
    print "baz"; print "quux"}' input >output
tripleee
  • 175,061
  • 34
  • 275
  • 318
0

use the sed 'a command with a regex for the line you need to match

sed -i '/the target line looks like this/ a this is line 1\
this is line 2\
this is line 3\
this is line 4
' FILENAME
user340140
  • 628
  • 6
  • 10
0

The problem can be solved efficiently for any filesize by this algorithm:

  1. Read each line from the original file and print it to a tempfile.
  2. If the last line was the marker line, print your insertion lines to the tempfile
  3. Print the remaining lines
  4. Rename the tempfile to the original filename.

As a Perl script:

#!perl
use strict; use warnings;

$^I = ".bak"; # create a backup file

while (<>) {
  print;
  last if /regex to determine if this is the line/;
}

print <<'END';
Yourstuff
END

print while <>; # print remaining lines
# renaming automatically done.

Testfile:

foo
bar
baz
qux
quux

Regex is /^ba/.

Usage: $ perl this_script.pl source-file

The testfile after processing:

foo
bar
Yourstuff
baz
qux
quux
amon
  • 57,091
  • 2
  • 89
  • 149
0

Another way to look at this is that you want to merge two files at some point in one of the files. If your extra four lines were in a separate file, you could make a more generic tool like this:

#!/usr/bin/awk

BEGIN {
  SEARCH=ARGV[1];    # Get the search string from the command line
  delete ARGV[1];    # Delete the argument, so subsequent arguments are files
}

# Collect the contents of the first file into a variable
NR==FNR { 
  ins=ins $0 "\n";
  next;
}

1    # print every line in the second (or rather the non-first) file

# Once we're in the second file, if we see the match, print stuff...
$0==SEARCH {
  printf("%s", ins);    # Using printf instead of print to avoid the extra newline
  next;
}

I've spelled this out for ease of documentation; you could obviously shorten it to something that looked more like triplee's answer. You'd invoke this like:

$ scriptname "Text to match" mergefile.txt origfile.txt > outputfile.txt

Done this way, you'd have a tool that could be used to achieve this kind of merge on different files and with different text.

Alternately, you could of course do this in pure bash.

#!/bin/bash

while read line; do
  echo "$line"
  if [[ "$line" = "matchtext" ]]; then
    cat mergefile.txt    # or echo or printf your extra lines
  fi
done < origfile.txt
ghoti
  • 45,319
  • 8
  • 65
  • 104
  • Tried your script but got error ./buildosx4.sh: line 5: syntax error in conditional expression: unexpected token `;' ./buildosx4.sh: line 5: syntax error near `;' ./buildosx4.sh: line 5: ` if [[ "$line" = "1.0"]]; then' – Paul Taylor Feb 16 '13 at 13:15
  • @PaulTaylor - I see from your updated question that you're missing the space before the `]]`. You need that space. – ghoti Feb 16 '13 at 14:40