Entfernen von Dateien durch regulären Ausdruck

Entfernen von Dateien durch regulären Ausdruck

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.

lsDie Befehle und rmunterstü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+?.datversucht 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.datfoobarfooabrebenfalls 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-egrepscheint genauso gut zu funktionieren wie -regextype posix-extended.
  • Wenn Ihre Version von findnicht unterstützt -delete, verwenden Sie -exec rm -- {} +oder -exec rm -- {} ';'.
  • Wenn Sie nur im obersten Verzeichnis suchen möchten, verwenden Sie -maxdepth 1.

verwandte Informationen