Shell脚本实现字母数字日期转数字格式问题求助
问题:转换特殊格式时间数据为标准CSV文件
我有一个每10分钟记录一次的数据文件,日期采用字母数字格式,示例如下:
00 hour 00 minute (00:00H) 00 hour 10 minute (00:10H) 00 hour 20 minute (00:20H) and so on
输入文件ifile.txt内容:
00:00H01JUN2021 1.900 00:10H01JUN2021 2.400 00:20H01JUN2021 2.100 00:30H01JUN2021 2.300 00:40H01JUN2021 2.00 00:50H01JUN2021 2.300 01:00H01JUN2021 2.300 01:10H01JUN2021 0.000 01:20H01JUN2021 2.200 01:30H01JUN2021 0.100
数据说明:
- 第一列为日期时间,格式为
HH:MMHDDMMMYYYY,其中前6个字符YY:XXH里,YY是小时,XX是分钟 - 第二列为对应时间的数值
期望转换为带标准数字日期格式的CSV文件ofile.txt,内容如下:
yyyy-mm-dd hh:mm:ss,val 2021-06-01 00:00:00,1.900 2021-06-01 00:10:00,2.400 2021-06-01 00:20:00,2.100 2021-06-01 00:30:00,2.300 2021-06-01 00:40:00,2.000 2021-06-01 00:50:00,2.300 2021-06-01 01:00:00,2.300 2021-06-01 01:10:00,0.000 2021-06-01 01:20:00,2.200 2021-06-01 01:30:00,0.100
我编写的脚本无法得到预期结果:
#!/bin/sh gawk ' BEGIN { month["Jan"] = "01"; month["Feb"] = "02"; month["Mar"] = "03"; month["Apr"] = "04"; month["May"] = "05"; month["Jun"] = "06"; month["Jul"] = "07"; month["Aug"] = "08"; month["Sep"] = "09"; month["Oct"] = "10"; month["Nov"] = "11"; month["Dec"] = "12"; } function timestamp_to_numeric(s) { # 00:00H01JUN2021 => 2021-06-01 00:00:00 return substr(s,12,4)"-"month[substr(s,9,3)]"-"substr(s,7,2) substr(s,1,2)":"substr(s,4,2)":""00" } NR==1 {next} END { printf "%s",timestamp_to_numeric($1),$2 printf "\n" } ' ifile.txt
解决方案
原脚本问题分析
- 错误跳过第一行数据:
NR==1 {next}会跳过输入的第一行有效数据,但输入文件没有表头,所有行都是数据行。 - 仅处理最后一行:所有处理逻辑放在
END块中,只会在所有行读完后执行一次,仅输出最后一行的结果。 - 时间格式拼接错误:
timestamp_to_numeric函数中,日期部分和时间部分之间缺少空格,会生成类似2021-06-0100:00:00的错误格式。 - 月份匹配失败:输入中的月份是大写(如
JUN),但脚本中用的是小写(Jun),导致无法正确映射月份数字。 - 数值格式不统一:输入中存在
2.00这种两位小数的数值,需要统一格式化为三位小数。
修正后的脚本
#!/bin/sh gawk ' BEGIN { # 输出CSV表头 print "yyyy-mm-dd hh:mm:ss,val" # 月份映射,使用大写匹配输入格式 month["JAN"] = "01"; month["FEB"] = "02"; month["MAR"] = "03"; month["APR"] = "04"; month["MAY"] = "05"; month["JUN"] = "06"; month["JUL"] = "07"; month["AUG"] = "08"; month["SEP"] = "09"; month["OCT"] = "10"; month["NOV"] = "11"; month["DEC"] = "12"; } function timestamp_to_numeric(s) { # 拆分时间和日期各分量 hour = substr(s, 1, 2) minute = substr(s, 4, 2) day = substr(s, 7, 2) mon = substr(s, 9, 3) year = substr(s, 12, 4) # 拼接为标准格式,添加日期与时间的分隔空格 return year "-" month[mon] "-" day " " hour ":" minute ":00" } # 逐行处理数据 { # 格式化数值为三位小数,确保格式统一 printf "%s,%.3f\n", timestamp_to_numeric($1), $2 } ' ifile.txt > ofile.txt
修正点说明
- 添加表头输出:在
BEGIN块中先打印CSV的表头行,符合预期输出格式。 - 修正月份映射键:将月份缩写改为大写,匹配输入中的
JUN格式,确保月份数字正确映射。 - 重构时间转换函数:拆分各时间分量后再拼接,明确添加日期和时间之间的空格,避免格式错误。
- 遍历处理每一行:将处理逻辑放在主循环中,逐行转换并输出所有数据。
- 统一数值格式:使用
%.3f格式化数值,自动将两位小数补为三位(如2.00转为2.000)。
验证结果
执行修正后的脚本,输出文件ofile.txt将完全符合预期的CSV格式要求。
内容的提问来源于stack exchange,提问作者Kay
相关产品推荐
相关产品推荐

