
Ich versuche, den zweistelligen Monat und das zweistellige Jahr der Änderung einer Datei herauszufinden, aber es funktioniert nicht.
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
- Bash-Demo:http://rextester.com/DJSPH52792
- RegEx-Demo:https://regex101.com/r/UEOlMO/1
Was mache ich falsch?
Antwort1
Erstens unterdrücken die Anführungszeichen die Bedeutung der Sonderzeichen im regulären Ausdruck (Online-Handbuch):
Ein zusätzlicher binärer Operator,
=~
, ist verfügbar, … Jeder Teil des Musters kann in Anführungszeichen gesetzt werden, um die Übereinstimmung mit dem zitierten Teil als Zeichenfolge zu erzwingen. … Wenn Sie ein Zeichen zuordnen möchten, das für die Grammatik regulärer Ausdrücke eine Sonderstellung hat, muss es in Anführungszeichen gesetzt werden, um seine besondere Bedeutung zu entfernen.
Das Handbuch empfiehlt weiterhin, den regulären Ausdruck in eine Variable einzufügen, um Konflikte zwischen der Shell-Analyse und der Regex-Syntax zu vermeiden.
Zweitens: \d
Es tut nicht das, was Sie denken, sondern gleicht nur einen wörtlichen Wert ab d
.
Beachten Sie auch, dass ${BASH_REMATCH[0]}
die gesamte übereinstimmende Zeichenfolge enthalten ist und die Indizes 1
und höher die erfassten Gruppen enthalten.
Ich würde außerdem dringend empfehlen, vierstellige Jahreszahlen zu verwenden, also:
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
Für eine heute geänderte Datei ergibt das year: 2018
und month: 08
. Beachten Sie, dass Zahlen mit einer führenden Null von der Shell und möglicherweise anderen Dienstprogrammen als Oktalzahlen betrachtet werden.
(Vierstellige Jahreszahlen bereiten weniger Probleme, wenn Sie jemals mit Daten aus den 1900er Jahren arbeiten müssen, und sie sind leichter als Jahre und nicht als Monatstage zu erkennen.)
Antwort2
Hierfür sind keine regulären Ausdrücke erforderlich:
$ 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
Antwort3
Alternativ date
können Sie mit GNU Folgendes tun:
eval "$(date -r "$file" +'year=%Y month=%-m day=%-d')"
Um die Jahres-, Monats- und Tageskomponenten der Änderungszeit jeweils in und $year
zu speichern (entfernen Sie als Dezimalzahlen das s in und, wenn Ihnen die führenden Nullen nicht egal sind; siehe auch für zweistellige Jahreszahlen).$month
$day
-
%-m
%-d
%y
(Beachten Sie, dass im Gegensatz zu GNU stat
bei Dateien des Typs „symlink“ der Änderungszeitpunkt des Ziels des symbolischen Links und nicht der des symbolischen Links selbst berücksichtigt wird. Bei GNU stat
würden Sie verwenden stat -L
.)