Insert text from file inline after matching pattern in another file

I’m trying to take the contents of a file and insert it after a matching pattern in another file using sed. My question is very similar to this question, but I wish to insert the contents of a file inline rather than on a new line. How can I do this?

Using the example question I referenced, the first answer does exactly what I want; however, I want the insertion to happen inline:

sed '/First/r file1.txt' infile.txt

The actual data I want to insert is a JSON file:

[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

In your linked question there is already good awk answer, just modify it a little bit by using printf instead of print to insert the content without newline:

awk '/First/ { printf $0; getline < "File1.txt" }1' infile.txt

Result:

Some Text here
FirstThis is text to be inserted into the File.
Second
Some Text here

You may want to add space or other delimeter after “First” with printf $0 " "; ...


If inserted file has many lines then:

awk '/First/{printf $0; while(getline line<"File1.txt"){print line};next}1' infile.txt

Result:

Some Text here
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]
Second
Some Text here

Method 2

You could use perl (get the file content and substitute pattern with pattern+file content):

perl -pe '$text=`cat insert.txt`; chomp($text); s/PAT/$&$text/' file.txt

add -i to edit in place; g to append after each PAT (pattern) occurrence, e.g.:

perl -i -pe '$text=`cat insert.txt`; chomp($text); s/PAT/$&$text/g' file.txt

Another way, using ed:

printf '%sn' /PAT/s/PAT/&\ / - kb ". r insert.txt" j 'b j ,p q | ed -s file.txt

to edit in-place, replace ,p with w:

 printf '%sn' /PAT/s/PAT/&\ / - kb ". r insert.txt" j 'b j w q | ed -s file.txt

Probably no one is interested how this works but anyway, printf passes a list of commands to ed:

/PAT/s/PAT/&             #   set address to first line matching PAT and
/                         #   split the line right after PAT
-                         #   set address one line before (return to the line matching PAT)
kb                        #   mark the current line
. r insert.txt            #   insert content of insert.txt after this line         
j                         #   join current line and the next
'b                        #   set  address to marked line (return to the line matching PAT)
j                         #   join current line and the next one
,p                        #   print file content
q                         #   quit editor

Or, without using printf and |:

ed -s file.txt <<< $'/PAT/s/PAT/&\n/n-nkbn. r insert.txtnjn'bnjnwnqn'

Method 3

So it would be a little tricky to make this work portably in sed – you should be looking to cut and/or paste with some regex precursor generating their script in that context – and this is because sed will always insert a newline before the output of a read. Still, w/ GNU sed:

sed '/First/{x;s/.*/cat file/e;H;x;s/n//}' <<IN 
First
Second
Third
IN

That works by executing cat every time it encounters your /First/ address. It does this in the hold space (kind of – an alternate buffer anyway – because I exchange them it actually happens in pattern space which used to be hold space) so as to preserve the contents of the line matching First and then appends cat‘s output to your line and removes the intervening newline.

OUTPUT:

First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
]
Second
Third

Now if you want the entire contents of the file to fit between two portions of a line that has to work a little differently because with the above command I just remove the trailing newline between the end of the matching line and the beginning of the file. Still, you can do this, too:

sed '/First/{s//&n/;h
         s/.*/{ cat file; echo .; }/e;G
         s/(.*).n(.*)n/21/
}' <<IN
Third
Second
First Second Third
Third
Second
First Second Third
IN

That splits the line at the match with a newline character, saves it in hold space, executes cat – which replaces pattern space with its output – Gets the contents of the hold space appended to our new pattern space following another newline character, and then rearranges on newline delimiters.

I do echo . to preserve any trailing newline characters in file – but if that is not your wish (and isn’t very relevant to your example anyway) you can do without it and remove the first . before .n in the following s///ubstitution.

Just before the rearrange pattern space looks like this:

^cat's output - any number of newlines.*.nmatch on Firstnrest of match$

OUTPUT:

Third
Second
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
] Second Third 
Third
Second
First[
    {
        "foo": "bar", 
        "baz": "biff",
        "data": [
            {
                "a": 1945619, 
                "b": [
                    {
                        "c": 512665, 
                        "d": "futz"
                    }
                ]
            }
        ]
    }
] Second Third


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x