ubuntuusers.de

bash: Befehl/Script um mehrere Dateien umzubenennen.

Status: Ungelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

zebulon-ufh

Avatar von zebulon-ufh

Anmeldungsdatum:
12. Dezember 2016

Beiträge: 50

Hallo!

Auf der Suche nach einem Befehl/Script, mehrere Dateien in einem Rutsch umzubenennen, bin ich weder beim Googlen nach "mv"- oder "ren"-Beispielen noch gar in der Manpage der einschlägigen Befehle fündig geworden und brauche bitte deswegen wieder einmal Hilfe von euch. Gerne auch als Hilfe zur Selbsthilfe, um nicht ständig "dumme" Fragen stellen zu müssen.

Konkret geht es um einen rsync-"Unfall" (dessen Ursache ich wohl auch noch in einem anderen Brett erfragen müsste, hier ist aber erst einmal Doktorn am Symptom angesagt), der aus "foo.bar"-Dateinamen an der Quelle ".foo.bar.Xyzzy"-Namen am Ziel erzeugte. Nun suche ich händeringend nach einem Befehl/Script, welcher/s erstmal die Dateinamen wieder korrekt umbenennen sollte:

1.) Den führenden Punkt entfernen

2.) Die Extension ".Xyzzy" entfernen

Besonders "tricky" scheint mir dabei bereits der führende Punkt zu sein; eine "for in"-Schleife zum sukzessiven Bepuscheln aller Dateien scheint mir deswegen erst gar nichts zu finden. Vom eigentlichen Umbenennen erst gar nicht zu reden …

Wer möchte mir bitte dabei behülflich sein?

TIA, Ulrich

P.S.: Eure Forensoftware verlangt die Angabe einer Ubuntu-Version, obzwar das Problem wohl versionsübergreifend ist. So habe ich denn mal eine ausgewürfelt, weil meine nicht dabei ist …

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7782

Ui. Sind die Dateien denn überhaupt intakt?

Wenn du mit rsync eine Datei "foobar.img" überträgst, dann nennt rsync diese auf dem Ziel als ".foobar.img.6hfF1b". (6hfF1b ist dabei ein zufälliger String, da eine Datei mit dem Namen ja auch regulär existieren könnte.)

Je nach Dateigröße dauert der Up- bzw. Download ja eine ganze Weile. Erst wenn die Datei komplett ist, wird sie dann umbenannt zu "foobar.img".

Die kaputten Sachen sind versteckt bzw. werden (solange kein Stromausfall o.ä. eintritt) bei Fehler auch wieder gelöscht. So kannst du bei rsync sicher sein, daß Dateien immer richtig und vollständig sind.

Umgekehrt wenn solche .foo.bar.Xyzzy Dateien über bleiben, eben die Annahme daß da was nicht stimmt.

Umbenennen könntest du so probieren:

# dateien die mit . beginnen, und mit . gefolgt von sechs beliebigen Zeichen enden
for f in .*.??????
do
    echo mv -v -i "$f" "${f:1:-7}"
done

wenns gefällt, das echo wegmachen

das schnippt dann einfach das erste (.) und die letzten 7 (.??????) Zeichen vom Dateinamen weg.

Dateiliste unbedingt kontrollieren da das Pattern oben auch falsche Dateien erwischen kann (z.B. .Readme.md.un~ weil das zufällig gerade 6 Zeichen sind nach dem .), es gibt keine Garantie, daß nur rsync Dateien so gefunden werden.

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17604

Wohnort: Berlin

Das letzte Mal, als ich sowas gebraucht habe, gab es das separat zu installierende rename, welches ein Perl-Script ist und über Jahre weltweit von führenden Linuxusern empfohlen wurde. Ob es noch aktuell unter dem Namen läuft weiß ich nicht, aber ich wüsste nicht, wieso nicht.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apt search rename
Sortierung... Fertig
Volltextsuche... Fertig
antpm/xenial 1.17-2 amd64
  ANT+ information retrieval client for Garmin GPS products

# (...)

rename/xenial,xenial,now 0.20-4 all  [installiert]
  Perl extension for renaming multiple files

