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

まず、引用符は正規表現の特殊文字の意味を抑制します(オンラインマニュアル):

追加のバイナリ演算子=~、...を使用してパターンのすべての部分を引用して、引用符付き部分を文字列に一致させることができます。 ...正規表現構文で特殊文字を一致させるには、その文字を引用して特殊文字を削除する必要があります。

マニュアルでは、シェル構文解析と正規表現構文との競合を防ぐために、正規表現を変数に入れることをお勧めします。

第二に、\dあなたが思うように動作せず、ただテキストと一致しますd

さらに、${BASH_REMATCH[0]}インデックス付きの完全一致文字列1とそれ以上は、キャプチャされたグループに含まれます。

また、次のように4桁の年を使用することをお勧めします。

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。前にゼロの数字は、シェルやその他のユーティリティで8進数として扱われます。

(1900年代の日付を処理する必要がある場合、4桁の年は問題ではなく、月単位ではなく年で識別する方が簡単です。)

答え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$month10進整数で前に0が表示されている場合はsを削除し、2桁の年を$day参照)。-%-m%-d%y

(GNUとは異なり、statシンボリックリンクタイプファイルの場合、シンボリックリンク自体の修正時間ではなく、シンボリックリンクターゲットの修正時間が考慮されます。GNUではstatこれを使用できますstat -L)。

関連情報