我想格式化我的服务器日志,以便在执行“tail -f”时易于阅读。
我的日志看起来像:
{"item1":"ab","item2":"cdef","item3":"ghi"}
{"item1":"abc","item2":"defgh","item3":"i"}
我想获得:
var1=ab__ | var2=cdef_ | var3=ghi
var1=abc_ | var2=defgh | var3=i__
其中 '_' 是一个空格。
现在我使用:
sed -E 's/.*item1":"(.*)","item2":"(.*)","item3":"(.*)".*/var1=\1 | var2=\2 | var3=\3/'
然后我得到:
var1=ab | var2=cdef | var3=ghi
var1=abc | var2=defgh | var3=i
可以设置捕获组\1\2\3 的长度吗?用空格填充它们还是截断它们?
我想固定每个字段的长度(填充或截断)并实时流式传输我的日志。
最佳答案
评论已经在推荐jq
。
这是一种方法:
$ jq -r '[(.item1, .item2, .item3)] | @tsv' log.json
ab cdef ghi
abc defgh i
请注意,@tsv
过滤器是在 jq
1.5 版中引入的,因此如果您使用的是 1.4,也许是时候升级了。 :)
如果你想要垂直条,你可以在数组中添加它们:
$ jq -r '[(.item1, "|", .item2, "|", .item3)] | @tsv' log.json
ab | cdef | ghi
abc | defgh | i
请注意,@tsv
在每个字段之间添加了一个制表符,因此这可能不是您想要的。但是,它可以很容易地被 bash 解析:
$ while IFS=$'\t' read one two three; do \
printf 'var1=%-4s | var2=%-5s | var3=%-4s\n' "$one" "$two" "$three"; \
done < <(jq -r '[(.item1, .item2, .item3)] | @tsv' log.json)
var1=ab | var2=cdef | var3=ghi
var1=abc | var2=defgh | var3=i
或者,如果特定格式不重要,而您只是想让事情排成一行,也许是这样:
$ jq -r '[(.item1, "|", .item2, "|", .item3)] | @tsv' log.json | column -t
ab | cdef | ghi
abc | defgh | i
当然,这不处理tail -f
,它只是涉及格式化。如果您希望能够处理一个流,您可能需要在循环中执行此操作。例如:
tail -F "$logfile" | while read -r line; do
jq -r '[(.item1, .item2, .item3)] | @tsv' <<< "$line" |
while IFS=$'\t' read one two three; do
printf 'var1=%-4s | var2=%-5s | var3=%-4s\n' "$one" "$two" "$three"
done
done
请注意,此处选择的格式化选项是 printf
,因为所有其他解决方案都需要了解输入数据的最大长度。对于 printf
,我们假设您已经知道最大长度,并已在您的格式字符串中考虑到它。
关于linux - 设置捕获组的长度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48100013/