MirrG
MirrG

Reputation: 406

Awk exchange values from different columns

I have a file of the following structure:

4 1:4 3:1 6:1 56:2 57:4 58:7 59:1 66:2
1 2:1 56:1 57:1 58:2 59:2 65:1
8 1:2 2:1 3:8 12:1 56:1 57:2 58:2 59:2 66:1 67:2

What I need to do is to switch the values associated with 56 and 57 to the ones associated with 58 and 59:

4 1:4 3:1 6:1 56:7 57:1 58:2 59:4 66:2
1 2:1 56:2 57:2 58:1 59:1 65:1
8 1:2 2:1 3:8 12:1 56:2 57:2 58:1 59:2 66:1 67:2

For now I am trying to perform the replacement with at least two columns using something like:

awk '{
         for ( i=2;i<=NF;i++ )
         {
            split(, a, ":") 
            arr[a[1]] = a[2]
         }
      }
      END {
         n = asorti(arr, dest)
         ORS= 
         for ( i=1; i<=n; i++ ) 
         { 
            if ( dest[i] != 56 && dest[i] != 58 ) 
               print dest[i] ":" arr[dest[i]]
            else 
            { 
               if ( dest[i] == 56 ) 
                  print dest[i] ":" arr[dest[i+2]] 
               if ( dest[i] == 58 ) 
                  print dest[i] ":" arr[dest[i-2]]
            }
         }
      }' file

However, that looks quite bulky and final indexes are not sorted properly. Will appreciate any other solution.

Upvotes: 0

Views: 52

Answers (2)

Tom Fenech
Tom Fenech

Reputation: 74595

If you can rely on the ordering always being 56, 57, 58, 59, then you can do this with sed:

sed -E 's/(56:)([0-9]+)(.*57:)([0-9]+)(.*58:)([0-9]+)(.*59:)([0-9]+)/\1\6\3\8\5\2\7\4/' file

Just capture all the parts and reshuffle them in the replacement.

The odd-numbered capture groups refer to the "labels" and any leading content, except for in the first case where we don't have to touch that part of the line. The even-numbered ones refer to the numerical values.

Upvotes: 1

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

GNU awk solution:

awk '{ 
         r=gensub(/\<(56:)([0-9]+) (57:)([0-9]+) (58:)([0-9]+) (59:)([0-9]+)/, 
                 "\\1\\6 \\3\\8 \\5\\2 \\7\\4", "g"); 
         print r 
     }' file

The output:

4 1:4 3:1 6:1 56:7 57:1 58:2 59:4 66:2
1 2:1 56:2 57:2 58:1 59:1 65:1
8 1:2 2:1 3:8 12:1 56:2 57:2 58:1 59:2 66:1 67:2

gensub(regexp, replacement, how [, target])

Search the target string target for matches of the regular expression regexp. If how is a string beginning with ‘g’ or ‘G’ (short for “global”), then replace all matches of regexp with replacement.

Upvotes: 1

Related Questions