Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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 :-)

share|improve this question
add comment

3 Answers 3

up vote 1 down vote accepted

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.
share|improve this answer
add comment
/<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
share|improve this answer
    
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 '12 at 11:01
add comment

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.)

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.