Alle Dateinamen mit einer bestimmten Anzahl von Zeichen abrufen

Alle Dateinamen mit einer bestimmten Anzahl von Zeichen abrufen

Ich möchte alle Dateinamen ändern, die genau die Länge von 16 Zeichen (Ziffern und Kleinbuchstaben) haben. Ich habe es mit [0-9a-z]{16}und [0-9a-z]\{16\}für den Platzhalter regXim folgenden Snippet versucht, aber es funktioniert nicht.

for file in <regX>
do
  mv "$file" "${file}.txt"
done

Antwort1

Shell-Globbing-Mustersind keine regulären AusdrückeSie sehen zwar ähnlich aus, funktionieren aber in mancher Hinsicht ganz unterschiedlich.

Der reguläre Ausdruck [0-9a-z]{16}stimmt mit einer Zeichenfolge überein, die eine Folge von 16 Zeichen des genannten Zeichenbereichs enthält (die Zeichenfolge mit der Übereinstimmung kann länger sein).

Das entsprechende Shell-Globbing-Muster wäre etwa wie folgt

*[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]*

Das ist weil

  1. Globbing-Muster unterstützen keine Modifikatoren wie „das vorherige N-mal wiederholen“.
  2. Globbing-Muster sind standardmäßig am Anfang und Ende verankert. Deshalb habe ich *am Anfang und Ende des Musters eingefügt. A *entspricht einer beliebigen Anzahl beliebiger Zeichen. Entfernen Sie diese, wenn Sie übereinstimmen möchtengenau16 Zeichen.

[0-9a-z]Sie können mit Perl eine Zeichenfolge aus 16 Zeichen erstellen :

$ pattern="$( perl -e 'print "[0-9a-z]" x 16' )"

Mit bashkönnen Sie über alle Namen im aktuellen Verzeichnis iterieren und dann testen, ob die Namen mit Ihrem regulären Ausdruck übereinstimmen:

for name in *; do
    if [[ -f "$name" ]] && [[ "$name" =~ ^[0-9a-z]{16}$ ]]; then
        echo mv "$name" "$name.txt"
    fi
done

Entfernen Sie es, echosobald Sie sicher sind, dass es das Richtige tut.

Beachten Sie, dass ich das Muster verankert habe, sodass längere Namen nicht übereinstimmen. Mit dem -fTest stelle ich außerdem sicher, dass die Namen, die wir erhalten, tatsächlich nur die von regulären Dateien sind.

Antwort2

Mitextglob

shopt -s extglob
for file in +([0-9a-z])
do
    [[ ${#file} == 16 ]] && echo mv "$file" "${file}.txt"
done
  • +([0-9a-z])bedeutet ein oder mehrere [0-9a-z]Zeichen
  • ${#file}gibt die Länge des Dateinamens an
  • echoist für den Probelauf, entfernen Sie, sobald alles in Ordnung ist

Antwort3

Wenn Sie über perl-rename verfügen (wird renameauf Debian-basierten Systemen aufgerufen, perl-renameauf anderen), können Sie Folgendes tun:

perl-rename -n 's/^[0-9a-z]{16}$/$&.txt/' *

Wenn das das gewünschte Ergebnis bringt, entfernen Sie das , -ndamit die Dateien tatsächlich umbenannt werden. Die Syntax von perl-renameist ein Perl-Befehl. Hier verwenden wir den Substitutionsoperator ( ), der durch s/from/to/ersetzt . Das ist in diesem Fall Ihr regulärer Ausdruck und das ist die spezielle Variable , die „was auch immer übereinstimmt“ bedeutet, plus die Erweiterung .fromtofromto$&.txt


Um dies mit einem Shell-Glob zu tun (verwenden Sie@Kusalanandasoder@SundeepsAnsatz, dies dient nur der Vollständigkeit):

for f in [0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]; do
    mv -- "$f" "$f".txt
done

Mit GNU find:

find . -regextype posix-extended -regex '.*/[0-9a-z]{16}' -exec mv {} {}".txt" \;

Antwort4

L16=$(csh -c 'repeat 16 echo -n "?"')
find . -name "$L16" ! -name '*[!0-9a-z]*' -exec sh -c '
   mv "$1" "$1.txt"
' {} {} \;

verwandte Informationen