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 行的缓冲区,所以你总是在操作并输出你阅读的上一行。
我是 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 行的缓冲区,所以你总是在操作并输出你阅读的上一行。