
Ich möchte Dateien behalten, deren Namen mit übereinstimmen [0-9A-Z]{1,2}_\d{4}_\w+?\.dat
, z. B. A1_2001_pm23aD.dat
, K_1998_12.dat
, und den Rest entfernen.
ls
Die Befehle und rm
unterstützen solche regulären Ausdrücke jedoch nicht. Wie kann ich das tun?
Antwort1
Erweiterte Globs verwenden:
shopt -s extglob
printf '%s\n' !([[:digit:][:upper:]]?([[:digit:][:upper:]])_[[:digit:]][[:digit:]][[:digit:]][[:digit:]]_+([[:alnum:]]).dat)
Dadurch werden alle Datei-/Verzeichnisnamen gedruckt, die nicht ( !
) übereinstimmen [[:digit:][:upper:]]
, gefolgt von Null oder Eins, [[:digit:][:upper:]]
gefolgt von 4 [[:digit:]]
zwischen _
s und dann Eins oder mehr [[:alnum:]]
vor der Erweiterung .dat
.
Wenn Sie rekursiv suchen möchten:
shopt -s globstar
shopt -s extglob
printf '%s\n' **/!([[:digit:][:upper:]]?([[:digit:][:upper:]])_[[:digit:]][[:digit:]][[:digit:]][[:digit:]]_+([[:alnum:]]).dat)
Alternativ mit gnu find
(Sie können einen regulären Ausdruck verwenden):
find . -regextype egrep ! -regex '.*/[[:digit:][:upper:]]{1,2}_[[:digit:]]{4}_[[:alnum:]]+\.dat$'
Antwort2
Dafür gibt es viele Möglichkeiten. Sie können eine Skriptsprache verwenden, die reguläre Ausdrücke versteht. In Perl beispielsweise:
perl -le 'unlink(grep(!/[0-9A-Z]{1,2}_\d{4}_\w+?.dat/,@ARGV))' *
Dadurch wird nach allen Dateien gesucht (keine Unterverzeichnisse) im aktuellen Verzeichnis, sammeln Sie diejenigen, die nicht dem regulären Ausdruck entsprechen, und löschen Sie sie.
Sie können etwas Ähnliches auch mit Bash tun, Sie müssen lediglich den regulären Ausdruck in POSIX ERE übersetzen:
for f in *; do
[[ "$f" =~ [0-9A-Z]{1,2}_[0-9]{4}_[a-zA-Z0-9]+.dat ]] || rm "$f";
done
Beachten Sie, dass in Ihrem regulären Ausdruck \w+?.dat
versucht wird, die kleinstmögliche alphanumerische Zeichenfolge zu findenbeliebiges Zeichenund dat
. Ich verstehe nicht, warum Sie hier verwenden möchten, +?
und Sie wollten wahrscheinlich verwenden \.dat
. Ich vermute, Sie möchten wahrscheinlich auch sicherstellen, dass der gesamte Dateiname übereinstimmt, sodass Dinge wie foobarfoobarfoobarA1_2001_pm23aD.datfoobarfooabr
ebenfalls entfernt werden. Wenn ja, verwenden Sie stattdessen eines davon:
perl -le 'unlink(grep(!/^[0-9A-Z]{1,2}_\d{4}_\w+\.dat$/,@ARGV))' *
oder
for f in *; do
[[ "$f" =~ ^[0-9A-Z]{1,2}_[0-9]{4}_[a-zA-Z0-9]+.dat$ ]] || rm "$f";
done
Um schließlich auch Verzeichnisse zu löschen, können Sie Folgendes tun:
for f in *; do
[[ "$f" =~ ^[0-9A-Z]{1,2}_[0-9]{4}_[a-zA-Z0-9]+.dat$ ]] || rm -rf "$f";
done
Antwort3
Sie können dies tun mit find
:
find . -regextype posix-extended \
-type f ! -regex '.*/[0-9A-Z]{1,2}_[[:digit:]]{4}_[[:alnum:]_]+?\.dat' -delete
- Natürlich können Sie alles in eine Zeile packen (indem Sie das
\
am Ende der ersten Zeile entfernen). -regextype posix-egrep
scheint genauso gut zu funktionieren wie-regextype posix-extended
.- Wenn Ihre Version von
find
nicht unterstützt-delete
, verwenden Sie-exec rm -- {} +
oder-exec rm -- {} ';'
. - Wenn Sie nur im obersten Verzeichnis suchen möchten, verwenden Sie
-maxdepth 1
.