我正在尝试重新格式化日志文件,以便日期和时间出现在行首。我的日志如下所示:
blah, blah, blah, Friday, Mar 13,2015 16:59:42
yadi, yadi, yada, Friday, Mar 13,2015 16:51:11
我希望它们看起来像这样:
Friday, Mar 13,2015 16:59:42 blah, blah, blah
Friday, Mar 13,2015 16:51:11 yadi, yadi, yada
我甚至已经找到了正确的 grep 模式grep -o -i -e '[a-zA-Z]*, [a-z][a-z][a-z] [0-9]*,[0-9][0-9][0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9]' ~/log.txt
。
我怎样才能将这些模式结果移到信息字符串的左侧?谢谢您的帮助。
答案1
尝试sed
使用以下正则表达式:
$ sed -i.bak 's_\(.*\),[[:blank:]]\([[:alpha:]]\+,[[:blank:]][[:alpha:]]\+[[:blank:]][[:digit:]]\+,[^,]\+$\)_\2 \1_' file.txt
Friday, Mar 13,2015 16:59:42 blah, blah, blah
Friday, Mar 13,2015 16:51:11 yadi, yadi, yada
这里我们使用了sed
组替换方法来得到所需的输出。
\(.*\)
将匹配至,blah, blah, blah
因为我们必须在其后,[[:blank:]]
进行匹配。,
\([[:alpha:]]\+,[[:blank:]][[:alpha:]]\+[[:blank:]][[:digit:]]\+,[^,]\+$\)
将匹配该行的剩余部分(我们想要放在开头的部分)。
然后我们必须\2 \1
先放第二组,然后再放一个空格,最后放第一组。
原始文件将被备份为file.txt.bak
,如果您不想这样,请使用 而-i
不是-i.bak
。
**虽然您会得到所需的输出,但在这种情况下使用 Regex/sed 并不是最佳解决方案。
编辑:如果有类似这样的行[Internet disconnected] Friday, Mar 13,2015 15:48:34
,请尝试以下操作:
$ sed -i.bak 's_\(.*[^,]\),*[[:blank:]]\([[:alpha:]]\+,[[:blank:]][[:alpha:]]\+[[:blank:]][[:digit:]]\+,[^,]\+$\)_\2 \1_' file.txt
Friday, Mar 13,2015 15:48:34 [Internet disconnected]
Friday, Mar 13,2015 16:59:42 blah, blah, blah
Friday, Mar 13,2015 16:51:11 yadi, yadi, yada
在之前的正则表达式中,我们在\(.*\),[[:blank:]]
第一个匹配组后面有一个逗号和一个空格,现在为了在输出中包含新行,我们创建了第一个匹配组\(.*[^,]\)
以确保它不以逗号结尾,然后我们匹配了,*
一个或多个逗号。因此,新sed
命令将适用于所有提到的情况。
答案2
使用 awk 语法更简单
awk -F, '{print $4","$5","$6","$1","$2","$3}' file.txt
答案3
正则表达式的黄金法则是“少即是多”。您应该始终尝试编写与您的数据匹配的最简单的正则表达式。这不仅使其更易于阅读和理解,而且更加健壮,不会因格式的细微变化而中断。因此,对于您来说,您可以简单地执行以下操作:
$ sed -r 's/(.*), ([^,]+,[^,]+,[^,]*$)/\2\1/' file
Friday, Mar 13,2015 16:59:42blah, blah, blah,
Friday, Mar 13,2015 16:51:11yadi, yadi, yada,
这样就匹配了从行首到逗号和空格 ( (.*),
) 的所有内容,并且由于模式被括号包围,因此将其保存为\1
。现在,由于第二个捕获组(括号中的第二个模式)一直到行尾(这就是 的意思$
),我们知道我们匹配的是第一个中的正确部分。
第二个查找一个或多个非逗号字符 ( [^,]+
)、一个逗号、另一组非逗号、另一个逗号,然后查找尽可能多的非逗号字符,直到行尾。这样,我们就可以正确地将最后的字段识别为日期。 是s///
替换运算符,在这里只是切换第一个和第二个捕获模式的顺序。
您也可以在 中执行相同的操作awk
。据推测,日期之前的文本是可变的,因此我们不能假设每行的字段数量相同。因此,我们需要从行尾向后计算字段:
$ awk -F, '{
printf "%s,%s,%s, ", $(NF-2),$(NF-1),$NF;
for(i=1;i<NF-3;i++){printf "%s,", $i} print $(NF-3)
}' file
Friday, Mar 13,2015 16:59:42, blah, blah, blah
Friday, Mar 13,2015 16:51:11, yadi, yadi, yada
或者用 Perl 来写:
$ perl -lpe 's/(.*), ([^,]+,[^,]+,[^,]*$)/\2, \1/' file
Friday, Mar 13,2015 16:59:42, blah, blah, blah
Friday, Mar 13,2015 16:51:11, yadi, yadi, yada
$ perl -F, -lane 'print join ",",@F[$#F-2,$#F-1,$#F,0..$#F-3]' file
Friday, Mar 13,2015 16:59:42,blah, blah, blah
Friday, Mar 13,2015 16:51:11,yadi, yadi, yada