Subsitute string in file 1 by line n of file 2

Hello,

My OS is Windows 10 and I am using Cygwin.

The content of file 1 is:
XXX string1

The content of file 2 is
4.156
2.312
3.527
1.687
etc....

I need to replace string 1 in file 1 by the content of line n in file 2.

So the expected output is e.g.:
XXX 3.527 (for n = 3)

I have the following script:

sed "s/string1/$(cat file2.txt)/" file1.txt > file3.txt

How can I adapt it to get the replacement of string 1 by the nth line of file 2?

Thanks in advance.

Hello supernono06,

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

awk -v n=3 'FNR==NR{a[FNR]=$0;next} {sub("string1",a[n])} 1' file2  file1

OR in case you directly want to assign value from file2 to file1 on 2nd field of file1 then following may help you.

 awk -v n=3 'FNR==NR{a[FNR]=$0;next} {$2=a[n]} 1' file2  file1
 

Thanks,
R. Singh

1 Like

Hello RavinderSingh13,

It works perfectly, many thanks.

If n is large, is there a way to use a loop to do the following:

 
awk -v n=1 'FNR==NR{a[FNR]=$0;next} {sub("string1",a[n])} 1' file2  file1
awk -v n=2 'FNR==NR{a[FNR]=$0;next} {sub("string2",a[n])} 1' file2  file1
awk -v n=3 'FNR==NR{a[FNR]=$0;next} {sub("string3",a[n])} 1' file2  file1
etc.� 

Thanks.

Hello supernono06,

You could HIT THANKS button left most corner of any post if you feel it helped you :b:. Now coming to your problem, no need to use a loop for this. There could be 2 situations for this.

1st: To substitute all the string keywords in file1 in that case following may help you.

awk  'FNR==NR{a[FNR]=$0;next} {sub("string1",a[FNR])} 1' file2  file1

Above will change them as per file2's line number so let's say string keywords comes on 1st, 3rd line of file1 so it will substitute string keyword with respective line's value from file2 in file1.

2nd: In case you want to give multiple values of line numbers which you want to change in file1, then following may help you.

awk -v n="1,4"  'BEGIN{num=split(n,array,",")} FNR==NR{a[FNR]=$0;next} /string/{count=count==num?1:++count;gsub("string",a[array[count++]])} 1' file2  file1

So in this case line number(s) 1st and 4th from file2's value will substituted on file1's keyword string . Also it will not bother line number on file1 side(asap a string (string) comes it will substitute it).

Thanks,
R. Singh

Hello RavinderSingh13,

Thanks, but it is not doing what I need, I will explain it better.

The file 1 content is:
�..
XXX string1
�.
YYY string2
...
ZZZ string3
...
AAA string4
�.
The file 2 content is:
3.333
4.251
1.121
5.456

The expected output is:
...
XXX 3.333
...
YYY 4.251

ZZZ 1.121
...
AAA 5.456

Thanks in advance.

Supernono06

Hello supernono06,

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

 awk 'FNR==NR{a[FNR]=$0;next} {print $1,a[FNR]}'  Input_file2  Input_file1
 

Thanks,
R. Singh

Hello RavinderSingh13,

Thanks but it is not working. With this script, the replacement takes place in the second field of the four 4th lines of the files, and all other 2nd fields of the remaining lines are removed.

I need to mention that there are lines above and below the strings I need to replace.

Supernono06

Hello supernono06,

So I am assuming 2 things here.

1st: You want to do replacement wherever string keyword is found on lines of Input_file1.

2nd: I am assuming that in case number of lines are lesser in Input_file2 than Input_file1(means keywords strings are coming more than the numbers in Input_file2) then once it reaches it last value(from Input_file2) then again it should start from beginning in Input_file2 values.

awk 'FNR==NR{a[FNR]=$0;val++;next} {count==val?"":count} /string/{print $1,a[++count];next} 1'  Input_file2  Input_file1

Thanks,
R. Singh

1 Like

Thanks a lot RavinderSingh13.

This works. I have another file 1 with content:
...
set title "XXX YYY I = 3 mol L^{-1} pH = string1"
...
set title "XXX YYY I = 2 mol L^{-1} pH = string2"
...
set title "XXX YYY I = 1.5 mol L^{-1} pH = string3"
...
set title "XXX YYY I = 1 mol L^{-1} pH = string4"
...
With your actual script, the output is:
...
set 3.333
...
set 4.251
...
set 1.121
...
set 5.456
...
I would like to obtain the following output please:
...
set title "XXX YYY I = 3 mol L^{-1} pH = 3.333"
...
set title "XXX YYY I = 2 mol L^{-1} pH = 4.251"
...
set title "XXX YYY I = 1.5 mol L^{-1} pH = 1.121"
...
set title "XXX YYY I = 1 mol L^{-1} pH = 5.456"
...
Thanks in advance.

