6

I'm trying to build an awk statement to read this file:

A   1,2,3   *
A   4,5,6   **
B   1
B   4,5     *

and build a file like this:

A   1,2,3   *    3   1   0.333
A   4,5,6   **   3   2   0.666
B   1            1   0   0
B   4,5     *    2   1   0.5

In this new file, the first three columns are the same as in the original file. The fourth column must contain the number of comma-separated elements in column 2. The fifth column must contain the number of characters in column 3. The last column contains the proportion of column 5 on column 4 (i.e., column 5 divided by column 4).

I'm trying the following code:

awk '{print $1"\t"$2"\t"$3"\t"(NF","$2 -1)"\t"length($3)"\t"(length($3)/(NF","$2-1))}' file1 > file2

But I got the following output:

A   1,2,3   *    3,0   1   0.333333
A   4,5,6   **   3,3   2   0.666667
B   1            2,0   0   0
B   4,5     *    3,3   1   0.333333

I can't figure out what I'm doing wrong for column 4.

6

You seem to be hoping that (NF","$2 -1) will be treated as a function that will return the number of comma-delimited elements in field $2 - it won't. NF is always the number of fields in the record.

Instead, you can use awk's split function split($2,a,",") which splits field $2 into an array a and returns the number of elements. You can also tidy up the code by using setting the output filed separator to tab instead of using explicit "\t" in your print statement

awk '{l2=split($2,a,","); OFS="\t"; print $1, $2, $3, l2, length($3), length($3)/l2}' file1
  • I pasted your code, and I get back awk: line 1: illegal reference to array a . So I tried: awk '{split($2,a,",")}' file1; awk '{OFS="\t"; print $1, $2, $3, length(a), length($3), length($3)/length(a)}' file1 > file2 which does not give errors, but column 4 has zeros. – dovah Jul 17 '14 at 12:19
  • OK apparently mawk doesn't support length() on an array variable - please see updated answer – steeldriver Jul 17 '14 at 12:35
3

Here's a Perl approach:

$ perl -lane '@k=($F[1]=~/,/g); $i=$#k+2; $l=length($F[2]); 
              print "@F $i $l ", $l/$i' file 
A 1,2,3 * 3 1 0.333333333333333
A 4,5,6 ** 3 2 0.666666666666667
B 1 1  0
B 4,5 * 2 1 0.5

Or, with printf for pretty formatting:

$ perl -lane '@k=($F[1]=~/,/g); $i=$#k+2; $l=length($F[2]); 
              printf "%s %-5s %-3s %s %3s %10f\n",@F,$i,$l,$l/$i' file 
A 1,2,3 *   3   1   0.333333
A 4,5,6 **  3   2   0.666667
B 1     1      0   0.000000
B 4,5   *   2   1   0.500000

Explanation

  • -lane : the -l removes trailing newlines from each input line; the -a automatically splits each input line into the array @F on whitespace; the -n means "read the input file line by line" and the -e lets you pass a script as a commandline parameter.
  • @k=($F[1]=~/,/g); $i=$#k+2; : the array @k contains all the commas found in the second field. Then, $i is set to the greatest index is @F ($#F) plus two. The plus 2 is needed because i) arrays are counted from 0 so the greatest index of a single-element array will be 0. We're counting commas, not values, so we need to add one more since 1,2 has two values but only one comma.
  • $l=length($F[2]); : $l is now the number of characters of the 3d field.
  • print "@F $i $l ", $l/$i : print the requested information. @F is the line from the input file, and the rest are what you asked for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.