So entfernen Sie (1) mit dem Befehl find aus Dateinamen

13

Ich habe kürzlich alle meine FLAC-Dateien mit XLD auf meinem Mac OS 10.7 (Lion) auf eine niedrigere Abtastrate von 44,1 kHz und eine Bittiefe von 24 Bit konvertiert (da iPhone / iPod darüber hinaus nichts unterstützen).

Obwohl ich XLD anwies, alle vorherigen Dateien zu überschreiben, fügte XLD (1)am Ende einer Datei wie von ein

some_song.m4a

zu

some_song(1).m4a

Jetzt möchte ich das (1)von allen FLAC-Dateien entfernen, die ich konvertiert habe.

Ich weiß, ich hätte wahrscheinlich ein Programm oder sogar ein AppleScript verwenden können, um die Dateien umzubenennen, aber ich wollte lernen, wie man die alte Kommandozeile benutzt.

Ich weiß, dass find . -name *\(1\).m4aalle konvertierten FLAC-Datei greifen wird.

Als nächstes weiß ich, dass ich etwas mit den gefundenen Dateien anfangen -execund mvsie umbenennen muss. Aber was ich nicht herausfinden kann, ist, wie man den ursprünglichen Dateinamen behält und nur den entfernt (1).

Möglicherweise muss ich eine Gruppen-Regex-Erfassung durchführen, um den Teil des Dateinamens zu speichern, den ich nicht ändern möchte? Oder vielleicht ist es nicht möglich, alles in einer Zeile zu tun, und ich sollte ein Shell-Skript erstellen (was ich nicht so gerne mache, aber ich bin bereit, es zu versuchen).

Irgendwelche Tipps oder Vorschläge sind willkommen! Vielen Dank!

hobbes3
quelle
5
Warum die Gegenstimme? Es scheint eine gültige Frage zu sein ...
Unabhängig von Ihrer speziellen Frage (an find), die möglicherweise Ihr eigentliches Problem löst (Konvertieren von Audiodateien), sind Sie möglicherweise an einem Blick auf audiotools.sourceforge.net und auf diesen Beispielfall (für macosx lion) invibe.net/ interessiert. LaurentPerrinet / SciBlog / 2012-04-22
meduz

Antworten:

13

Versuchen Sie nicht, die findAusgabe zu analysieren, außer als letztes Mittel. Es ist wichtig zu wissen, dass Dateinamen auf Unix-Dateisystemen keine Strings sind (ein weit verbreitetes Missverständnis), sondern binäre Blobs, die alle Zeichen außer /dem Null-Zeichen enthalten können. Das sichere und korrekte Parsen von Dateinamen ist eine Qual, die Sie in 99% der Fälle nur vermeiden möchten (sehen Sie sich nur an, wie haarig der sedAusdruck in @ yareks Antwort ist und selbst das deckt nicht alle Fälle ab). . Zum Glück gibt es in diesem Fall einen viel einfacheren Ansatz:

find . -name '*(1).m4a' -execdir sh -c \
'for arg; do mv "$arg" "${arg%(1).m4a}".m4a; done' _ {} \+
jw013
quelle
ordentlicher Ansatz noch so haarig wie der sed Ausdruck :) +1
yrk
1
hier fehlt etwas ... wo ist es done?
11.
@yarek Danke für den Fang. Der größte Unterschied zwischen diesem und dem sedRohransatz ist, dass dies viel sicherer ist. Es ist immer noch einfacher zu lesen als Regex-Backslash-Suppe, vorausgesetzt, Sie verstehen einige grundlegende Shell-Skriptkonstrukte.
jw013
Du hast recht; das ist viel sauberer. Und die $argVariable erleichtert das Lesen erheblich.
hobbes3
1
@DQdlM Das Snippet ich oben geschrieben gerade ist findAufruf shmit ziemlich portable POSIX - Syntax. Weitere Informationen finden Sie im Abschnitt zur Parametererweiterung , im Abschnitt zu zusammengesetzten Befehlen zur Erläuterung der forSchleife und in der POSIX- findSpezifikation . Zusätzlich zu diesen Ressourcen beantworte ich gerne Ihre spezifischen Fragen.
jw013
6

Unter Debian und Ubuntu kann ich rename 's/\(1\)//' *.m4aIhr Problem lösen.