Supernono06

Hello supernono06,

For this shown Input_file1, could you please try following and let me know if this helps you.

awk 'FNR==NR{a[FNR]=$0;val++;next} {count==val?"":count} /string/{sub(/string[0-9]+/,a[++count])} 1'  Input_file2  Input_file1

Thanks,
R. Singh

1 Like

Hello RavinderSingh13,

Thanks a lot. It works very well.

Here is my last question.

I have another file 2 with content:
3.333 #3M
4.251 #2M
1.121 #1.5M
5.456 #1M

With the actual script, the output is:
...
set title "XXX YYY I = 3 mol L^{-1} pH = 3.333 #3M"
...
set title "XXX YYY I = 2 mol L^{-1} pH = 4.251" #2M"
...
set title "XXX YYY I = 1.5 mol L^{-1} pH = 1.121 #1.5M"
...
set title "XXX YYY I = 1 mol L^{-1} pH = 5.456 #1M"

Please, is it possible to adapt the script to get:
...
set title "XXX YYY I = 3 mol L^{-1} pH = 3.333"
...
set title "XXX YYY I = 2 mol L^{-1} pH = 4.251"
...
set title "XXX YYY I = 1.5 mol L^{-1} pH = 1.121"
...
set title "XXX YYY I = 1 mol L^{-1} pH = 5.456"

Thanks a lot.

Supernono06

Hello supernono06,

Please do wrap your samples in CODE TAGS(see how my command looks similarly see co de button while editing your post and wrap your examples in it). Could you please try following then and let me know if this helps you.

awk 'FNR==NR{a[FNR]=$1;val++;next} {count==val?"":count} /string/{sub(/string[0-9]+/,a[++count])} 1'  Input_file2  Input_file1

Thanks,
R. Singh

1 Like

Hello RavinderSingh13,

Thanks a lot. Just a last thing please.

I have another file 1 as follows:

...
XXX; YYY; ZZZ; AAA string1   BBB; END
XXX; YYY; ZZZ; AAA string1   BBB; END
...
XXX; YYY; ZZZ; AAA string2   BBB; END
XXX; YYY; ZZZ; AAA string2   BBB; END
...
XXX; YYY; ZZZ; AAA string3   BBB; END
XXX; YYY; ZZZ; AAA string3   BBB; END
...
XXX; YYY; ZZZ; AAA string4   BBB; END
XXX; YYY; ZZZ; AAA string4   BBB; END
...

With the actual script, I get:

 
XXX; YYY; ZZZ; AAA 3.333   BBB; END
XXX; YYY; ZZZ; AAA 4.251   BBB; END
XXX; YYY; ZZZ; AAA 1.121   BBB; END
XXX; YYY; ZZZ; AAA 5.456   BBB; END
XXX; YYY; ZZZ; AAA         BBB; END
XXX; YYY; ZZZ; AAA         BBB; END
....
 

The strings are replaced in the four first lines and become empty for all other lines.

I would need the following output please:

...
XXX; YYY; ZZZ; AAA 3.333   BBB; END
XXX; YYY; ZZZ; AAA 3.333   BBB; END
...
XXX; YYY; ZZZ; AAA 4.251   BBB; END
XXX; YYY; ZZZ; AAA 4.251   BBB; END
...
XXX; YYY; ZZZ; AAA 1.121   BBB; END
XXX; YYY; ZZZ; AAA 1.121   BBB; END
...
XXX; YYY; ZZZ; AAA 5.456   BBB; END
XXX; YYY; ZZZ; AAA 5.456   BBB; END
...

Thanks again.

Supernono06

Hello supernono06,

Again assuming that your Input_file(s) are same as shown ones, if yes then following may help you here.

awk 'FNR==NR{a[FNR]=$1;val++;next} {count=count==val?0:count} match($0,/string[0-9]+/){prev=val=substr($0,RSTART,RLENGTH);if(!array[prev]++){count++};sub(val,a[count])} 1'  Input_file2   Input_file1

Adding a non-one liner form of solution too here.

awk '
FNR==NR{
  a[FNR]=$1;
  val++;
  next
}
{
  count=count==val?0:count
}
match($0,/string[0-9]+/){
  prev=val=substr($0,RSTART,RLENGTH);
  if(!array[prev]++){ count++ };
  sub(val,a[count])
}
1
'  Input_file2   Input_file1
 

Thanks,
R. Singh

1 Like

Thanks a lot RavinderSingh13, everything works as expected!

Supernono06