我有现有的日志文件,其中包括以下类型的行:
2018-05-14T10:10:22.769029+03:00 timom usbmonitor: [INFORMATION 6] [FILE: UsbChecker.cpp:51][FUNC: vendorCheck][MSG: USB vendors changed: "0403 14e1 05e3 05e3 03f0 0403 0bda 1d6b 1d6b 1d6b 1d6b 1d6b 1d6b 1d6b" ]
从这些文件我想要grep上面的行,以便从开头获取时间戳,并在引号内输入文本,以便我有一个漂亮而紧凑的输出:
2018-05-14T10:10:22.769029+03:00 0403 14e1 05e3 05e3 03f0 0403 0bda 1d6b 1d6b 1d6b 1d6b 1d6b 1d6b 1d6b
有没有办法用单线程做到这一点?
我正在寻找一种有效获得所需输出的方法,而无需在grepped线上循环。我有成千上万的日志文件,每个日志文件可能有数百个匹配,所以grep / sed /需要高效。
到目前为止,我已经这样做了:
#!/bin/bash
INPUTDIR=
OUTPUTDIR=
while getopts ":h:d:o:" OPTION; do
case $OPTION in
h)
usage
exit 1
;;
d)
INPUTDIR=$OPTARG
;;
o)
OUTPUTDIR=$OPTARG
;;
?)
usage
exit 1
;;
esac
done
if [ -z $INPUTDIR ] || [ -z $OUTPUTDIR ]; then
echo "BAD ARGUMENTS: both directories aren't given" >&2
usage
exit 1
fi
OUTPUTFILE="$(date +%Y%m%d%H%M%S)-usb-analysis-summary"
for i in $( ls $INPUTDIR ); do
# Interesting files are of format <number>_<number>
if [ $(echo "$i" | grep -Ev "^[0-9]+_[0-9]+$") ] ; then
echo "Skipping $i"
continue
fi
grep vendorCheck $INPUTDIR/$i | while read -r l ; do
# We do know timestamp is 32 characters long. GEFN
echo "$l" | sed -r "s|^(.{32}).*changed: \"(.*)\".*|\1 \2|" >>$OUTPUTFILE
done
done
但这不是最佳的,因为现在我循环文件然后从每个文件循环grep匹配。
我试过
grep "vendorCheck" $INPUTDIR/$i | sed -r "s|^(.{32}).*changed: \"(.*)\".*|\1 \2|"
但是这会删除换行符 然后,如果我将多个模式放在一个grep中,我也会遇到格式问题;我需要将引号内的时间戳和文本放到一行,然后将下一个类似的匹配放到下一行。
答案 0 :(得分:1)
Sed可以随时进行行选择匹配和编辑。
你也可以使用$(...)
生成sed的输入文件列表,所以你真的可以把它全部放到一行,我想,ls
不是理想的,你说你在下面的评论中需要文件名,所以......
而不是
sed -r -n '/vendorCheck/{s/(.{32}).*changed: \"(.*)\"/\1 \2/; p;}' $( ls -1 $INPUTDIR | egrep '^[0-9]+_[0-9]+$' ) >> $OUTPUTFILE
你可以嵌入一些空格,使其变得不那么难看而不用改变&#34; one-liner&#34;功能,循环可以取代ls
:
for f in $INPUTDIR/[0-9]*_[0-9]* # limit input, not a definitive check
do echo "$f" | egrep '^[0-9]+_[0-9]+$' || continue # CONFIRM filename match
[[ -f $f ]] || continue # and assert file, not dir
sed -r -n "/vendorCheck/{
s/(.{32}).*changed: \"(.*)\"/\1 \2/;
s/^/$f: /;
p;
}" "$f" # the "s/^/$f: /;" is a placeholder of your need for the name
done >> $OUTPUTFILE
注意:删除了我的测试数据,因此这项返工并未经过仔细审核。如果有人看到拼写错误,请告诉我。