我试图获取文件修改的 2 位数月份和 2 位数年份,但它不起作用。
modified=$(stat -c %y "$line");
# modified="2018-08-22 14:39:36.400469308 -0400"
if [[ $modified =~ ".{2}(\d{2})-(\d{2})" ]]; then
echo ${BASH_REMATCH[0]}
echo ${BASH_REMATCH[1]
fi
我究竟做错了什么?
答案1
首先,引号抑制了正则表达式中特殊字符的含义(在线手册):
可以使用附加的二元运算符
=~
, ... 可以引用模式的任何部分,以强制将引用的部分作为字符串进行匹配。 ...如果要匹配正则表达式语法中特殊的字符,则必须将其加引号以删除其特殊含义。
该手册继续建议将正则表达式放入变量中,以防止 shell 解析和正则表达式语法之间发生一些冲突。
其次,\d
不做你认为它做的事情,而只是匹配文字d
。
另请注意,${BASH_REMATCH[0]}
包含整个匹配字符串,索引1
和向上包含捕获的组。
我还强烈建议使用四位数年份,因此:
modified=$(stat -c %y "$file")
re='^([0-9]{4})-([0-9]{2})'
if [[ $modified =~ $re ]]; then
echo "year: ${BASH_REMATCH[1]}"
echo "month: ${BASH_REMATCH[2]}"
else
echo "invalid timestamp"
fi
对于今天修改的文件,给出year: 2018
和month: 08
。请注意,带有前导零的数字将被 shell 和可能的其他实用程序视为八进制。
(如果您需要处理 1900 年代的日期,四位数年份的问题较少,而且它们更容易识别为年份而不是月份中的日期。)
答案2
为此不需要正则表达式:
$ touch -t 197001010000 myfile
$ ls -l myfile
-rw-rw-r-- 1 jackman jackman 0 Jan 1 1970 myfile
$ IFS='-' read -r year month _rest < <(stat -c %y myfile)
$ echo "$year:${year#??}"$month"
1970:70:01
答案3
作为替代方案,使用 GNU date
,您可以执行以下操作:
eval "$(date -r "$file" +'year=%Y month=%-m day=%-d')"
要将修改时间的年、月和日部分分别存储在$year
、$month
和 中$day
(作为十进制整数,如果您关心前导零,请删除 和 中的 s;另请参阅2-
位年份)。%-m
%-d
%y
(请注意,与 GNU 相反stat
,对于符号链接类型的文件,会考虑符号链接目标的修改时间,而不是符号链接本身的修改时间。使用 GNU 时stat
,您可以使用stat -L
)。