Bis mindestens 16.04 auch noch offiziell in den Ubunturepos.

Dass die for-Schleife nichts findet liegt wohl am führenden Punkt.

1
2
3
4
5
6
7
8
9
for f in *
do 
  echo $f
done 

for f in .*
do 
  echo $f
done 

Von den oberen zwei Schleifen findet nur die untere versteckte Dateien.

zebulon-ufh

(Themenstarter)
Avatar von zebulon-ufh

Anmeldungsdatum:
12. Dezember 2016

Beiträge: 50

frostschutz schrieb:

Ui. Sind die Dateien denn überhaupt intakt?

Ja.

Wenn du mit rsync eine Datei "foobar.img" überträgst, dann nennt rsync diese auf dem Ziel als ".foobar.img.6hfF1b". (6hfF1b ist dabei ein zufälliger String, da eine Datei mit dem Namen ja auch regulär existieren könnte.)

Je nach Dateigröße dauert der Up- bzw. Download ja eine ganze Weile. Erst wenn die Datei komplett ist, wird sie dann umbenannt zu "foobar.img".

Das scheitert bunt gemischt (bei jedem rsync-Lauf in einem anderen Verzeichnis, während die einen fehlerfrei übertragen werden. Aber immer wieder alle Dateien des betroffenen Directorys) an einem sinngemäßen "Cannot rename: Permission denied(13)". Höchstwahrscheinlich deswegen habe ich solche "Leichen" am Ziel. Bei mehreren rsync-Läufen sogar mehrere. Aber das zu ergründen, sind wir wohl im falschen Brett.

Umbenennen könntest du so probieren:

# dateien die mit . beginnen, und mit . gefolgt von sechs beliebigen Zeichen enden
for f in .*.??????

Diese Muster werde ich in diesem Leben wohl nie verstehen. RegEx ist es schonmal nicht …

do
    echo mv -v -i "$f" "${f:1:-7}"
done

Schaumama. Im Moment sitze ich nicht am Zielrechner.

das schnippt dann einfach das erste (.) und die letzten 7 (.??????) Zeichen vom Dateinamen weg.

Mhh. Gab's da nicht auchmal einen Befehl, der einen Dateinamen in Name und Erweiterung zerlegt?

Ulrich

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11248

Wohnort: München

zebulon-ufh schrieb:

Diese Muster werde ich in diesem Leben wohl nie verstehen. RegEx ist es schonmal nicht …

