输入是一个日志文件。我目前感兴趣的过程,在过程的开始和结束时记录一行。开始始终具有某个固定模式以及对象ID。结尾也有一个固定的模式,以及相同的对象ID。
我希望输出每个对象ID包含一行,后跟第一行的时间戳,后跟第二行的时间戳。此输出将用于其他工具的进一步分析。输出应按起始行的时间戳排序;没有起始线(见障碍物)的物体应放在最后。
我想使用标准的Unix shell工具来解决这个问题。猜测,awk的东西应该可以解决问题。如果解决方案涉及Unix shell脚本,请使用sh作为shell。
障碍: 我无法保证进程是严格顺序的,因此在完全处理object1之前,object1的开始可以跟随object2的开始。此外,我不能保证日志文件始终与开头匹配,反之亦然。在这种情况下,ID应该具有缺失点的空值。
输入外观本质上是这样的:
2014-03-11 09:00:01.123 bla bla bla TAG_START ID:1234 bla bla bla
2014-03-11 09:00:11.123 bla bla bla TAG_END ID:1234 bla bla bla
2014-03-11 09:01:01.123 bla bla bla TAG_START ID:2353 bla bla bla
2014-03-11 09:02:01.123 bla bla bla TAG_END ID:2353 bla bla bla
2014-03-11 09:03:01.123 bla bla bla TAG_START ID:3456 bla bla bla
2014-03-11 09:04:01.123 bla bla bla TAG_END ID:4567 bla bla bla
输出:
1234;09:00:01.123;09:00:11.123
2353;09:01:01.123;09:02:01.123
3456;09:03:01.123;
4567;;09:04:01.123
提前致谢!
答案 0 :(得分:2)
您可以尝试使用GNU awk
(使用asorti
函数进行排序输出):
gawk '
function findID(line) {
for (i = 1; i<=NF; i++)
if ($i ~ /^ID/)
split($i, tmp, /:/)
return tmp[2]
}
/TAG_START/ {
id = findID($0)
lines[id] = $2 ";"
}
/TAG_END/ {
id = findID($0)
lines[id] = ((lines[id]) ? lines[id] $2 : ";" $2)
}
END {
n = asorti(lines, lines_s)
for (i = 1; i <= n; i++) {
print lines_s[i] ";" lines[lines_s[i]]
}
}' file
如果您没有GNU awk
,那么您可以将常规awk
的输出传输到sort
。
awk '
function findID(line) {
for (i = 1; i<=NF; i++)
if ($i ~ /^ID/)
split($i, tmp, /:/)
return tmp[2]
}
/TAG_START/ {
id = findID($0)
lines[id] = $2 ";"
}
/TAG_END/ {
id = findID($0)
lines[id] = ((lines[id]) ? lines[id] $2 : ";" $2)
}
END {
for (x in lines)
print x ";" lines[x]
}' file | sort -t";" -nk1,2
<强>输出:强>
1234;09:00:01.123;09:00:11.123
2353;09:01:01.123;09:02:01.123
3456;09:03:01.123;
4567;;09:04:01.123
<强>解释强>
/TAG_START/
的行,我们调用用户定义的函数,迭代空格分隔的每个字段。一旦我们遇到以ID
开头的字段,我们会将其与:
分隔符拆分并捕获其第二部分(即如果字段为TAG_START ID:1234
,我们会捕获1234
) lines
中的键,并为其分配第二个字段的值,即时间戳,并在其后填充;
。 /TAG_END/
的行执行类似的操作,唯一的区别是我们检查数组中是否存在key
。如果它存在,我们将第二个字段附加到它,因为它是结束时间戳。如果密钥不存在,那么我们只需添加;
并将值添加到数组中。这是为了满足您的要求另外,我不能保证日志文件始终与开头匹配,反之亦然。在这种情况下,ID应该有缺失点的空值。 GNU awk
,我们调用asorti
函数按值排序并迭代数组并打印行。对于常规awk
,我们会打印这些行并将其传递给sort
。 答案 1 :(得分:1)
输出的顺序与输入中显示的ID相同:
awk -v OFS=';' '
{
time = $2
type = (/TAG_START ID:/ ? "s" : "e")
sub(/.*TAG_(START|END) ID:/,"")
sub(/ .*$/,"")
id = $0
if (!seen[id]++) {
ids[++numIds] = id
}
times[id,type] = time
}
END {
for (idNr=1; idNr<=numIds; idNr++) {
id = ids[idNr]
print id, times[id,"s"], times[id,"e"]
}
}' file
1234;09:00:01.123;09:00:11.123
2353;09:01:01.123;09:02:01.123
3456;09:03:01.123;
4567;;09:04:01.123
if
语句只是按输入文件中显示的顺序跟踪唯一ID。第一次看到id时,数组seen[id]
的值为零,因为这是一个新的唯一ID,因此计数器numIds
预先递增,id
存储在{ {1}}数组位于由新值ids
索引的位置。由于numIds
在seen[id]
中后递增,因此下次看到if
时id
的值为seen[id]
,因此条件为1
现在是假的。
它只是习惯性的awk方法,用于如何按照它们在输入中出现的顺序保留唯一键列表(!seen[id]
),以便它们可以在END部分中按顺序引用使用ids
语句的随机顺序。
答案 2 :(得分:1)
在gnu awk中使用arrays of arrays
。
awk '{split($7,c,":");a[c[2]][$6]=$2;b[c[2]]}
END{for (i in b) {print i,a[i]["TAG_START"],a[i]["TAG_END"]}}' OFS=";" file
1234;09:00:01.123;09:00:11.123
2353;09:01:01.123;09:02:01.123
3456;09:03:01.123;
4567;;09:04:01.123
ID:1234
,拆分为数组c,并使用值c [2]作为数组a中的索引。arrays of arrays
,您可以直接打印两个值a[i]["TAG_START"]
和a[i]["TAG_END"]
awk '{for (i=1;i<=NF;i++) if ($i ~/TAG_(START|END)/) {status=$i;id=$(i+1)};split(id,c,":");a[c[2]][status]=$2;b[c[2]]}
END{for (i in b) {print i,a[i]["TAG_START"],a[i]["TAG_END"]}}' OFS=";" file