Füllen Sie Dateinamen auf, sodass Unix sie in numerischer Reihenfolge auflistet

Füllen Sie Dateinamen auf, sodass Unix sie in numerischer Reihenfolge auflistet

Ich habe einen Ordner mit mehreren Dateien, die wie folgt formatiert sind:

C Block Scan copy 1.pdf
C Block Scan copy 2.pdf
C Block Scan copy 3.pdf
C Block Scan copy 4.pdf
.
.
.

Ein Problem, das ich habe, ist, dass Unix sie beim Ausführen lsals auflistet

C Block Scan copy 1.pdf
C Block Scan copy 10.pdf
C Block Scan copy 11.pdf
C Block Scan copy 12.pdf
.
.
.

Ich möchte die Zahlen auffüllen, so dass Unix sie (hoffentlich) in der Reihenfolge auflistet, wie

C Block Scan copy 01.pdf
C Block Scan copy 02.pdf
C Block Scan copy 03.pdf
.
.
.
C Block Scan copy 09.pdf
C Block Scan copy 10.pdf
C Block Scan copy 11.pdf
C Block Scan copy 12.pdf
.
.
.

Ich habe einen Beitrag mit einem ähnlichen Problem gefunden.Auffüllen einer Zahl in einem Dateinamen auf eine feste Länge, aber ich habe versucht, ihre Lösung auf meinen Fall anzuwenden, aber es hat nicht funktioniert. Folgendes habe ich versucht:

for f in *.pdf; do
    int=`basename $f .pdf | cut -d '.' -f 2`
    new_name=`printf "file.%0.2i.pdf\n” $int`
    [ ! -f $new_name ] && mv $f $new_name
done

Ich gebe zu, dass dies eine blinde Anpassung ihrer Lösung an meine Situation ist, was mir nicht gefällt, da ich die zugrunde liegende Syntax nicht wirklich verstehe und mein Rang bei StackExchange noch nicht hoch genug ist, um diesen Beitrag zu kommentieren.

Ich bin neu im Shell-Scripting, daher wäre eine Erklärung der Syntax hilfreich und willkommen.

Falls es hilft: Ich verwende macOS Mojave 10.14.6 und habe Brew installiert.

Dank im Voraus.

Antwort1

Mit zsh(jetzt die Standardbenutzer-Shell unter macOS):

autoload zmv # best in ~/.zshrc
zmv '(* )([0-9].pdf)' '${1}0$2'

Antwort2

Dadurch werden alle „*.pdf“-Dateien im aktuellen Verzeichnis gefunden und umbenannt, deren Namen dem in der Frage beschriebenen Muster folgen. Sie erhalten denselben Namen, jedoch mit einer auf zwei Ziffern aufgefüllten Nummer:

#!/usr/bin/env bash

shopt -s nullglob

for f in *[[:space:]][0-9].pdf; do
    int="$(basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1)"
    name="$(basename "$f" | rev | cut -d ' ' -f2- | rev)"
    padded_int="$(printf "%02d\n" "$int")"

    echo mv "$f" "$(printf "%s %s.pdf" "$name" "$padded_int")"

done

Entfernen Sie es echo, bevor mves tatsächlich ausgeführt wird mv, aber führen Sie es zuerst so aus, wie es ist, um sicherzustellen, dass es das tut, was Sie möchten. Beispielverwendung mit dem oben genannten Skript, gespeichert unter pdf.sh:

$ for i in {1..10}; do touch "C Block Scan copy $i.pdf"; done
$ ./pdf.sh
mv C Block Scan copy 1.pdf C Block Scan copy 01.pdf
mv C Block Scan copy 2.pdf C Block Scan copy 02.pdf
mv C Block Scan copy 3.pdf C Block Scan copy 03.pdf
mv C Block Scan copy 4.pdf C Block Scan copy 04.pdf
mv C Block Scan copy 5.pdf C Block Scan copy 05.pdf
mv C Block Scan copy 6.pdf C Block Scan copy 06.pdf
mv C Block Scan copy 7.pdf C Block Scan copy 07.pdf
mv C Block Scan copy 8.pdf C Block Scan copy 08.pdf
mv C Block Scan copy 9.pdf C Block Scan copy 09.pdf

Die erste Zeile:

#!/usr/bin/env bash

ist einsiebang. Außerdem verwende ich envfürseine Eigenschaften.

Diese Linie

shopt -s nullglob

Sätzenullglob Shell-Option was auch auf der verlinkten Seite erklärt wird:

nullglob

If set, Bash allows filename patterns which match no files to
expand to a null string, rather than themselves.

Dies ist erforderlich, um den Start einer For-Schleife zu verhindern, wenn keine Dateien vorhanden sind, die den Musterkriterien entsprechen:

for f in *[[:space:]][0-9].pdf; do

*[[:space:]][0-9].pdfist ein Shell-Muster, das bedeutet, dass nach Dateien gesucht wird, deren Namen aus einer beliebigen Anzahl von Zeichen bestehen, gefolgt von einem Leerzeichen, gefolgt von einer einzelnen Ziffer und endend mit.pdf. In der Schleife $fbefindet sich der Name der verarbeiteten PDF-Datei.

Hier

int="$(basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1)"

wir gebrauchenBefehlsersetzung um einer Variablen einen ganzzahligen Teil des angegebenen Dateinamens zuzuweisen. Sie können sehen, was basenamepassiert, man basenameund die Pipeline im Terminal reproduzieren:

$ f='C Block Scan copy 1.pdf'
$ echo basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1
1
$ f='C Block Scan copy 5.pdf'
$ echo basename "$f" | rev | cut -d ' ' -f1 | rev | cut -d . -f1
5

(Beachten Sie, dass $hier einEingabeaufforderung wird verwendet, um den Beginn einer neuen Zeile anzuzeigen, ist nicht Teil des Befehls).

In der nächsten Zeile

name="$(basename "$f" | rev | cut -d ' ' -f2- | rev)"

wir extrahieren den Namensteil der PDF-Datei, also alles vor der Nummer.

In der nächsten Zeile

padded_int="$(printf "%02d\n" "$int")"

Wir verwenden den integrierten Bash- printfBefehl, um es aufzufüllen $intund in einer Variable namens zu speichern padded_int. In der letzten Zeile der Schleife

echo mv "$f" "$(printf "%s %s.pdf" "$name" "$padded_int")"

wir führen ( echonatürlich ohne) die eigentliche Umbenennung mithilfe von printf und Befehlsersetzung erneut aus. wird mit 2 Formatbezeichnern und 2 entsprechenden Argumenten printfverwendet , ähnlich wie in C.%s

Die letzte Zeile

done

schließt den Kreis.

Antwort3

PE-Parametererweiterung verwenden. Nur mvfür externe Tools aus der bashShell.

#!/usr/bin/env bash

shopt -s nullglob

for f in *[[:space:]][0-9].pdf; do
  n=${f##* }  ##: Remain only 1.pdf, 2.pdf etc.
  n=0${n%.*}  ##: Remain only 1 , 2 etc. and pad 0 so it will be 01, 02 ..
  echo mv -v "$f" "${f/[0-9]/"$n"}"  ##: Replace all [0-9] with the value of "$n"
done

verwandte Informationen