
我試圖獲取文件修改的 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
)。