1
votes

Assume a multi-line text file file1, where some lines contain the keyword "keyw".

$ cat file1
foo
bar keyw
baz
keyw qux
quux

Further assume a single-line text file file2 that contains as many strings as keyword occurrences in file1. The strings in file2 are separated by single whitespaces.

$ cat file2
string1 string2

I would like to append each string of file2 to a keyword-containing line of file1 based on the respective positions:

  • The first string in file2 appended to the first line in file1 that contains the keyword.

  • The second string in file2 appended to the second line in file1 that contains the keyword.

  • etc.

Here is the sought output:

$ awk ... file1 file2
foo
bar keyw string1
baz
keyw qux string2
quux

What awk-code would you use to conduct this replacement?

3
What did you try? I am sure some of your previous awk questions lead to interesting code that can help on this topic!fedorqui 'SO stop harming'
That is lucky that within 25 mins of asking your question you got the best best possible answer and so were able to accept it rather than waiting to see if a better answer would be posted.Ed Morton

3 Answers

0
votes

Below one gives desired o/p shown above,

Using awk

awk '
     FNR==NR{split($0,strarr);next}
     /keyw/{$0 = $0 OFS strarr[++i]}1
    ' file2 file1

Since you said,

Further assume a single-line text file file2 that contains as many strings as keyword occurrences in file1. The strings in file2 are separated by single whitespaces.

Explanation

  • split($0,strarr); is used, so that it will split record by default FS single space, and elements are saved in array strarr

  • So whenever records matches regexp /keyw/ of file1, we print array element, and variable i will incremented, and go to next line/record

  • +1 at the end does default operation that is print current/record/row, print $0. To know how awk works try, awk '1' infile, which will print all records/lines, whereas awk '0' infile prints nothing. Any number other than zero is true, which triggers the default behaviour.

Test Results:

$ cat file1
foo
bar keyw
baz
keyw qux
quux

$ cat file2
string1 string2

$ awk 'FNR==NR{split($0,strarr);next}/keyw/{$0 = $0 OFS strarr[++i]}1' file2 file1
foo
bar keyw string1
baz
keyw qux string2
quux
0
votes

This is all you need:

awk 'FNR==NR{split($0,a);next} /keyw/{$0=$0 OFS a[++c]} 1' file2 file1

It will work in any awk and will not add a blank space to the end of the non-targetted lines.

0
votes

If your Input_file is same as shown sample then could you please try following and let me know if this helps you.

awk 'FNR==NR{for(i=1;i<=NF;i++){a[i]=$i}next} {print $0,$0 ~ /keyw/?a[++j]:""}' FIlE2  FIlE1

Output will be as follows.

foo
bar keyw string1
baz
keyw qux string2
quux

Adding explanation here too on same.

awk '
FNR==NR{            ##Using FNR==NR condition which will be RUE when first Input_file is getting read. FNR and NR both represents number of lines, only difference between them is FNR value will be RESET on every next file is getting read and NR value will be keep on increasing till all the files are read.
 for(i=1;i<=NF;i++){##Starting a for loop which will run from i variable value 1 to till value of variable NF, where NF is out of the box variable whose value is the value of number of fields on a line.
  a[i]=$i}          ##Creating an array named a whose index is variable i and its value is $i(specific fields value)
  next              ##next will skip all further statements for current line(s).
}
{                   ##These statements will be executed when 2nd Input_file is being read.
  print $0,$0 ~ /keyw/?a[++j]:"" ##Printing the value of current line along with that checking of a line has string keyw in it then printing the value of array a whose index is value of j(whose value increments with 1 each time it comes here), else print NULL/nothing.
}
' FIlE2  FIlE1      ##mentioning the Input_file(s) here.