Printing all combinations : Awk

$ cat key.txt
#ID1 Start
1|AA1
2|AA2
3|AA3
4|AA4
#ID1 Complete

#ID2 Start
1|BB1
2|BB2
3|BB3
#ID2 Complete

I was required this output:

AA1|BB1
AA1|BB2
AA1|BB3
AA2|BB1
AA2|BB2
AA2|BB3
AA3|BB1
AA3|BB2
AA3|BB3
AA4|BB1
AA4|BB2
AA4|BB3

I achieved this by writing this:

for KEY in `awk '/Start/ {print $1}' key.txt | tr '#' ' '`
        do
                sed -n "/$KEY Start/,/$KEY Complete/p" key.txt > .$KEY.tmp
        done

for id1 in `awk 'BEGIN {FS="|"} !/^#/ && NF!=0 {print $2}' .ID1.tmp`
        do
                for id2 in `awk 'BEGIN {FS="|"} !/^#/ && NF!=0 {print $2}' .ID2.tmp`
                        do
                                echo "$id1|$id2"
                        done
        done

Which worked for me :slight_smile:

Now problem is that, if in future somebody adds one more key to key.txt

i.e.

#ID1 Start
1|AA1
2|AA2
3|AA3
4|AA4
#ID1 Complete

#ID2 Start
1|BB1
2|BB2
3|BB3
#ID2 Complete

#ID3 Start
1|DD1
2|DD2
#ID3 Complete

I want to make my code generic, such that it takes all keys(ID1,ID2,ID3...) in key.txt and print the way I printed above.
(The hierarchy of KEY is as the order in key.txt)

i.e.

for loop for ID1
{
	for loop for ID2
		{
			for loop for ID3 
                           { ... }

		}

}

Please help.

Not quite sure ...
Something like this?
(use nawk or /usr/xpg4/bin/awk on Solaris)

awk 'f && /^[0-9]/ { _[$1] = $2; c = $1; next }
!NF { f = 0 }
/^[0-9]/ { __[++n] = $2 }
END { for (i=1; i<=c; i++) {
  for(j=1; j<=n; j++)
    print _ FS __[j] }
}' FS=\| f=1 file

Another approach:

awk 'BEGIN{FS=OFS="|"}
NR==FNR {
if(/#ID2 Start/){f=1;next}
if(/#ID2 Complete/){f=0}
if(f){a[i++]=$2}
next}
/#ID1 Start/{f=1;next}
/ID1 Complete/{exit}
{for(i in a){print $2,a}}
'  file file

If you get errors use nawk or /usr/xpg4/bin/awk on Solaris.

Thanks to radoulov and Franklin for your replies.

Just to make my requirement simple.

$ ls /temp
one  three  two

$ cat one
1
2
3

$ cat two
4
5

$ cat three
6
7
8

$ cat comb.sh
for i1 in `cat one`
        do
                for i2 in `cat two`
                        do
                                for i3 in `cat three`
                                        do
                                                echo "$i1|$i2|$i3"
                                        done
                        done
        done

$ ./comb.sh
1|4|6
1|4|7
1|4|8
1|5|6
1|5|7
1|5|8
2|4|6
2|4|7
2|4|8
2|5|6
2|5|7
2|5|8
3|4|6
3|4|7
3|4|8
3|5|6
3|5|7
3|5|8

But above code is hard-coded (I am specifying the file names in the code, I don't want to do that). what I want is that suppose if I add one more file called "four" with entries

$ cat four
9

Without adding a "for loop" for file "four", it should take automatically:

so that the output becomes:

1|4|6|9
1|4|7|9
1|4|8|9
1|5|6|9
1|5|7|9
1|5|8|9
2|4|6|9
2|4|7|9
2|4|8|9
2|5|6|9
2|5|7|9
2|5|8|9
3|4|6|9
3|4|7|9
3|4|8|9
3|5|6|9
3|5|7|9
3|5|8|9

i.e. How to construct the above "for loops" automatically based upon the files in /temp;; (Assuming the order of the loops is defined in a separate file)

$ cat order
one
two
three
four

Apologies for posting a huge query.

Below code take a and b as the file name

sed '1d;$d' a | awk 'BEGIN{FS="|"}{print $2}'> a.t
sed '1d;$d' b | awk 'BEGIN{FS="|"}{print $2}'> b.t
while read aline
do
	while read bline
	do
		echo $aline"|"$bline
	done < b.t
done < a.t
rm a.t b.t

Thank you Summer_Cherry for your reply. But its not printing the combinations of the values in the files as I stated.

Try the following script :

$ cat comb.sh
awk '
{
   file_count++;
   rec_num = 0;
   while (getline rec <$0)
     records[file_count, ++rec_num] = rec;
   close($0);
   records[file_count, "count"] = rec_num;
}

function comb_file(file_num, rec     ,rec_count ,r) {
   if (file_num > file_count) {
      print rec;
   } else {
      rec_count = records[file_num, "count"];
      for (r=1; r<=rec_count; r++)
         comb_file(file_num+1, rec (file_num>1 ? "|" : "") records[file_num, r]);
   }
}

END {
   rec = "";
   comb_file(1, rec);
}

' file_order.txt
$

Input files:

$ cat file_order.txt
file_1.txt
file_2.txt
file_3.txt
$ cat file_1.txt
F1.1
F1.2
F1.3
$ cat file_2.txt
F2.1
F2.2
$ cat file_3.txt
F3.1
F3.2
F3.3
F3.4
$

Output :

$ comb.sh
F1.1|F2.1|F3.1
F1.1|F2.1|F3.2
F1.1|F2.1|F3.3
F1.1|F2.1|F3.4
F1.1|F2.2|F3.1
F1.1|F2.2|F3.2
F1.1|F2.2|F3.3
F1.1|F2.2|F3.4
F1.2|F2.1|F3.1
F1.2|F2.1|F3.2
F1.2|F2.1|F3.3
F1.2|F2.1|F3.4
F1.2|F2.2|F3.1
F1.2|F2.2|F3.2
F1.2|F2.2|F3.3
F1.2|F2.2|F3.4
F1.3|F2.1|F3.1
F1.3|F2.1|F3.2
F1.3|F2.1|F3.3
F1.3|F2.1|F3.4
F1.3|F2.2|F3.1
F1.3|F2.2|F3.2
F1.3|F2.2|F3.3
F1.3|F2.2|F3.4
$

Jean-Pierre.

Jean-Pierre,
yes, this is what I was looking for. Thank you very much. It helped me a lot.