sed命令转换mm/dd/yyyy至DD-MMM-YYYY格式出错求助
问题描述
需要将字符串06/08/2023 06:30:11 06/08/2023 06:30:19中的mm/dd/yyyy格式日期转换为DD-MMM-YYYY格式(预期结果:08-JUN-2023 06:30:11 08-JUN-2023 06:30:19),但执行以下sed命令后得到错误日期01-Feb-0003:
echo "06/08/2023 06:30:11 06/08/2023 06:30:19" | sed -E 's#([0-9]{2})/([0-9]{2})/([0-9]{4})#'"$(echo '\2/\1/\3' | xargs -I{} date -d {} +'%d-%^b-%Y')"#g
错误原因
核心问题是命令替换的执行时机:
- Shell会优先解析
$(...)部分,此时sed的捕获组\2、\1、\3还未被sed匹配替换,只是单纯的字面字符串。 echo '\2/\1/\3'输出的是\2/\1/\3,传给date -d后,date会忽略非数字字符,将其解析为2/1/3(即0003年2月1日),因此生成错误的01-Feb-0003。- 最终sed拿到这个错误结果,将所有匹配到的日期全部替换成它,导致整体输出错误。
正确解决方案
方案1:使用awk(跨平台兼容性好)
awk可直接处理捕获组,并通过strftime函数转换日期格式(需GNU awk或支持该函数的awk版本):
echo "06/08/2023 06:30:11 06/08/2023 06:30:19" | awk '{ for (i=1; i<=NF; i++) { if ($i ~ /^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/) { split($i, d, "/"); mktime(d[3]" "d[1]" "d[2]" 0 0 0"); $i = strftime("%d-%^b-%Y"); } } print $0 }'
输出结果:
08-JUN-2023 06:30:11 08-JUN-2023 06:30:19
方案2:使用GNU sed的e命令(仅适用于GNU sed)
GNU sed支持e标志,可将替换后的内容作为shell命令执行,并用输出替换原匹配内容:
echo "06/08/2023 06:30:11 06/08/2023 06:30:19" | sed -E 's#([0-9]{2})/([0-9]{2})/([0-9]{4})#echo "\2/\1/\3" | xargs -I{} date -d {} +"%d-%^b-%Y"#ge'
g表示全局替换,e表示执行替换生成的shell命令,用命令输出替换原匹配的日期字符串。
方案3:使用Shell循环处理(适合简单场景)
input="06/08/2023 06:30:11 06/08/2023 06:30:19" output="" for word in $input; do if [[ $word =~ ^([0-9]{2})/([0-9]{2})/([0-9]{4})$ ]]; then new_date=$(date -d "${BASH_REMATCH[2]}/${BASH_REMATCH[1]}/${BASH_REMATCH[3]}" +'%d-%^b-%Y') output="$output $new_date" else output="$output $word" fi done echo "${output# }"
内容的提问来源于stack exchange,提问作者Mahesh
相关产品推荐
相关产品推荐

