合并与正则表达式不匹配的行
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" ...
.
我有一个包含网络日志的文件;简化版如下:
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" ...
.