7

I have a text file employees:

Chen Cho 5/19/63 203-344-1234 $76
Tom Billy 4/12/45 913-972-4536 $102
Larry White 11/2/54 908-657-2389 $54
Bill Clinton 1/14/60 654-576-4114 $201
Steve Ann 9/15/71 202-545-8899 $58

When I do awk '$4 < 40' employees, I get:

203-344-1234
202-545-8899

It gives the same output until < 65 and when I compare $4 < 66, I get:

203-344-1234
654-576-4114
202-545-8899

I'm confused with this behaviour of awk. It seems like it's only comparing the first two digits of the field instead of throwing some error stating the comparison can't be done or something.

My question is: How is awk comparing/behaving in this case? Thank you.

1
  • Shouldn't this file be a tab delimited file?
    – user232326
    Commented Apr 26, 2022 at 22:30

1 Answer 1

15

In short, this is an alphabetical comparison for GNU awk.

Because we compare a string ('203-344-1234') with a number ('40').


What is the comparison type

From [GNU awk] String Type versus Numeric Type:

When two operands are compared, either string comparison or numeric comparison may be used. This depends upon the attributes of the operands, according to the following symmetric matrix:

    +---------------------------------------------------------
    |                 STRING          NUMERIC         STRNUM
    +---------------------------------------------------------
    | STRING  |       string          string          string
    | NUMERIC |       string          numeric         numeric
    | STRNUM  |       string          numeric         numeric
    +---------------------------------------------------------

How a number is converted to string

From [GNU awk] Comparison Operators:

When comparing operands of mixed types, numeric operands are converted to strings using the value of CONVFMT (see section Conversion of Strings and Numbers).

Following the link above, we see how the number is converted to a string for the comparison. A string is created with a call to sprintf() and the awk predefined variable CONVFMT is used for formatting, default it is "%.6g", which would keep at most 6 significant digits for a decimal. But for an integer:

As a special case, if a number is an integer, then the result of converting it to a string is always an integer, no matter what the value of CONVFMT may be.

For this case, $4 is 203-344-1234, is a string, not a number. And the second argument is a number, converted to the string '40' (regardless of the CONVFMT value, because it is an integer).


How to force string or number

Some additional information, from the same page:

If, for some reason, you need to force a number to be converted to a string, concatenate that number with the empty string, "". To force a string to be converted to a number, add zero to that string

Sometimes, to ensure that a field will be used as numeric, we write it like $1+0. For example, in this case, if we force $4+0 it will be an integer with the first three digits, 203 (that's it, the attempt to create a number ended at the first non-numeric character).

2
  • Your now-second quote is incomplete to the point of being wrong. Immediately following the text you copied, it actually links to gnu.org/software/gawk/manual/html_node/Strings-And-Numbers.html which does describe CONVFMT, but then adds "As a special case, if a number is an integer, [it is converted as an integer and CONVFMT is not used]". 40 is an integer. Commented Jun 5, 2022 at 0:19
  • Updated, thank you @dave_thompson_085
    – thanasisp
    Commented Jun 5, 2022 at 10:00

You must log in to answer this question.

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