【问题标题】:Join line to previous line if it doesn't start with a timestamp in UNIX shell如果在 UNIX shell 中不以时间戳开头,则将行加入上一行
【发布时间】:2020-12-02 15:07:51
【问题描述】:

我有一个工具可以输出带有时间戳前缀的日志,但是日志条目可能包含换行符。我想将任何没有时间戳的行与前一行合并。

例子:

[ 2020/08/12 11:40] Success with "one line [42]"
[ 2020/08/12 11:40] Success with "two
lines [13]"
[ 2020/08/12 11:40] Success with "two lines with a twist
[19] to confuse you"
[ 2020/08/12 11:41] Failure with "one line again"

使用 awk 我可以做这样的事情来合并不以 [ 大括号开头的行:

awk -v RS="[" 'NR>1{$1=$1; print RS, $0}'

但是,您可以在上面的“twist”行中看到失败的地方。 “twist”行以 [ 开头,它不是时间戳的一部分。

有没有办法为那个时间戳前缀使用正则表达式?或者有没有更好的命令行工具来完成这个?

【问题讨论】:

    标签: regex awk text-processing


    【解决方案1】:

    您能否尝试使用现场展示的样本进行书面和测试https://ideone.com/PXVCh2

    awk '
    {
      printf("%s%s",$0~/^\[ [0-9]{4}\/[0-9]{2}\/[0-9]{2}/\
              ?(FNR!=1?ORS:""):OFS,$0)
    }
    END{ print "" }
    ' Input_file
    

    根据 Ed sir 的评论,添加了一个 print new line 语句以在 Input_file 的最后添加一个新行,以防万一它已经这样做了,那么可以省略该部分。

    注意:我是在手机上写的;抱歉,我无法判断它在大屏幕上的显示效果如何,所以我在这里将一条打印线分成两行

    【讨论】:

      【解决方案2】:

      在我看来,你真正的问题实际上是你引用的字符串可以包含换行符,所以这个寻找引用字符串的 GNU awk 解决方案(用于多字符 RS)可能比在开头查找时间戳更健壮行:

      $ awk -v RS='"[^"]*"' '{gsub("\n"," ",RT); ORS=RT} 1' file
      [ 2020/08/12 11:40] Success with "one line [42]"
      [ 2020/08/12 11:40] Success with "two lines [13]"
      [ 2020/08/12 11:40] Success with "two lines with a twist [19] to confuse you"
      [ 2020/08/12 11:41] Failure with "one line again"
      

      如果您引用的字符串可以包含可能出现在行首的时间戳,那么这将比检查以时间戳开头的行更好,例如(注意"four lines with a twist... 块中的时间戳):

      $ cat file
      [ 2020/08/12 11:40] Success with "one line [42]"
      [ 2020/08/12 11:40] Success with "two
      lines [13]"
      [ 2020/08/12 11:40] Success with "four lines with a twist
      [ 2020/08/12 11:40] to confuse you
      repeatedly and
      in ""horrible"" ways"
      [ 2020/08/12 11:41] Failure with "one line again"
      

      .

      $ awk -v RS='"[^"]*"' '{ORS=gensub("\n"," ","g",RT)} 1' file
      [ 2020/08/12 11:40] Success with "one line [42]"
      [ 2020/08/12 11:40] Success with "two lines [13]"
      [ 2020/08/12 11:40] Success with "four lines with a twist [ 2020/08/12 11:40] to confuse you repeatedly and in ""horrible"" ways"
      [ 2020/08/12 11:41] Failure with "one line again"
      

      【讨论】:

        【解决方案3】:

        假设日志包含您的示例文件:

        $ cat log
        
        [ 2020/08/12 11:40] Success with "one line [42]"
        [ 2020/08/12 11:40] Success with "two
        lines [13]"
        [ 2020/08/12 11:40] Success with "two lines with a twist
        [19] to confuse you"
        [ 2020/08/12 11:41] Failure with "one line again"
        

        以下代码检查双引号 (") 的数量,如果只找到一个双引号,则连接两行:

        $ gawk 'gsub("\"", "\"") == 1 {x=$0; getline; print x " " $0;} gsub("\"", "\"") == 2 {print}' log
        
        [ 2020/08/12 11:40] Success with "one line [42]"
        [ 2020/08/12 11:40] Success with "two lines [13]"
        [ 2020/08/12 11:40] Success with "two lines with a twist [19] to confuse you"
        [ 2020/08/12 11:41] Failure with "one line again"
        

        【讨论】:

        • 这不是使用 getline 的安全方法,也没有必要(请参阅awk.freeshell.org/AllAboutGetline),如果引用的字段内有超过 2 行,则会失败。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-10-23
        • 1970-01-01
        • 1970-01-01
        • 2012-06-25
        • 2012-11-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多