来自终端的sed regex字符串替换

时间:2015-03-31 11:10:48

标签: regex linux bash sed

我有一个标准格式的日志文件,例如:

31 Mar - Lorem Ipsom1
31 Mar - Lorem Ipsom2
31 Mar - Lorem Ipsom3

我要实现的替换是31 * 31到31,所以我最终会得到一个只有最后一行的日志,在这个例子中它看起来像:

31 Mar - Lorem Ipsom3

我希望在没有perl的自定义linux机器上执行它。 我试着像这样使用sed:

sed -i -- 's/31*31/31/g' /var/log/prog/logFile

但它没有做任何事...... 任何涉及忍者猛击命令的替代方案也受到欢迎。

3 个答案:

答案 0 :(得分:4)

仅保留与模式匹配的最后连续行的方法是

sed -n '/^31/ { :a $!{ h; n; //ba; x; G } }; p' filename

其工作原理如下:

/^31/ {    # if a line begins with 31
  :a       # jump label for looping

  $!{      # if the end of input has not been reached (otherwise the current
           # line is the last line of the block by virtue of being the last
           # line)

    h      # hold the current line
    n      # fetch the next line. (note that this doesn't print the line
           # because of -n)

    //ba   # if that line also begins with 31, go to :a. // attempts the
           # most recently attempted regex again, which was ^31

    x      # swap hold buffer, pattern space
    G      # append hold buffer to pattern space. The PS now contains
           # the last line of the block followed by the first line that 
           # comes after it
  }
}
p          # in the end, print the result

这避免了多行正则表达式的一些问题,例如在行的中间开始或结束的匹配。它也不会丢弃两个匹配行块之间的行,并保留每个块的最后一行。

答案 1 :(得分:2)

*不是通配符,因为它在shell中,它是一个量词。您需要量化.(任何字符)。因此正则表达式是:

sed ':a;N;$!ba;s/31.*31/31/g'

(我删除了-i标记,因此您可以先安全地测试文件。

:a;N;$!ba;部分可以处理新行

但请注意:

  • 正则表达式将匹配任何31所以:

    31 Mar - Lorem Ipsom1
    31 Mar - Lorem 31 Ipsom2
    

    将导致

    31 Ipsom2
    
  • 如果日志显示为:

    ,它将匹配贪婪
    31 Mar - Lorem Ipsom1
    30 Mar - Lorem Ipsom2
    31 Mar - Lorem Ipsom3
    

删除第二行。

您可以通过写下来解决第一个问题:

sed ':a;N;$!ba;s/(^|\n)31.*\n31/31/g'

强制第二个31位于该行处的的正则​​表达式。

答案 2 :(得分:0)

我认为你可能正在寻找“尾巴”来获取文件的最后一行 e.g。

tail -1 /path/file

或者如果您想要每天的最后一个条目,那么“排序”可能是您的解决方案

sort -ur -k 1,2 /path/file | sort
  • -u标志仅指定将返回关键字段的单个匹配
  • -k 1,2指定关键字段是前两个字段 - 在这种情况下它们是月份和日期 - 默认情况下字段用空格分隔。
  • -r标志会反转这些行,以便返回每个日期的最后一个匹配项。第二次排序以恢复原始订单。

如果您的日志文件有超过一个月的数据,并且您希望保留订单(例如,如果您在同一文件中包含3月31日和4月1日),您可以尝试:

cat -n tmp2 | sort -nr | sort -u -k 2,3 | sort -n | cut -f 2-
  • cat -n在排序之前将行号添加到日志文件中。
  • sort和以前一样但是使用字段2和3,因为字段1现在是原始行号
  • sort按原始行号恢复原始订单。
  • 使用cut删除行号并恢复原始行内容。

e.g。

 $ cat tmp2
 30 Mar - Lorem Ipsom2
 30 Mar - Lorem Ipsom1
 31 Mar - Lorem Ipsom1
 31 Mar - Lorem Ipsom2
 31 Mar - Lorem Ipsom3
 1 Apr - Lorem Ipsom1
 1 Apr - Lorem Ipsom2

 $ cat -n tmp2 | sort -r | sort -u -k 2,3 | sort | cut -f 2-
 30 Mar - Lorem Ipsom1
 31 Mar - Lorem Ipsom3
 1 Apr - Lorem Ipsom2