使用AWK从庞大的数字列表中获取特定范围的数值

时间:2018-08-29 07:02:20

标签: awk rhel nawk

我想取出一定范围的巨大数值,即720000002774991000到720000002774991099。所以我尝试了以下命令,

awk -F, ' { if (($1 >= 720000002774991000) && ($1 <= 720000002774991099)) print $0} ' VOUCHER_DUMP_REPORT.csv | head

VOUCHER_DUMP_REPORT.csv是我的输入文件,并且只有一列如此庞大的数字。

但是我得到的输出不准确,除了我给定的范围外,它还有一些其他值。

输出:

720000002774991065
720000002774991082
720000002774990985
720000002774991131
720000002774990919
720000002774991110
720000002774990947
720000002774991070
720000002774991042
720000002774991044

1 个答案:

答案 0 :(得分:2)

看起来您的数字太长,无法正确表示为整数。

您有两种可能的解决方案。使用GNU awk,您可以使用-M启用对arbitrary precision integers的支持:

awk -M '$1 >= 720000002774991000 && $1 <= 720000002774991099' file

否则,如果您确定第一列仅包含数字,则可以使用字符串比较:

awk -F, -v min=720000002774991000 -v max=720000002774991099 '
  BEGIN { lmin = length(min); lmax = length(max) } # save length of min and max
  "" $1 < min || "" $1 > max { next }            # skip lines which fail string comparison
  { l1 = length($1) }                            # calculate length of field
  l1 >= lmin && l1 <= lmax                       # check that string length is correct
' file

"" $1将空字符串与第一个字段的内容连接在一起,这迫使awk将其视为字符串而不是数字。没有这个,比较将是数字的,而不是词汇的,并且您将遇到与原始尝试相同的问题。

使用字符串比较的效率可能较低但较易理解的版本是:

awk -F, -v min=720000002774991000 -v max=720000002774991099 '
  "" $1 >= min && "" $1 <= max \
  && length($1) >= length(min) && length($1) <= length(max)' file

与以前的版本一样,打印的行同时通过字符串比较和长度比较。这种方法的缺点是minmax$1的长度计算得比必要的次数更多。


测试(以上三种方法)

$ cat file
720000002774991065
720000002774991082
720000002774990985
720000002774991131
720000002774990919
720000002774991110
720000002774990947
720000002774991070
720000002774991042
720000002774991044
$ awk -M '$1 >= 720000002774991000 && $1 <= 720000002774991099' file
720000002774991065
720000002774991082
720000002774991070
720000002774991042
720000002774991044
$ awk -F, -v min=720000002774991000 -v max=720000002774991099 '
  BEGIN { lmin = length(min); lmax = length(max) } # save length of min and max
  "" $1 < min || "" $1 > max { next }            # skip lines which fail string comparison
  { l1 = length($1) }                            # calculate length of field
  l1 >= lmin && l1 <= lmax                       # check that string length is correct
' file
720000002774991065
720000002774991082
720000002774991070
720000002774991042
720000002774991044
$ awk -F, -v min=720000002774991000 -v max=720000002774991099 '
  "" $1 >= min && "" $1 <= max \
  && length($1) >= length(min) && length($1) <= length(max)' file
720000002774991065
720000002774991082
720000002774991070
720000002774991042
720000002774991044