Come rimuovere (1) dai nomi dei file usando il comando find


13

Di recente ho convertito tutti i miei file FLAC a una frequenza di campionamento inferiore di 44,1 kHz e una profondità di 24 bit (perché iPhone / iPod non supportano nulla di simile) utilizzando XLD sul mio Mac OS 10.7 (Lion).

Anche se ho detto a XLD di sovrascrivere tutti i file precedenti, XLD ha aggiunto un (1)alla fine di un file come da

some_song.m4a

per

some_song(1).m4a

Quindi ora voglio rimuoverlo (1)da tutti i file FLAC che ho convertito.

So che probabilmente avrei potuto usare un programma o addirittura un AppleScript per rinominare i file, ma volevo imparare usando la vecchia riga di comando.

So che find . -name *\(1\).m4aafferrerà tutto il file FLAC convertito.

Quindi so che devo fare qualcosa con -exece mvrinominare tutti i file trovati. Ma quello che non riesco a capire è come mantenere il nome file originale e rimuovere solo il (1).

Forse ho bisogno di fare un po 'di regex di cattura per memorizzare la parte del nome del file che non voglio modificare? O forse non è possibile fare tutto in una riga e dovrei creare uno script di shell (cosa che non mi piace fare, ma sono disposto a provarlo).

Eventuali suggerimenti o suggerimenti sono i benvenuti! Grazie!


5
Perché il downvote? Sembra una domanda valida ...

non correlato alla tua domanda specifica ( attivatafind ) ma che potrebbe risolvere il tuo problema reale (conversione di file audio), potresti essere interessato a dare un'occhiata a audiotools.sourceforge.net e al caso di esempio (per macosx lion) invibe.net/ LaurentPerrinet / SciBlog / 22-04-2012
meduz,

Risposte:


13

Non tentare di analizzare l' findoutput se non come ultima risorsa. È importante rendersi conto che sui file system Unix, i nomi dei file non sono stringhe (un'idea sbagliata comune) ma piuttosto BLOB binari che possono contenere qualsiasi carattere tranne /e il carattere null. L'analisi dei nomi dei file in modo sicuro e corretto è una sofferenza che il 99% delle volte vorresti solo evitare di fare del tutto (guarda solo quanto è capricciosa l' sedespressione nella risposta di @ yarek e anche questo non copre tutti i casi) . Per fortuna, in questo caso esiste un approccio molto più semplice:

find . -name '*(1).m4a' -execdir sh -c \
'for arg; do mv "$arg" "${arg%(1).m4a}".m4a; done' _ {} \+

approccio pulito ma peloso come l'espressione sed :) +1
anno

1
qualcosa manca qui ... dov'è done?
anno

@yarek Grazie per la cattura. La più grande differenza tra questo e l' sedapproccio pipe è che è molto più sicuro. È ancora più facile da leggere rispetto alla zuppa di barra rovesciata regex, a condizione che tu comprenda alcuni costrutti di scripting di shell di base.
jw013,

Hai ragione; questo è molto più pulito. E la $argvariabile rende molto più facile la lettura.
hobbes3,

1
@DQdlM Lo snippet che ho postato sopra sta semplicemente findinvocando shuna sintassi POSIX abbastanza portatile. Per ulteriori dettagli, è possibile consultare la sezione sull'espansione dei parametri , la sezione sui comandi composti che spiega il forciclo e le specifiche POSIXfind . Oltre a queste risorse, sarei felice di rispondere a qualsiasi domanda specifica tu abbia.
jw013,

6

Su Debian e Ubuntu, posso usare rename 's/\(1\)//' *.m4aper risolvere il tuo problema.


Strano, posso farlo man rename, ma in realtà non ho rename: -bash: rename: command not found( which renamenon mostra nulla).
hobbes3,

@ hobbes3 sul mac qui man -a renametrova rename (2) - syscall e rename (n) - il comando TCL. Non ci sono né rinomina (1) né l'utilità stessa lì.
anno

1
IIRC, renameè uno script perl incluso con gli esempi inclusi in alcune installazioni di perl e un paio di distro lo includono nel percorso perché è un comando conveniente. (@Hobbes forse lo puoi trovare su Internet)
Kevin,

@Kevin sul mio sistema renameè binario normale (non perl). Tuttavia, un altro avvertimento è che non tutte le versioni di renameregex supportano. La versione che ho, ad esempio, ti consente solo di sostituire direttamente le stringhe, ad esrename '(1)' '' *.m4a
Patrick

1
Lo renamescript Perl è installato solo da Debian e derivati. Altri sistemi Linux hanno renameun'utilità diversa (mostrata da Patrick). OSX non ha nessuno dei due.
Gilles 'SO- smetti di essere malvagio'

4

In zsh, usando zmv :

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

Nel secondo argomento (il nuovo nome), $1e $2fare riferimento ai gruppi tra parentesi (PATTERN)nel modello di origine. Un altro modo di scrivere questa ridenominazione è

zmv '(*)' '${1/\(1\)/}'

3

Il seguente approccio ti dà la possibilità di visualizzare in anteprima / potare i comandi generati prima di eseguirli, ed è molto portabile: dovrebbe funzionare non solo su un Mac, non solo con bash, e non solo con GNU sed; anche su sistemi senza findcomando (1) è possibile sostituirlo con du(1) senza problemi.

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

Se sei soddisfatto dei comandi stampati, riesegui con l' | sh -xaggiunta.

Se sei preoccupato per gli spazi nei nomi dei file, aggiungi altri s per sfuggire a tutti gli spazi:

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

Se sono previsti altri caratteri speciali, diventa un po 'più complicato:

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

La prima funzione converte tutti 'in una forma in modo tale che questi siano presi letteralmente quando sono nel mezzo di '...'una stringa con escape. La seconda funzione genera comandi mv i cui argomenti sono racchiusi all'interno '...'.


1
Quel comando non sta sfuggendo al nome del file (gli spazi (e tutti gli altri caratteri speciali) o aggiungendo virgolette attorno al nome del file. Ho provato a modificare il tuo comando, ma non sono riuscito a capire come aggiungere virgolette attorno a entrambi i nomi di file per il mvcomando. Uno degli output risultanti dal tuo comando è 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. E se eseguo quel comando ottengo -bash: syntax error near unexpected token '('.
hobbes3,

questo dovrebbe essere un compito a casa :) ma ok, aggiornerò la risposta
yrk

A proposito GNU sed può eseguire il comando stesso aggiungendo il ecomando dopo la sostituzione. Ad esempio find . -name '*(1).m4a' | sed 's/\(.*\)(1).m4a$/mv & \1.m4a/e'eseguirà il comando senza eseguire il piping a sh -x.
corsa

@ Rush è l'unica sed che lo fa; e deve comunque avviare la shell, ma una nuova per ogni comando (ricorda il problema del make , no?)
yrk,

2
Non penso che dovremmo votare in negativo. Dopo tutto è una soluzione valida.
hobbes3,

1

Ecco un piccolo script che lo fa:

for var in `find . -type f -name "*(1).m4a"`; do
    new=`echo $var | cut -d'(' -f1`;
    mv $var $new.m4a;
done

questo si strozzerà con file con spazi nei loro nomi; inoltre richiede una memoria temporanea abbastanza grande per il`find ...`
yrk
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.