Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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.

share|improve this question
    
Why is the count of 1,2,3 equal to 3 but the count of 4,5 equal to 1? Do you want to count the number of comma-separated elements, or the number of commas? –  steeldriver Jul 17 at 12:38
    
I'd like the number of comma_separated elements. The count of 4,5 should be equal to 2. –  Dovah Jul 17 at 13:02
    
Oops I was misreading your output (the tabs don't line up) - please ignore my previous comment. –  steeldriver Jul 17 at 13:05

2 Answers 2

up vote 6 down vote accepted

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
share|improve this answer
    
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 at 12:19
    
OK apparently mawk doesn't support length() on an array variable - please see updated answer –  steeldriver Jul 17 at 12:35
    
Ok thanks! This works fine! –  Dovah Jul 17 at 13:05

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.
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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