在awk中匹配时间戳失败求助:正则在grep可用但awk不可用
这个问题我太熟悉了——你遇到的核心矛盾是grep -P使用的是Perl兼容正则表达式(PCRE),而awk默认采用的是POSIX基本正则表达式(BRE),两者的语法规则有不少差异,尤其是\s这类Perl风格的元字符,awk的BRE完全不认识。
问题拆解
你的grep命令里的\s是PCRE里匹配任意空白字符的简写,但在awk的正则体系里,需要用POSIX字符类[[:space:]](或者直接写空格,如果你确定只有空格的话);另外,PCRE里的{1,2}这类量词可以直接用,但在BRE里必须转义成\{1,2\},这也是导致匹配失效的原因之一。
解决方案
这里给你两种可行的改写方式:
方案1:改用awk的扩展正则表达式(ERE)
大部分现代awk版本(比如gawk、mawk)都支持扩展正则,只需要加上-E选项,这样你可以不用转义量词,同时把\s替换成空格(你的示例里日期和时间之间就是空格,更精准):
awk -E '/^(([0-9]{1,2}\/){2}[0-9]{2} [0-9]{1,2}:){2}[0-9]{2}/' file.txt
方案2:简化正则表达式(更易读)
其实可以去掉多余的嵌套括号,直接匹配开头的日期时间格式,写法更简洁:
awk -E '/^[0-9]{1,2}\/[0-9]{1,2}\/[0-9]{2} [0-9]{1,2}:[0-9]{1,2}:[0-9]{2}/' file.txt
这个正则会匹配以MM/DD/YY HH:MM:SS开头的行,完美符合你的需求——前三条示例行都会被匹配,第四条没有时间部分的行则会被排除。
方案3:兼容老式awk(BRE写法)
如果你用的是非常老的awk版本,不支持扩展正则,那就要把量词转义:
awk '/^[0-9]\{1,2\}\/[0-9]\{1,2\}\/[0-9]\{2\} [0-9]\{1,2\}:[0-9]\{1,2\}:[0-9]\{2\}/' file.txt
这种写法兼容性最高,但可读性差一些,优先推荐前两种方案。
验证测试
用你的示例数据测试:
12/21/17 20:11:57 data data data #应匹配
12/21/17 20:12:18 data data data #应匹配
12/21/17 20:12:20 data data data #应匹配
12/21/2017 data data #不应匹配
以上三种awk命令都会正确输出前三行,第四行不会被匹配,和你的预期一致。
内容的提问来源于stack exchange,提问作者user2773013

