Insert content of file before the first occurrence of a line starts with a pattern in another file

Hi all,

I'm new to scripting.. facing some problems while inserting content of a file into another file...

I want to insert content of a file (file2) into file1, before first occurrence of "line starts with pattern" in file1

file1

working on linux
its unix world
working on unix
its linux world
unix is best          --> first occurrence of line starts with unix
linux is easy
unix is easy
unix is best
linux is best

file2

Here is my content
i want to insert this

output

working on linux
its unix world
working on unix
its linux world
Here is my content
i want to insert this
unix is best      -->  first occurrence of line starts with unix
linux is easy
unix is easy
unix is best
linux is best

Can you please suggest me one liner shell command to get this output..

Really appreciate your help...

Try

awk '/^unix/ {while (0 < getline X < FI) print X} 1' FI="file2" file1
working on linux
its unix world
working on unix
its linux world
Here is my content
i want to insert this
unix is best          --> first occurrence of line starts with unix
linux is easy
unix is easy
unix is best
linux is best

Hello Jagadeesh kumar,

Could you please try following and let me know if this helps you.

awk '{$1=="unix"?++A[$1]:A[$1]} A[$1]==1{system("cat Input_file2")} 1' Input_file1

Output will be as follows.

working on linux
its unix world
working on unix
its linux world
Here is my content
i want to insert this
unix is best
linux is easy
unix is easy
unix is best
linux is best

EDIT: Following may help you in same too, a little different from previous one(not having array here).

awk '($1=="unix" && ++q==1){system("cat  Input_file2")} 1'  Input_file1

Output will be as follows.

working on linux
its unix world
working on unix
its linux world
Here is my content
i want to insert this
unix is best
linux is easy
unix is easy
unix is best
linux is best
 

Thanks,
R. Singh

2 Likes

R. Singh's answer is great.
You can also write it this way :

awk '$1=="unix" && !i {i++; system("cat  Input_file2")}1'  Input_file1

Comments :
I don't support the ++ operator in the pattern section of the script . This is why i++ appears in the action section ( i.e between {} )
Parenthesis are useless in the first pattern section.

Another approach is to use ed (I learnt it from Don C on this forum, thanks!)

Let's say I need to insert content of file f2 into file f1 before line starting with 3.

 
$ cat f1
1
2
3
$ cat f2
INSERT LINE
$ ed -s f1 <<-EOF > f3
> H
> /^3/-1r f2
> ,p
> Q
> EOF
 

This script says go to the beginning of the file (H),
then find first line starting with 3 (/^3)
then step one line up (-1)
then read in content of f2 (r f2)
then print out whole new content with (p), then quit (Q)

Result

 
$ cat f3
1
2
INSERT LINE
3
 

Almost...
The H command in ed doesn't move to the beginning of the file, it tells ed that if any of the following commands fail, ed should print a textual diagnostic message (or Help message) explaining what went wrong instead of just printing a question mark.

And, if I understand the requirements correctly, instead of printing results to the terminal, we want to update the file we are editing in place. So, in this case we would need something more like:

ed -s file1 <<EOF
	H
	/^unix/-1r file2
	w
	q
EOF

Where ed -s file1 uses ed to open a file named file1 without printing the size of the file when we open it and without printing the size of the file again when the script writes the updated file and <<EOF says that the following lines until we find a line that contains only EOF is to be treated as commands to be read and execute by ed . And the commands given to ed are:

  • H to turn on verbose help messages,
  • /^unix/-1r file2 to search for the first line starting with the string unix , move up one line from there, and read the contents of the file named file2 into the editing buffer after that line,
  • w to write the updated contents of the editing buffer back to the file named on the command line, and
  • q to cleanly quit. The q command can be skipped here and get the same results; I just like to tell ed to quit instead of having it hit EOF on the here-document when it is looking for another command to execute.

The things that could go wrong in this script include:

  1. not finding a line that starts with the string unix , and
  2. not finding a file named file2 .

Getting a message like script, line 2: no match or script, line 2: cannot open input file instead of just a ? helps the user of your script figure out what went wrong. That is why I give ed the H command (even though I know my script will work perfectly :rolleyes: ).

1 Like

Hi,
Another way with gnu sed:

$ cat f1.txt 
working on linux
its unix world
working on unix
its linux world
unix is best          --> first occurrence of line starts with unix
linux is easy
unix is easy
unix is best
linux is best
$ cat f2.txt 
Here is my content
i want to insert this
$ sed -e '0,/^unix/{/^unix.*/s//cat f2.txt;echo "&"/e;}' f1.txt
working on linux
its unix world
working on unix
its linux world
Here is my content
i want to insert this
unix is best          --> first occurrence of line starts with unix
linux is easy
unix is easy
unix is best
linux is best

Regards.

1 Like

@disedorgue. interesting trick with the GNU e-modifier..
I think you need 0,/^unix/.... otherwise it seems to insert twice in case the first line starts with the pattern...

1 Like

Hey all, thanks for you support.. What if i want the same action after 'n'th occurrence ?

Can you please help me

Hello Jagadeesh Kumar,

Let's say if you want to enter the text from Input_file2 after 5th occurrence so you could try following.

awk '($1=="unix" && ++q==6){system("cat Input_file2")} 1'  Input_file1
OR
awk '{$1=="unix"?++A[$1]:A[$1]} A[$1]==6{system("cat Input_file2")} 1' Input_file1

So point to not here is in above codes my condition checks for ==6 though we want to insert after 5th occurrence, so whenever you want after nth occurrence to print statements then please put n+1 in condition as simple as that, I hope this helps you.

EDIT: If you want to print contents of Input_file2 on exact occurrence(let's say 5th in this example here) of string then following may help you in same too.

awk '{$1=="unix"?++A[$1]:A[$1]} A[$1]==5{print;system("cat Input_file2");next} 1' Input_file1
OR
awk '($1=="unix" && ++q==5){print;system("cat  Input_file2");next} 1'  Input_file1

Thanks,
R. Singh

Thanks for notice, I corrected in post.

Otherwise, always with gnu sed for n'th' occurence ( 3rd occurence in example) :

sed -e '/^unix/{x;s/^/1/;/^1\{3\}$/!bno;x;s/^unix.*/cat f2.txt;echo "&"/e;b;:no;x;}' f1.txt

Regards.

Hi All,

Apologies for repeated questioning on the same.. I am very much new to this scripting. Please tell me some simple command using sed or awk (without using system) to achieve the task..

Thanks all in advance.

How far did you get with the proposals given?

Actually i need to execute this task on a a device which taken this input inside system command.. I am not able achieve my task with the given inputs..

example:

command = sed -e '/^unix/{x;s/^/1/;/^1\{3\}$/!bno;x;s/^unix.*/cat f2.txt;echo "&"/e;b;:no;x;}' f1.txt

I need to execute like system("command")

Means system will execute the command like a shell command..

---------- Post updated at 04:00 PM ---------- Previous update was at 04:00 PM ----------

Actually i need to execute this task on a a device which taken this input inside system command.. I am not able achieve my task with the given inputs..

example:

command = sed -e '/^unix/{x;s/^/1/;/^1\{3\}$/!bno;x;s/^unix.*/cat f2.txt;echo "&"/e;b;:no;x;}' f1.txt

I need to execute like system("command")

Means system will execute the command like a shell command..

I'm not sure to understand: what is it not work ?
Here, a way with command standard awk (without system function) :
Always 3rd occurence in example:

awk 'FNR == NR {str=str$0"\n";next}/^unix/ && ++x==3 {$0=str$0}1' f2.txt f1.txt

Regards.