2
Input file tab separated:
A   |B   |  C | KEY  |  D|  E|  F  |G     | H | I | J   |   k |      
----|----|----|------|---|---|-----|------|---|---|-----|-----|      
word|word|word| one  |  8|  8|qw123| ""   | ""| ""| word| word|      
word|word|word| one  |  8|  8|qw234| ""   | ""| ""| word| word|      
word|word|word| one  |  8|  8|qw111| er432| ""| ""| word| word|      
word|word|word| seven|  8|  8|tr123| ""   | ""| ""| word| word|      
word|word|word| seven|  8|  8|ww000| ""   | ""| ""| word| word|      


Desired Output:                                                                     
A   |B   |  C | KEY  |D |E |F    |G    |H    |I    |J   |K   |  
----|----|----|------|--|--|-----|-----|-----|-----|----|----|
word|word|word|one   | 8| 8|qw123|qw234|qw111|er432|word|word|
word|word|word|one   | 8| 8|qw123|qw234|qw111|er432|word|word|
word|word|word|one   | 8| 8|qw123|qw234|qw111|er432|word|word|
word|word|word|seven | 8| 8|tr123|ww000|""   |""   |word|word|
word|word|word|seven | 8| 8|tr123|ww000|""   |""   |word|word|

It is about merging the range of columns [F to I] with the same KEY. Is it possible to achieve this without using arrays in AWK? How I can control when the value of the key column changes?

4
  • What if there are more than four values in the combined F-G-H-I list?
    – rici
    Nov 10, 2015 at 17:24
  • That's not gonna happen. As much it will have to combine four values.
    – Polucho
    Nov 10, 2015 at 19:44
  • The other fields are not necessarily the same in rows with the same key, right?
    – rici
    Nov 10, 2015 at 19:53
  • No, we must respect the other columns with their values ​​and positions. The only thing that must change is the range [F to I]
    – Polucho
    Nov 10, 2015 at 20:02

1 Answer 1

1

I don't see how you could do this in Awk without using arrays. It would be more convenient in Gawk, which allows array elements to be arrays, but it's easy enough to do with ordinary Awk simulated-multidimensional arrays.

Basically, we need to remember input lines and then output them (with the updated F-I fields) when the key changes. We need to also do that at the end of the file. For convenience, we use an output function since it will inevitably be called from two places.

The following uses fixed column numbers: 1-6 and 11-12 for the standard data fields, with 4 being the key field, and 7-10 for the merged fields, which I called tags for want of a better name. That's not great style, and it should probably be factored out into some variables.

awk -F '\t' '
  function show_and_reset(            i, c) {
    for (i = 1; i <= count; ++i) {
      for (c = 1; c <= 6; ++c) printf "%s\t", data[i,c]
      for (f in tags) printf "%s\t", f;
      for (c = ntags; c <= 3; ++c) printf "\t" 
      for (c = 11; c <= 12; ++c) printf "\t%s", data[i,c]
      print ""
    }
    /* Clear the holding data */
    for (f in tags) delete tags[f]
    ntags = 0;
    count = 0
  }
  /* Record one line of data */
  function record(                   c) {
    ++count;
    for (c = 1; c <= 6; ++c) data[count,c] = $c
    for (c = 11; c <= 12; ++c) data[count,c] = $c
    for (c = 6; c <= 10; ++c) 
      if ($c != "" && !tags[$c]++) ++ntags;
  }
  $4 != key { show_and_reset(); key = $4; }
            { record(); }
  END       { show_and_reset(); }
'
2
  • And using only one array, only for the combination of the range [F to I]?
    – Polucho
    Nov 11, 2015 at 9:15
  • @Polucho: The first line you want to print contains data which has not yet been read. Since no version of awk implements time travel, that can only work if you either store the first line until you have all the data, or you read the file twice. Awk does not provide seek (and not all input streams implement seek, either), so rereading the file is problematic. That leaves us with storing the data until it is possible to print it, as in the solution I propose.
    – rici
    Nov 11, 2015 at 15:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .