4

I want to insert some text in the middle of a file. The text to insert would be after a specific line, say, "<begin>". I don't know the line number, nor do I know the number of lines in the text to insert. I only know that after the line that reads "<begin>" I need to insert the content of another file.

I just don't know how to use awk to do something like this.

Thanks :-)

3 Answers 3

2

Create a file with the following code. You could save it as:
insertfile.awk (or whatever you wish)

    BEGIN{
        while ( (getline < outerfile) > 0 )
        {
            if ($0 == matchline) 
            {  
                if ("after" == includematch)
                {
                    print
                }
                if ("before" == includematch)
                {
                    holdline = $0
                }
                  while ( (getline < innerfile) > 0) 
                {
                    print
                }
                close(innerfile)
                if ("before" == includematch)
                {
                     print holdline
                     holdline = ""
                }
            }
            else
            {
                print
            }
        }
        close(outerfile)
    }

The awk command line parameters used are:

-v outerfile="file1.txt"    This is the name of the file you are searching (and printing).
-v innerfile="file2.txt"    This is the name of the file you will insert when you file a match
-v matchline="Search Text"  This is what you will search for as a line in file1.txt
-v includematch="before"    Optional: insert the file, before the matchline
-v includematch="after"     Optional: insert the file, after the matchline
-v includematch=""          If "includematch" is any other value, or empty, or not present, 
                            then insert the file, REPLACING matchline.
-f "insertfile.awk"         This is the name of the awk command file.

Then, to use it you call awk like this:

awk -v outerfile="file1.txt" -v innerfile="file2.txt" -v matchline="cat" -f "insertfile.awk"  
(Read and print "file1.txt".  Search for line containing only "cat". REPLACE "cat" lines with "file2.txt"  

awk -v outerfile="file1.txt" -v innerfile="file2.txt" -v matchline="dog" -v includematch="before" -f "insertfile.awk"
(Read and print "file1.txt".  Search for line containing only "dog". Insert "file2.txt" Before matched line.

awk -v outerfile="file1.txt" -v innerfile="file2.txt" -v matchline="bird" -v includematch="after" -f "insertfile.awk"
(Read and print "file1.txt".  Search for line containing only "bird". Insert "file2.txt" After matched line.

In the awk script, you can edit it like this:

Change $0 to $1 or $2 or other to match a specific word instead of the whole line.  
"hard-code" the file-names instead of outerfile and innerfile if you wish.

If you want to "pipe" the input data into the script instead of getting it from a file, edit the insertfile.awk script like this:

        {
            if ($0 == matchline) 
            {

                if ("after" == includematch)
                {
                    print
                }
                if ("before" == includematch)
                {
                    holdline = $0
                }

                while ( (getline < innerfile) > 0) 
                {
                    print
                }
                close(innerfile)

                if ("before" == includematch)
                {
                     print holdline
                     holdline = ""
                }

            }
            else
            {
                print
            }
            close(outerfile)
        }

Then, to use it you call awk like this:

type "somefile.txt" | awk -v innerfile="file2.txt" -v matchline="cat" -f "insertfile.awk"  
(Read and print STDIN.  Search for line containing only "cat". REPLACE "cat" lines with "file2.txt"  

type "anyfile.txt" | awk -v innerfile="file2.txt" -v matchline="dog" -v includematch="before" -f "insertfile.awk"
(Read and print STDIN.  Search for line containg only "dog". Insert "file2.txt" Before matched line.

type "otherfile.txt" | awk -v innerfile="file2.txt" -v matchline="bird" -v includematch="after" -f "insertfile.awk"
(Read and print STDIN.  Search for line containg only "bird". Insert "file2.txt" After matched line.
5
/<begin>/{
    insert_file("before_file.html")
    print $0
    insert_file("after_file.html")
    next
}
{
    print $0
}

where you will have to write the insert_file function which might look something like

function insert_file(file) {
    while (getline line <file)
        print line
    close(file)
}

Note that this exact version doesn't seem to be working as expected on my Mac when before_file and after_file are the same...I'm only getting the only the first copy. It probably has something to do with failing to close the file. I shall investigate. Yes, it is necessary to close the file, and that should be done in general for good practice.


Also, I think this might be even easier in sed...

For inserting the file after the key line

sed '/<begin>/r after_file.html' input_file

Inseting the file before is a little more complicated,

 sed -n -e '/^function/r before_file.html' -e 'x' -e 'p' input_file

so you could use a script like

/^function/r before_file.html
x
p

with

sed -n -f script input_file
1
  • With this sed script, you're going to have an issue with the last line, which is left unprinted in the hold space. You could fix by adding a final -e '${g;p}', or by making sure your input has an extra \n at the end.
    – dubiousjim
    Apr 19, 2012 at 11:01
2

Perl is awk's bigger brother.

perl -p -i -e 'print "some text\n" if /<begin>/' filename

If you have multiple <begin>s then it will need amending.

EDIT: Oh you wanted to insert a file

perl -MFile::Slurp -p -i -e 'print read_file("file2") if /<begin>/' filename

(tested OK but you might need cpan File::Slurp first.)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .