Bash-使用group by的时间字段总和
输入: 所需输出:Bash-使用group by的时间字段总和,bash,awk,Bash,Awk,输入: 所需输出: 70|00:00:01 70|00:00:03 180|00:00:01 180|00:00:10 180|00:00:05 我有一个工作代码,但它只返回总时间 70|00:00:04 180|00:00:16 如何调整代码以按第1个字段进行分组?解决方案第1个:考虑到您的输入文件是按第一个字段排序的,下面可能会对您有所帮助 awk -F\| '{ split($2, tm, ":"); secs += tm[3];
70|00:00:01
70|00:00:03
180|00:00:01
180|00:00:10
180|00:00:05
我有一个工作代码,但它只返回总时间
70|00:00:04
180|00:00:16
如何调整代码以按第1个字段进行分组?解决方案第1个:考虑到您的输入文件是按第一个字段排序的,下面可能会对您有所帮助
awk -F\| '{
split($2, tm, ":");
secs += tm[3];
mins += tm[2] + int(secs / 60);
hrs += tm[1] + int(mins / 60);
secs %= 60; mins %= 60;
}
END {
printf "%d:%d:%d\n", hrs, mins, secs;
}' input
解决方案2:如果您的输入文件未按第一个字段排序,您可以通过执行sort-t'|'-k1
对其进行排序,并将输出传递给上述代码
awk -F\| '
prev!=$1 && FNR>1{
printf "%d|%d:%d:%d\n", prev, hrs, mins, secs
prev=hrs=mins=secs=""
}
{
split($2, tm, ":");
secs += tm[3];
mins += tm[2] + int(secs / 60);
hrs += tm[1] + int(mins / 60);
secs %= 60; mins %= 60;
prev=$1
}
END{
if(prev){
printf "%d|%d:%d:%d\n", prev, hrs, mins, secs
}
}' Input_file
解决方案一:考虑到您的输入文件是按以下第一个字段排序的,可能会对您有所帮助
awk -F\| '{
split($2, tm, ":");
secs += tm[3];
mins += tm[2] + int(secs / 60);
hrs += tm[1] + int(mins / 60);
secs %= 60; mins %= 60;
}
END {
printf "%d:%d:%d\n", hrs, mins, secs;
}' input
解决方案2:如果您的输入文件未按第一个字段排序,您可以通过执行sort-t'|'-k1
对其进行排序,并将输出传递给上述代码
awk -F\| '
prev!=$1 && FNR>1{
printf "%d|%d:%d:%d\n", prev, hrs, mins, secs
prev=hrs=mins=secs=""
}
{
split($2, tm, ":");
secs += tm[3];
mins += tm[2] + int(secs / 60);
hrs += tm[1] + int(mins / 60);
secs %= 60; mins %= 60;
prev=$1
}
END{
if(prev){
printf "%d|%d:%d:%d\n", prev, hrs, mins, secs
}
}' Input_file
您可以使用多维数组,只需在末尾进行迭代和打印:
sort -t'|' -nk1 Input_file |
awk -F\| '
prev!=$1 && FNR>1{
printf "%d|%d:%d:%d\n", prev, hrs, mins, secs
prev=hrs=mins=secs=""
}
{
split($2, tm, ":");
secs += tm[3];
mins += tm[2] + int(secs / 60);
hrs += tm[1] + int(mins / 60);
secs %= 60; mins %= 60;
prev=$1
}
END{
if(prev){
printf "%d|%d:%d:%d\n", prev, hrs, mins, secs
}
}'
我在这里编辑了您的
printf
,在您的时间输出中包含前导0以匹配输入。您可以使用多维数组,只需在最后迭代并打印:
sort -t'|' -nk1 Input_file |
awk -F\| '
prev!=$1 && FNR>1{
printf "%d|%d:%d:%d\n", prev, hrs, mins, secs
prev=hrs=mins=secs=""
}
{
split($2, tm, ":");
secs += tm[3];
mins += tm[2] + int(secs / 60);
hrs += tm[1] + int(mins / 60);
secs %= 60; mins %= 60;
prev=$1
}
END{
if(prev){
printf "%d|%d:%d:%d\n", prev, hrs, mins, secs
}
}'
awk -F\| '{
split($2, tm, ":");
out[$1]["secs"] += tm[3];
out[$1]["mins"] += tm[2] + int(out[$1]["secs"] / 60);
out[$1]["hrs"] += tm[1] + int(out[$1]["mins"] / 60);
out[$1]["secs"] %= 60; out[$1]["mins"] %= 60;
}
END {
for (time in out){
printf "%s|%02d:%02d:%02d\n", time, out[time]["hrs"], out[time]["mins"], out[time]["secs"];
}
}' input
我在这里编辑了您的printf
,在您的时间输出中包含前导0以匹配输入
awk -F\| '{
split($2, tm, ":");
out[$1]["secs"] += tm[3];
out[$1]["mins"] += tm[2] + int(out[$1]["secs"] / 60);
out[$1]["hrs"] += tm[1] + int(out[$1]["mins"] / 60);
out[$1]["secs"] %= 60; out[$1]["mins"] %= 60;
}
END {
for (time in out){
printf "%s|%02d:%02d:%02d\n", time, out[time]["hrs"], out[time]["mins"], out[time]["secs"];
}
}' input
注意:
mktime
无法以UTC格式返回结果,因此在我的例子中,通过添加3小时(3600秒*3=10800
)即可将mktime
时间戳结果转换为UTC。你应该选择你的时区值
输入(测试复杂)
输出
70|00:00:01
70|04:00:03
70|10:00:03
70|02:00:52
70|03:00:03
70|04:00:05
180|00:00:01
180|00:00:10
180|00:00:05
注意:
mktime
无法以UTC格式返回结果,因此在我的例子中,通过添加3小时(3600秒*3=10800
)即可将mktime
时间戳结果转换为UTC。你应该选择你的时区值
输入(测试复杂)
输出
70|00:00:01
70|04:00:03
70|10:00:03
70|02:00:52
70|03:00:03
70|04:00:05
180|00:00:01
180|00:00:10
180|00:00:05
你可以通过使用
-F[:|]
:)来保存自己的拆分
)哦,是的,完全是@PesaThe,这是一个很好的添加。我认为-F[:\ \124;]
虽然要避开
regex元字符。嗯,我认为在[…]
中没有必要这样做。我得到了一个awk:fatal:不匹配[,[^,[:,[,或[=:/[:/
没有它。也许这取决于awk版本或其他什么。你应该提到的是,考虑到真正的多维数组语法,它只能在GNU awk中工作。你可以通过使用-F[:]
:)来保存自己的拆分,哦,是的@PesaThe,这是一个很好的补充。我认为-F[:\]
虽然要避开|
regex元字符.Hmm,但我认为在[…]中没有必要这样做。
我得到了一个awk:fatal:Unmatched[,[^,[:,[,或[=:/[:/
没有它。可能这取决于awk版本或其他什么。你应该提到的是,考虑到真正的多维数组语法,这只在GNU awk中有效。不客气。请参阅了解下一步要做什么。不客气。请参阅了解下一步要做什么。