我正在尝试从bash中的字符串/文件路径中提取日期。这是我希望工作的,但不是:
#!/bin/bash
f=/mnt/media/CameraUploads/CMGPH_20190626_200707386.gif
if [[ $f =~ (19|20)\d\d(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01]) ]]; then
strresult=${BASH_REMATCH[1]}
echo $strresult
else
echo "unable to parse string $f"
fi
我期望$ strresult = 20190626
我在做什么错了?
答案 0 :(得分:1)
最简单的方法是简单地使用带有子字符串删除功能的参数扩展隔离日期,然后传递给date -d
以转换为您喜欢的任何格式的日期,例如>
f=/mnt/media/CameraUploads/CMGPH_20190626_200707386.gif
t="${f%_*}" ## trim from right to 1st '_'
t="${t##*_}" ## trim from left to final '_' isolating date
date -d "$t" ## call date format as needed
使用/输出示例
$ f=/mnt/media/CameraUploads/CMGPH_20190626_200707386.gif
> t="${f%_*}" ## trim from right to 1st '_'
> t="${t##*_}" ## trim from left to final '_' isolating date
> date -d "$t" ## call date format as needed
Wed Jun 26 00:00:00 CDT 2019
如果希望包含文件名的 time 部分,可以执行相同的操作。
要隔离完整的日期/时间字符串,您可以执行以下操作:
f=/mnt/media/CameraUploads/CMGPH_20190626_200707386.gif
t="${f%.*}" ## trim from right to 1st '.'
t="${t##*_}" ## trim from left to final '_' isolating time
t="${t:0:2}:${t:2:2}:${t:4:2}.${t:6:3}" ## format time with : between
d="${f%_*}" ## trim from right to 1st '_'
d="${d##*_}" ## trim from left to final '_' isolating date
d="${d:0:4}-${d:4:2}-${d:6:2}" ## format date with - between
date -d "$d $t" ## call date format as needed
传递给"$d $t"
的最后一个date
字符串是:
2019-06-26 20:07:07.386
示例输出
Wed Jun 26 20:07:07 CDT 2019
编辑-文件名中的日期/时间
如果根据您的编辑,date_time
可以出现在文件名中的任意位置,并且如果time
可以包含或不包含毫秒,则使用日期/时间提取的有效方法是使用sed
隔离yyyymmdd_hhmmssSSSS
字符串,然后使用进程替换将隔离的字符串馈送到while
循环以进行上述处理。 (唯一的变化是您在将.SSSS
毫秒添加到时间字符串之前检查是否存在毫秒-在下面的示例中限制为4位-必要时添加)
#!/bin/bash
while read line || [ -n "$line" ]; do
d="${line%_*}"
d="${d##*_}" ## trim from left to final '_' isolating date
d="${d:0:4}-${d:4:2}-${d:6:2}" ## format date with - between
t="${line#*_}"
t="${t##*_}" ## trim from left to final '_' isolating time
t="${t:0:2}:${t:2:2}:${t:4:2}" ## format time with : between
[ -n "${t:6:4}" ] && t="$t.${t:6:4}" ## append miliseconds if present
printf "%s\n\n" "$(date -d "$d $t")"
done < <(sed 's/^[^0-9]*\([0-9][0-9_]*\).*$/\1/' "$1")
示例输入文件名
$ cat file
20181214_195948-ANIMATION.gif
20191012_223451.jpg
IMG_20181122_182138511.jpg
VID_20160909_163547.3gp
使用/输出示例
$ bash extract.sh file
Fri Dec 14 19:59:48 CST 2018
Sat Oct 12 22:34:51 CDT 2019
Thu Nov 22 18:21:38 CST 2018
Fri Sep 9 16:35:47 CDT 2016
这应该涵盖评论中发布的文件名。
答案 1 :(得分:1)
Bash正则表达式不支持非POSIX标准的\d
表达式。
相反,您需要使用[0-9]
或[[:digit:]]
。
请将您的正则表达式行修改为:
if [[ $f =~ (19|20)[0-9]{2}(0[1-9]|1[012])(0[1-9]|[12][0-9]|3[01]) ]]; then
strresult=${BASH_REMATCH[0]}
那么您会得到:
20190626
请注意,${BASH_REMATCH[0]}
包含与整个字符串匹配的子字符串
正则表达式,而${BASH_REMATCH[1]}
保留与第一个匹配的部分
带括号的子表达式。
希望这会有所帮助。