将模式移动到行首

将模式移动到行首

我正在尝试重新格式化日志文件,以便日期和时间出现在行首。我的日志如下所示:

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

相关内容