BASH 不喜歡我的正規表示式

BASH 不喜歡我的正規表示式

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

相關內容