Das ist ein einfaches Glob-Muster (vgl. http://man7.org/linux/man-pages/man7/glob.7.html). Der Punkt steht für einen Punkt, der Stern für beliebig viele Zeichen und jedes Fragezeichen für ein beliebiges Zeichen.

zebulon-ufh

(Themenstarter)
Avatar von zebulon-ufh

Anmeldungsdatum:
12. Dezember 2016

Beiträge: 50

frostschutz schrieb:

Umbenennen könntest du so probieren:

# dateien die mit . beginnen, und mit . gefolgt von sechs beliebigen Zeichen enden
for f in .*.??????
do
    echo mv -v -i "$f" "${f:1:-7}"
done

Was will mir daraufhin der Pinguin mit

bash: -7: Teilstring-Ausdruck < 0

sagen?

Irgendwie treffen da mit dem und mir Welten aufeinander ☹

Ulrich

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11248

Wohnort: München

Da dürfte ein Leerzeichen nach dem zweiten Doppelpunkt fehlen, vgl. https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html Stichwort "negative offset"

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7782

zebulon-ufh schrieb:

Was will mir daraufhin der Pinguin mit

bash: -7: Teilstring-Ausdruck < 0

sagen?

Die Meldung kommt wenn der Variableninhalt zu kurz ist.

var="hallo"
echo ${var:1:-7}
# bash: -7: substring expression < 0
var="hallo welt"
echo ${var:1:-7}
# al

Allerdings kann im obigen Beispiel dieser Fall eigentlich gar nicht eintreten, da f ja auf .*.?????? gesetzt wird, was immer lang genug ist (auch wenn so eine Datei gar nicht existiert, was man vielleicht vorher prüfen sollte *hust*)

Das Problem bei diesen Substring-Spielereien ist, sie funktionieren nur im Kontext. Und der Kontext ist hier die Variable hat ein überflüssiges Zeichen am Anfang und sieben überflüssige Zeichen am Ende. 😉

zebulon-ufh

(Themenstarter)
Avatar von zebulon-ufh

Anmeldungsdatum:
12. Dezember 2016

Beiträge: 50

frostschutz schrieb:

zebulon-ufh schrieb:

Was will mir daraufhin der Pinguin mit

bash: -7: Teilstring-Ausdruck < 0

sagen?

Die Meldung kommt wenn der Variableninhalt zu kurz ist.

Die Meldung kommt hier bei jedem "-". Ich hab's jetzt mal in zwei Schritte getrennt:

for f in .*.??????; do f1=${f:1};echo mv -i -v "$f" "${f1%.*}"; done

"${f:1}" nimmt den führenden "." weg. "${f1%.*}" strippt die (letzte) Extension. Das testweise "echo" wegzunehmen traue ich mich heute nicht mehr 😉

Ulrich

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7782

zebulon-ufh schrieb:

Die Meldung kommt hier bei jedem "-".

Versteh ich nicht.

$ touch ". was ist denn jetzt ein - bitte.6hfF1b"
$ for f in .*.?????? ; do echo mv -i -v "$f" "${f:1:-7}"; done
mv -i -v . was ist denn jetzt ein - bitte.6hfF1b  was ist denn jetzt ein - bitte
$ for f in .*.?????? ; do mv -i -v "$f" "${f:1:-7}"; done
renamed '. was ist denn jetzt ein - bitte.6hfF1b' -> ' was ist denn jetzt ein - bitte'
$ rm " was ist denn jetzt ein - bitte"

Wenn das bei dir 1:1 so nicht klappt... mit welcher Shell(-Version) bist du denn unterwegs? EDIT: die negative substring-länge gibts scheinbar erst seit Bash 4.2 ... also seit 2011

"${f:1}" nimmt den führenden "." weg. "${f1%.*}" strippt die (letzte) Extension. Das testweise "echo" wegzunehmen traue ich mich heute nicht mehr 😉

Das kannst natürlich auch machen. Hat den Vorteil daß du die Anzahl .?????? ändern kannst ohne das -7 entsprechend anzupassen.

zebulon-ufh

(Themenstarter)
Avatar von zebulon-ufh

Anmeldungsdatum:
12. Dezember 2016

Beiträge: 50

frostschutz schrieb:

zebulon-ufh schrieb:

Die Meldung kommt hier bei jedem "-".

Versteh ich nicht.

Egal, was ich als Parameter hinter dem zweiten Doppelpunkt angebe: Wenn der negativ ist (== bei jedem "-"), gibt es diese Fehlermeldung. Auch das von seahawk1986 empfohlene Leerzeichen hinter dem zweiten Doppelpunkt oder auch in anderen Google-Treffern gefundene Klammern von negativen Parametern - also ${f:1:(-7)} - funktioniert nicht.

$ touch ". was ist denn jetzt ein - bitte.6hfF1b"
$ for f in .*.?????? ; do echo mv -i -v "$f" "${f:1:-7}"; done
mv -i -v . was ist denn jetzt ein - bitte.6hfF1b  was ist denn jetzt ein - bitte
$ for f in .*.?????? ; do mv -i -v "$f" "${f:1:-7}"; done
renamed '. was ist denn jetzt ein - bitte.6hfF1b' -> ' was ist denn jetzt ein - bitte'
$ rm " was ist denn jetzt ein - bitte"

Hä?

Wenn das bei dir 1:1 so nicht klappt...

test=1234567
echo ${test:1:-1}
# müsste eigentlich 23456 ergeben. Ergibt aber:
bash: -1: Teilstring-Ausdruck < 0.

mit welcher Shell(-Version) bist du denn unterwegs? EDIT: die negative substring-länge gibts scheinbar erst seit Bash 4.2 ... also seit 2011

bash --version
GNU bash, Version 4.1.5(1)-release (i486-pc-linux-gnu)

Ja, ich beabsichtige mein Home von diesem alten Ubuntu 10.04 LTS - welches ich als Version nicht angeben konnte! - auf ein neues zu rsyncen. Und ja: Ich denke wohl immer wieder fälschlicherweise Linux==Linux und nicht bash!=bash. Interessanterweise klappte das alles problemlos, nur der Inhalt von manchen - ständig wechselnden - Unterverzeichnissen unterhalb ~/music.flac macht solchen Fuzzak ☹

"f1=${f:1}" nimmt den führenden "." weg. "${f1%.*}" strippt die (letzte) Extension.

Das kannst natürlich auch machen. Hat den Vorteil daß du die Anzahl .?????? ändern kannst ohne das -7 entsprechend anzupassen.

Das hat vor Allem den Vorteil, wohl zu funktionieren :-p

Kaum ist (scheint?) aber ein Problem gelöst, kommt das nächste: Wie formuliere ich das nun so, daß es in allen Unterverzeichnissen unterhalb eines Verzeichnisses (hier konkret: ~/music.flac. Alle andern lassen sich problemlos rsyncen) ausgeführt wird?

Ulrich

frostschutz

Avatar von frostschutz

Anmeldungsdatum:
18. November 2010

Beiträge: 7782

shopt -s globstar

for df in **/.*.??????
do
    d=$(dirname "$df")
    f=$(basename "$df")
    echo mv -v -i "$d"/"$f" "$d"/"${f:1:-7}"
done

das globstar gibts seit Bash 4.0 😉

zebulon-ufh

(Themenstarter)
Avatar von zebulon-ufh

Anmeldungsdatum:
12. Dezember 2016

Beiträge: 50

frostschutz schrieb:

shopt -s globstar

for df in **/.*.??????
do
    d=$(dirname "$df")
    f=$(basename "$df")
    echo mv -v -i "$d"/"$f" "$d"/"${f:1:-7}"
done

das globstar gibts seit Bash 4.0 😉

Trotzdem bekomme ich auch damit wieder das "-7" angemeckert. Macht aber nichts, wenn ich es wieder als

for df in **/.*.??????
do
    d=$(dirname "$df")
    f=$(basename "$df")
    f1=${f:1}
    mv -v -i "$d"/"$f" "$d"/"${f1%*}"
done
 

umschreibe.

Trotzdem herzliches Dankeschön für den "for/in"-Rahmen: Er scheint mir grundsätzlich eine Lösung für "mache $irgendwas mit passenden Dateien unter allen Unterverzeichnissen" zu sein. Von selbst wäre ich auf den nicht gekommen.

TNX, Ulrich

user_unknown

Avatar von user_unknown

Anmeldungsdatum:
10. August 2005

Beiträge: 17604

Wohnort: Berlin

P.S.: Eure Forensoftware verlangt die Angabe einer Ubuntu-Version, obzwar das Problem wohl versionsübergreifend ist. So habe ich denn mal eine ausgewürfelt, weil meine nicht dabei ist …

Wenn man solch alte Software einsetzt, wofür es gute Gründe geben kann, dann sollte man das schon klar dazu sagen.

zebulon-ufh

(Themenstarter)
Avatar von zebulon-ufh

Anmeldungsdatum:
12. Dezember 2016

Beiträge: 50

user_unknown schrieb:

Wenn man solch alte Software einsetzt, wofür es gute Gründe geben kann,

In der Tat: http://u-heidenreich.de/why1004.html

dann sollte man das schon klar dazu sagen.

Was nutzt es, wenn ich die Version im Dropdownfeld nicht auswählen kann? Zudem war ich felsenfest davon überzeugt, daß so etwas Grundlegendes wie die bash (also noch älter als mein 10.04 LTS) inzwischen in Stein gemeisselte Wahrheit ist …

Aber nix für ungut: Das Doktorn am Symptom funktioniert ja jetzt. In welchem Unterforum mag ich nun mindestens genauso "dumme Fragen"™ stellen dürfen, was der Grund für den rsync-Unfall gewesen sein mag?

Ulrich

Antworten |