Dom
quelle
Seltsam, das kann ich man rename, aber ich habe eigentlich nicht rename: -bash: rename: command not found( which renamezeigt nichts).
hobbes3
@ hobbes3 hier auf dem Mac man -a renamefindet Umbenennungs (2) - die syscall und Umbenennungs (n) - den TCL - Befehl. Es gibt dort weder umbenennen (1) noch das Dienstprogramm selbst.
11.
1
IIRC renameist ein Perl-Skript, das in den Beispielen einiger Perl-Installationen enthalten ist, und einige Distributionen fügen es in den Pfad ein, weil es ein praktischer Befehl ist. (@ Hobbes vielleicht finden Sie es im Internet)
Kevin
@ Kevin auf meinem System renameist normal binär (nicht Perl). Eine weitere Einschränkung ist jedoch, dass nicht alle Versionen der renameUnterstützung reguläre Ausdrücke unterstützen. Die Version, die ich zum Beispiel habe, erlaubt nur das direkte Ersetzen von Strings, zBrename '(1)' '' *.m4a
Patrick
1
Das Perl- renameSkript wird nur von Debian und Derivaten installiert. Andere Linux-Systeme haben ein anderes renameDienstprogramm (von Patrick gezeigt). OSX hat keine.
Gilles 'SO - hör auf böse zu sein'
4

In zsh mit zmv :

autoload zmv      # you can put this line in your .zshrc
zmv '(*)\(1\)(*)' '$1$2'

In dem zweiten Argument (der neue Name), $1und $2beziehen sich auf die eingeklammerten Gruppen (PATTERN)in dem Quellenmuster. Eine andere Art, diese Umbenennung zu schreiben, ist

zmv '(*)' '${1/\(1\)/}'
Gilles 'SO - hör auf böse zu sein'
quelle
3

Der folgende Ansatz gibt Ihnen die Möglichkeit, die generierten Befehle vor dem Ausführen in der Vorschau anzuzeigen / zu bereinigen. Er ist sehr portabel: Er sollte nicht nur auf einem Mac funktionieren, nicht nur mit bash und nicht nur mit GNU sed. Selbst auf Systemen ohne find(1) Befehl ist es problemlos möglich, sie durch du(1) zu ersetzen .

find . -name '*(1).m4a' |
sed 's/\(.*\)(1).m4a$/mv & \1.m4a/' 

Wenn Sie mit den gedruckten Befehlen zufrieden sind, führen Sie sie mit | sh -xangehängten Befehlen erneut aus .

Wenn Sie sich Gedanken über Leerzeichen in Dateinamen machen, fügen Sie ein weiteres s hinzu , um alle Leerzeichen zu umgehen:

find . -name '*(1).m4a' |
sed -e 's/ /\\ /g' -e 's/\(.*\)(1).m4a$/mv & \1.m4a/'

Wenn andere Sonderzeichen erwartet werden, wird es ein bisschen kniffliger:

find . -name '*(1).m4a' |
sed -e "s/'/'\\\\''/g" -e 's/\(.*\)(1).m4a$/mv '\''&'\'' '\''\1.m4a'\'/

Die erste Funktion wandelt alles 'in eine Form um, die in der Mitte eines '...'Strings wörtlich genommen wird . Die zweite Funktion generiert mv- Befehle, deren Argumente in eingeschlossen sind '...'.

yrk
quelle
1
Dieser Befehl maskiert den Dateinamen (die Leerzeichen (und alle anderen Sonderzeichen) nicht und setzt den Dateinamen nicht in Anführungszeichen. Ich habe versucht, Ihren Befehl zu ändern, konnte aber nicht herausfinden, wie Anführungszeichen um beide Dateinamen für den mvBefehl eingefügt werden . Eine der resultierenden Ausgaben Ihres Befehls ist mv ./The Beatles - Let It Be (MFSL LP 1-109) 24-96 Vinyl Rip/01 Two Of Us(1).m4a ./The Beatles - Let It Be (MFSL LP 1-109) 24-96 Vinyl Rip/01 Two Of Us.m4a. Und wenn ich diesen Befehl ausführe, bekomme ich -bash: syntax error near unexpected token '('.
hobbes3
dies soll eine hausaufgabe sein :) aber ok, ich aktualisiere die
antwort
Übrigens kann GNU sed den Befehl selbst ausführen, indem es den eBefehl nach dem Ersetzen hinzufügt . Zum Beispiel find . -name '*(1).m4a' | sed 's/\(.*\)(1).m4a$/mv & \1.m4a/e'wird der Befehl ausgeführt, ohne eine Weiterleitung an sh -x.
Ansturm
@ Rush das ist der einzige sed der das macht; und es muss die Shell trotzdem starten, aber eine neue für jeden Befehl (erinnert an das make- Problem, nicht
wahr
2
Ich denke nicht, dass wir abstimmen sollten. Es ist schließlich eine gültige Lösung.
hobbes3
1

Hier ist ein kleines Skript, das das macht:

for var in `find . -type f -name "*(1).m4a"`; do
    new=`echo $var | cut -d'(' -f1`;
    mv $var $new.m4a;
done
Anupam
quelle
Dieser erstickt an Dateien mit Leerzeichen im Namen. Auch erfordert es groß genug , um temporäre Speicher für das`find ...`
Yrk