如何使用awk选取CSV文本列并重格式化datetime字段
awk处理CSV时的时间字段格式化方法
首先需要明确一个高频踩坑点:你提到的直接用awk '{print $1,$5,$6}'的写法,在这个逗号分隔、无内嵌空格的CSV上是无法正常工作的。awk默认字段分隔符为任意空白字符,这类无空格的逗号分隔文件会被整行识别为$1,后续列的读取会全部失效,必须先在脚本中指定字段分隔符为逗号。
下面给出三种不同场景下的可落地实现:
方案1:正则逐次替换(全版本awk兼容)
原时间字段是结构固定的ISO格式,不需要复杂逻辑,逐次替换指定字符即可得到目标格式:
BEGIN { FS="," } { dt = $1 gsub(/-/, "", dt) # 移除年月日之间的横杠 gsub(/T/, "_", dt) # 将日期与时间之间的T分隔符替换为下划线 gsub(/:/, "", dt) # 移除时分秒之间的冒号 sub(/\..*/, ".x", dt) # 将小数点后的毫秒部分替换为固定的.x后缀 print dt, $5, $6 }
方案2:固定位置切片(适配macOS自带BSD awk)
由于输入的时间字符串为等长固定结构,直接按字符位置提取需要的片段拼接,不依赖gawk的专有特性,可在所有awk版本上运行:
BEGIN { FS="," } { # 按固定字符位置提取日期、时间片段 ymd = substr($1, 1, 4) substr($1, 6, 2) substr($1, 9, 2) hms = substr($1, 12, 2) substr($1, 15, 2) substr($1, 18, 2) print ymd "_" hms ".x", $5, $6 }
方案3:正则捕获组(Linux GNU awk下更简洁)
如果使用的是Linux系统内置的GNU awk,可以直接通过match函数的捕获组一次性提取需要的内容,代码更简洁:
BEGIN { FS="," } { match($1, /(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/, tm) dt = sprintf("%s%s%s_%s%s%s.x", tm[1], tm[2], tm[3], tm[4], tm[5], tm[6]) print dt, $5, $6 }
实际运行效果
针对你给出的测试数据,以上三种脚本运行后都会输出符合要求的结果:
20080114_133837.x C200801141338s 20080114T133837M583Z044 20080116_115444.x C200801161154d 20080116T115444M589Z012
内容的提问来源于stack exchange,提问作者wsdzbm
相关产品推荐
相关产品推荐

