合并与正则表达式不匹配的行

Merge lines which don't match a regex

我有一个包含网络日志的文件;简化版如下:

en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;
Unix
Linux
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;
START
Solaris
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;
Aix
SCO

我尝试了几个 Regex 组合来识别接受语言,它是每一行的开头,使用以下 awk/sed:

/^[a-z]{2}(-[A-Z]{2})?/
/\*|[A-Z]{1,8}(-[A-Z0-9]{1,8})*/i  
/([^-;]*)(?:-([^;]*))?(?:;q=([0-9]\.[0-9]))?/

到目前为止,我还没有设法让 awk/sed 给我以下结果:

en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;    Unix    Linux
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;    STAR    Solaris
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;    Aix    SCO

感谢任何帮助。该文件包含大约 100 万条以上的记录,所以我很高兴走一条不使用 sed/awk 并提高性能的路线。

只是为了好玩,这是一个 sed 解决方案:

sed -ne 1bgo \
   -e '/^[a-z][a-z]-[A-Z][A-Z]/ { x;p;s/.*//;x; };:go' \
   -e 'H;x;s/^\n//;s/\n/  /;x;${ x;p; }' < input

它是这样工作的:

  • 读取每一行但不是立即打印它,而是通过将其附加到保留 space (H) 来保存它,除了删除将它与已经存在的任何东西(x;s/^\n//;s/\n/ /;x)。 (如果您想在输出中使用制表符,请将它们放在这里我放了几个 space 的地方。)

  • 如果您遇到与您的 Accept-Language 模式相匹配的行,请在向其附加任何内容之前刷新保留 space。打印并清除它 (x;p;s/.*//;x)。然后照常进行附加和诸如此类的事情。

  • 第一行和最后一行的处理方式与其他行不同:在阅读完第一行后,永远不要刷新保留 space(1bgo 跳过第一行,向下到位置标记为 :go),并始终在阅读最后一行 (${ x;p; })

  • 后刷新保留 space

根据观察,我们可以区分 = 上的两种类型的行,您可以使用这个 awk 脚本:

file.awk

[=10=] ~ /=/ { printf("%s%s", v,[=10=])
           v="\n"
           next
         } 
         { printf("\t%s", [=10=]) } 
END      { printf("\n") }

你这样使用它:awk -f file.awk yourfile

  • v 第一行是空的,后面包含换行符
  • 对于带有 = 的行,我们打印 [=15=] 前面有 v
  • 对于其他行(注意第一个操作中的 next),我们打印 [=15=] 没有换行,但使用 \t 作为分隔符
$ awk '/[a-z]{2}-[A-Z]{2}/ { print b; b=[=10=]; next }  # @xx-XX empty buffer, refill
                           { b=b OFS [=10=] }           # otherwise append to buffer
                       END { print b }' file        # dump the buffer in the end

en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd;
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd; Unix Linux
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd; START Solaris
en-GB,en-US;q=0.8,en    jsdjpksdkskd;lkskd; Aix SCO

您将得到一个空行来开始输出。此外,如果需要,在输出中使用制表符分隔符:awk -v OFS="\t" ....