Ersetzen Sie ein Wort in einem Verzeichnisnamen und in den Dateinamen in diesem Verzeichnis

7

Ich habe eine Verzeichnisstruktur wie diese:

Bookname Edition 1
  Bookname Edition 1 type1.pdf
  Bookname Edition 1 type2.pdf
Bookname Edition 2
  Bookname Edition 2 type1.pdf
  Bookname Edition 2 type2.pdf

Ich möchte rekursiv den Namen ändern aus , Editionum Volumeaus dem Verzeichnis und den Dateinamen in diesen Verzeichnissen.

Ich habe damit angefangen und das ist in Ordnung, wenn ich im Verzeichnis bin:

for f in *.pdf; do
    a="$(echo $f | sed s/Edition/Volume/)"
    mv "$f" "$a"
done

Dann habe ich versucht, alle Dateien unter den Verzeichnissen zu ändern, und dann blieb ich stecken ...

Können Sie mir bitte sagen, wie das geht, oder mir einen besseren Weg geben, das zu tun? Es gibt 15000 PDFs in 100 Verzeichnissen.

Bischof
quelle
Wie bist du genau festgefahren? Basierend auf dieser forSchleife würde ich annehmen, dass nichts passiert ist, aber ich möchte bestätigen.
Wjandrea
1
Das obige Skript hat alle Vorkommen von Edition in Volume im Verzeichnis geändert. Ich möchte dies von außerhalb des Verzeichnisses tun, da es über 100 Verzeichnisse voller PDFs gibt. Ich möchte auch den Verzeichnisnamen von Edition in Volume ändern.
Bischof
OK, aber wie bist du genau festgefahren?
Wjandrea

Antworten:

10

Wenn Ihre Struktur nur zwei Ebenen hat, müssen Sie keine Rekursion verwenden.

Analysieren Sie keine Dateinamen mit sed. Wenn Sie Regex und sedStilsyntax zum Umbenennen von Dateien verwenden möchten , verwenden Sie rename. Wenn Sie Ubuntu 17.10 verwenden, müssen Sie es installieren

sudo apt install rename

Dann können Sie die Antwort von pa4080 verwenden .

Mit rename, verwenden Sie die -nOption zum Testen.

rename -n 'expression' file(s)

Sie können auch einfach den mvBefehl verwenden. Als einzeiliger Befehl:

for d in ./*/; do mv -v "$d" "${d/Edition/Volume}"; done; for f in ./*/*; do mv -v "$f" "${f/Edition/Volume}"; done

Sie können echozum Testen mit verwenden mv, dh echo mv -v source destes werden hier ungenaue Ergebnisse angezeigt, es sei denn, Sie testen die Schleifen und führen sie dann separat aus.

Als Skript:

#!/bin/bash

# rename directories first
for d in ./*/; do
    mv -v "$d" "${d/Edition/Volume}"
done

# now rename files
for f in ./*/*; do
    mv -v "$f" "${f/Edition/Volume}"
done

mvund renameerkennen --, um das Ende der Optionen anzuzeigen. Da ./in diesem Beispiel alle Pfade mit beginnen , müssen wir dies nicht verwenden. Wenn jedoch Pfade beginnen dürfen -, verwenden Sie diese --am Ende von Optionen, z. B. um rename -n -- 's/foo/bar/' *zu verhindern, dass diese Pfade als Optionen interpretiert werden.

Zanna
quelle
Vielen Dank dafür - es hat die Verzeichnisnamen geändert, aber die Dateien darunter wurden nicht umbenannt.
Bischof
@ Bischof gut, sollte es. Was genau hast du gemacht?
Zanna
6

Bei mehrstufigen Verzeichnissen können Sie dies in einem Schritt tun. Das Problem besteht jedoch darin, dass Sie sicherstellen müssen, dass die Verzeichnisse von unten nach oben umbenannt werden, um zu verhindern, dass der Befehl oder das Skript den Verzeichnisnamen ändert, bevor der Inhalt geändert wird.

In Python können Sie Folgendes verwenden:

os.walk

in Kombination mit

topdown=False

In einem Skript:

#!/usr/bin/env python3
import os
import shutil
import sys

for root, dirs, files in os.walk(sys.argv[1], topdown=False):
    for f in files:
        shutil.move(
            root+"/"+f, root+"/"+f.replace("Edition", "Volume").strip()
        )
    for dr in dirs:
        shutil.move(
            root+"/"+dr, root+"/"+dr.replace("Edition", "Volume").strip()
        )

Speichern Sie das Skript unter change_name.pyund führen Sie es mit dem Verzeichnis als Argument aus:

python3 /path/to/change_name.py <directory>

Dies funktioniert rekursiv auf einer beliebigen Anzahl von Ebenen.

Jacob Vlijm
quelle
Sie können os.path.joinZeichenfolgen verwenden, anstatt sie mit zu verketten "/".
Eric Duminil
@EricDuminil absolut, aber in dieser Situation (Skript als Antwort) habe ich die weniger ausführliche Option verwendet. Es gibt keinerlei Unterschiede in der Funktionalität. Trotzdem danke.
Jacob Vlijm
2

Verwendung findmit der -depthOption kombiniert mit prename:

find [DIRS...] -depth | prename -n 's|Edition(?=[^/]*$)|Volume|'

Erläuterung:

  • -depthWählt Verzeichniskinder vor ihren Eltern aus. Ein Tool, das die ausgewählten Pfadnamen zum Umbenennen „verbraucht“, kann dann Kinder vor ihren Eltern umbenennen.

  • s|Edition(?=[^/]*$)|Volume|Ersetzt das erste Vorkommen Editionim Pfadnamen durch, Volume aber nur, wenn der Rest kein a enthält /, dh nur für die letzte Pfadnamenkomponente (erreicht durch die positive Vorausschau (?=[^/]*$)).

  • -nweist prenamean, die Pfade nicht tatsächlich umzubenennen, sondern zu drucken, wie sie umbenannt werden sollen. Entfernen Sie diese Option, um sie tatsächlich umzubenennen.

David Foerster
quelle