AWK 匹配列中的值并执行计算

AWK matching values in a column and performing calculation

我是 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  ~ NR++  &&  ~ /f/) subtract = NR  - NR++ ; {print subtract}}' allHealthRecords_Sorted

显然那是行不通的。有人可以帮忙吗?

在 BEGIN 动作中,读取第一行 getline 并保存 $1 和 $4 的值。

在之后的每一行中,将 $1 与上一行中保存的值进行比较。如果它们相同,并且 ~ /f/,则执行所需的过程。然后为下一行保存 $1 和 $4 的值。

这应该足以让您入门。代码写的有问题可以回来多提问

另存为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 (+0 == key && flag == "f") 
        diff = abs( to_time() - to_time(time) )
    print line (diff > 0 ? " | " diff : "")
} 

{
    # remember the previous line's values
    key = +0; flag = ; time = ; line = [=10=]
}

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 是一个日期,所以我知道您所说的 "subtract" 是什么意思,但这基本上是正确的方法:

$ cat tst.awk         
BEGIN{ FS="[[:space:]]*[|][[:space:]]*"; OFS=" | " }
split(prev,p) { print prev ( (==p[1])&&(p[3]=="f") ? OFS p[4] -  : "") }
{ prev = [=10=] }
END { print prev ( (==p[1])&&(p[3]=="f") ? OFS p[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 行的缓冲区,所以你总是在操作并输出你阅读的上一行。