AWK сопоставление значений в столбце и выполнение расчета
Я новичок в AWK, и я пытаюсь найти ответ на мою проблему. У меня есть плоский файл со следующими значениями:
403 | SanMateo | f | 2015-04-09 18:50:24.38
403 | SanMateo | t | 2015-04-09 18:45:24.36
403 | SanMateo | t | 2015-04-09 18:40:24.383
403 | SanMateo | f | 2015-04-09 18:35:24.357
403 | SanMateo | t | 2015-04-09 18:30:24.355
404 | RedwoodCity| f | 2015-04-09 18:35:50.308
404 | RedwoodCity| t | 2015-04-09 18:30:50.242
404 | RedwoodCity| f | 2015-04-09 18:25:50.245
404 | RedwoodCity| t | 2015-04-09 18:20:50.242
404 | RedwoodCity| f | 2015-04-09 18:15:50.242
Я хочу использовать awk для сравнения $ 1 текущей строки с $ 1 следующей строки и $3 ~/f/. если утверждение истинно, тогда вычтите 4 доллара следующей строки из 4 долларов текущей строки и запишите разницу в новом столбце текущей строки, а если ложь, то ничего не делайте. что я до сих пор это:
awk 'BEGIN {FS="|";} {if (NR $1 ~ NR++ $1 && $3 ~ /f/) subtract = NR $4 - NR++ $4; {print subtract}}' allHealthRecords_Sorted
и, очевидно, это не работает. Может кто-нибудь, пожалуйста, помогите?
3 ответа
Сохранить это как time_diff.awk
BEGIN {FS = "[[:blank:]]*\\|[[:blank:]]*"}
# convert "YYYY-mm-dd HH:MM:SS.fff" to a number
function to_time(timestamp, fraction) {
fraction = timestamp
sub(/\..*$/, "", timestamp)
gsub(/[-:]/, " ", timestamp)
sub(/.*\./, "0.", fraction)
return mktime(timestamp) + fraction
}
# gawk has no builtin abs() function
function abs(val) {
return( val < 0 ? -1*val : val)
}
# add the time diff if the condition is met
NR > 1 {
diff = 0
if ($1+0 == key && flag == "f")
diff = abs( to_time($4) - to_time(time) )
print line (diff > 0 ? " | " diff : "")
}
{
# remember the previous line's values
key = $1+0; flag = $3; time = $4; line = $0
}
END {print}
затем
$ gawk -f time_diff.awk file
403 | SanMateo| f | 2015-04-09 18:50:24.38 | 300.02
403 | SanMateo| t | 2015-04-09 18:45:24.36
403 | SanMateo| t | 2015-04-09 18:40:24.383
403 | SanMateo| f | 2015-04-09 18:35:24.357 | 300.002
403 | SanMateo| t | 2015-04-09 18:30:24.355
404 | RedwoodCity| f | 2015-04-09 18:35:50.308 | 300.066
404 | RedwoodCity| t | 2015-04-09 18:30:50.242
404 | RedwoodCity| f | 2015-04-09 18:25:50.245 | 300.003
404 | RedwoodCity| t | 2015-04-09 18:20:50.242
404 | RedwoodCity| f | 2015-04-09 18:15:50.242
Вы не показываете ожидаемый результат, поэтому мы не можем его протестировать, а 4 доллара - это дата, так что сходите с тем, что вы подразумеваете под "вычитанием", но это в основном правильный подход:
$ cat tst.awk
BEGIN{ FS="[[:space:]]*[|][[:space:]]*"; OFS=" | " }
split(prev,p) { print prev ( ($1==p[1])&&(p[3]=="f") ? OFS p[4] - $4 : "") }
{ prev = $0 }
END { print prev ( ($1==p[1])&&(p[3]=="f") ? OFS p[4] - $4 : "") }
$ awk -f tst.awk file
403 | SanMateo | f | 2015-04-09 18:50:24.38 | 0
403 | SanMateo | t | 2015-04-09 18:45:24.36
403 | SanMateo | t | 2015-04-09 18:40:24.383
403 | SanMateo | f | 2015-04-09 18:35:24.357 | 0
403 | SanMateo | t | 2015-04-09 18:30:24.355
404 | RedwoodCity| f | 2015-04-09 18:35:50.308 | 0
404 | RedwoodCity| t | 2015-04-09 18:30:50.242
404 | RedwoodCity| f | 2015-04-09 18:25:50.245 | 0
404 | RedwoodCity| t | 2015-04-09 18:20:50.242
404 | RedwoodCity| f | 2015-04-09 18:15:50.242
т. е. у вас есть буфер в 1 строку, поэтому вы всегда работаете и выводите предыдущую прочитанную строку.
В действии BEGIN прочитайте первую строку с getline
и сохраните значения $1 и $4.
Затем в каждой строке сравнивайте $1 с сохраненным значением из предыдущей строки. Если они одинаковы, и $3 ~ /f/
, сделать желаемый процесс. Затем сохраните значения $1 и $ 4 для следующей строки.
Этого должно быть достаточно, чтобы вы начали. Если у вас возникли проблемы с написанием кода, вернитесь и задайте больше вопросов.