如何用sed和date命令替换字符串中指定格式的日期并提前3天
解决方案
一、sed 实现方案
你的核心问题是shell会优先执行$(...)命令替换,此时sed还未捕获到\1对应的日期字段,导致\1在shell层面无意义,date命令无法识别。要让sed捕获的字段传递给date,可借助GNU sed的s///e选项(执行替换后的字符串作为shell命令):
echo "M;12345678900000;Z;;FEWO;F;010622;0.0;;;1.00;0.00;1.25;Y;;;XXX" | sed -E 's/^(([^;]*;){6})([0-9]{2})([0-9]{2})([0-9]{2})(;.*)$/echo "\1$(date -d "\3/\4/20\5 -3 days" +%d%m%y)\6"/e'
关键说明:
- 用
-E启用扩展正则,简化括号写法:^(([^;]*;){6}):匹配前6个字段(含末尾分号)([0-9]{2})([0-9]{2})([0-9]{2}):拆分第七个字段为日(\3)、月(\4)、年(\5)(原格式为ddmmyy,需转为日/月/20年让date识别)(;.*)$:匹配第七个字段后的所有内容
s///e选项会将替换后的字符串作为shell命令执行,此时$(date ...)能拿到sed捕获的日期值,计算出早3天的日期后拼接回原字符串。
如果是BSD sed(如macOS环境),不支持e选项,可改用xargs结合shell处理:
echo "M;12345678900000;Z;;FEWO;F;010622;0.0;;;1.00;0.00;1.25;Y;;;XXX" | sed -E 's/^(([^;]*;){6})([0-9]{6})(;.*)$/\1\3\4\x00/;s/\n//g' | xargs -0 -I {} bash -c 'str="{}"; date_part=${str:24:6}; new_date=$(date -d "${date_part:0:2}/${date_part:2:2}/20${date_part:4:2} -3 days" +%d%m%y); echo "${str:0:24}${new_date}${str:30}"'
二、awk 实现方案
awk的字段分割能力更适合这类需求,直接按分号拆分字段后处理第七个日期字段即可:
1. 通用版本(调用系统date命令)
echo "M;12345678900000;Z;;FEWO;F;010622;0.0;;;1.00;0.00;1.25;Y;;;XXX" | awk -F';' -v OFS=';' '{ # 拆分ddmmyy格式为日、月、年 dd = substr($7,1,2) mm = substr($7,3,2) yy = substr($7,5,2) # 构造date命令计算早3天的日期 cmd = "date -d \"" dd "/" mm "/20" yy " -3 days\" +%d%m%y" cmd | getline new_date close(cmd) # 关闭管道避免资源泄漏 $7 = new_date print $0 }'
2. GNU awk 高效版本(内置日期函数)
如果使用GNU awk(gawk),可直接用内置函数处理日期,无需调用外部命令:
echo "M;12345678900000;Z;;FEWO;F;010622;0.0;;;1.00;0.00;1.25;Y;;;XXX" | gawk -F';' -v OFS=';' '{ dd = substr($7,1,2) + 0 mm = substr($7,3,2) + 0 yy = substr($7,5,2) + 2000 # 转换为时间戳,减去3天的秒数(3*86400) timestamp = mktime(yy " " mm " " dd " 0 0 0") - 3*86400 # 格式化为ddmmyy格式 $7 = strftime("%d%m%y", timestamp) print $0 }'
关键说明:
mktime(yy " " mm " " dd " 0 0 0"):将年月日转换为Unix时间戳- 减去3天的总秒数(3×24×60×60=259200)
strftime("%d%m%y", timestamp):把新时间戳转换回ddmmyy格式
内容的提问来源于stack exchange,提问作者242710
相关产品推荐
相关产品推荐

