Первое, что нужно сделать 1002 *, это прекратить вызывать шесть субоболочек для запуска awk
для каждой строки ввода. Давайте сделаем несколько быстрых расчетов за пределами конверта.
Если предположить, что ваши строки ввода имеют длину около 292 символов (как в вашем примере), файл 2G будет состоять из чуть более 7,3 миллиона строк. Это означает, что вы запускаете и останавливаете колоссальные сорок четыре миллиона процессов.
И, хотя Linux превосходно обрабатывает fork
и exec
настолько эффективно, насколько это возможно, это не без затрат:
pax$ time for i in {1..44000000} ; do true ; done
real 1m0.946s
Кроме того, bash
на самом деле не был оптимизирован для такого рода обработки, его дизайн приводит к неоптимальному поведению для этого конкретного варианта использования. Подробнее об этом см. отличный ответ на одном из наших родственных сайтов.
Анализ двух методов обработки файлов (одна программа читает весь файл (каждая строка имеет только hello
) и bash
читает его по строке за раз) показана ниже. Две команды, используемые для получения времени были:
time ( cat somefile >/dev/null )
time ( while read -r x ; do echo $x >/dev/null ; done <somefile )
Для файлов разного размера (user+sys
время, усредненное за несколько прогонов), это довольно интересно:
# of lines cat-method while-method
---------- ---------- ------------
1,000 0.375s 0.031s
10,000 0.391s 0.234s
100,000 0.406s 1.994s
1,000,000 0.391s 19.844s
10,000,000 0.375s 205.583s
44,000,000 0.453s 889.402s
Из этого следует, что метод while
может сохранять свои собственные значения для небольших наборов данных, действительно плохо масштабируется.
Поскольку awk
сам имеет способы выполнять вычисления и форматировать вывод, обрабатывая файл одним одиночным awk
сценарием, а не * bash
/ multi- awk
-per-line Это приведет к тому, что затраты на создание всех этих процессов и линейные задержки исчезнут.
Этот скрипт будет хорошей первой попыткой, назовем его prog.awk
:
BEGIN {
FMT = "%.2f"
OFS = FS
}
{
isOneWay=$7
priceOutbound=$30
priceExc=$25
tax=$27
priceInc=$26
if (isOneWay == 0) {
if (priceOutbound > 0) {
$25 = sprintf(FMT, priceOutbound)
$26 = sprintf(FMT, priceOutbound + tax / 2)
} else {
$25 = sprintf(FMT, priceExc / 2)
$26 = sprintf(FMT, priceInc / 2)
}
}
print
}
Вы просто запускаете сценарий single awk
с:
awk -F'","' -f prog.awk data.txt
С данными испытаний, которые вы предоставили, вот до и после, с маркерами для полей с номерами 25 и 26:
<-25-> <-26->
"111","2018-08-24","01:21","ZZ","AAA","BBB","0","","","ZZ","ZZ111","ZZ110","2018-10-12","07:00","2018-10-12","08:05","2018-10-19","06:30","2018-10-19","09:35","ZZZZ","ZZZZ","A","B","146.00","222.26","76.26","EEE","abc","100.50","45.50","0","E","ESSENTIAL","ESSENTIAL","4","4","7","125","125"
"111","2018-08-24","01:21","ZZ","AAA","BBB","0","","","ZZ","ZZ111","ZZ110","2018-10-12","07:00","2018-10-12","08:05","2018-10-19","06:30","2018-10-19","09:35","ZZZZ","ZZZZ","A","B","100.50","138.63","76.26","EEE","abc","100.50","45.50","0","E","ESSENTIAL","ESSENTIAL","4","4","7","125","125"