Извлечение определенного диапазона числовых значений из огромного списка чисел с помощью AWK - PullRequest
0 голосов
/ 29 августа 2018

я хочу вывести определенный диапазон огромных числовых значений, от 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 голосов
/ 29 августа 2018

Похоже, ваши числа слишком длинные, чтобы их можно было правильно представить в виде целых чисел.

У вас есть несколько возможных решений. В GNU awk вы можете использовать -M, чтобы включить поддержку произвольных целочисленных значений точности :

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

Как и в предыдущей версии, печатаются строки, которые передают как сравнение строк, так и сравнение длин. Недостатком этого подхода является то, что длины min, max и $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
...