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