Cómo eliminar el (1) de los nombres de archivo con el comando find

13

Recientemente convertí todos mis archivos FLAC a una velocidad de muestreo más baja de 44.1 kHz y una profundidad de bits de 24 bits (porque iPhone / iPod no admite nada por encima de eso) usando XLD en mi Mac OS 10.7 (Lion).

Aunque le dije a XLD que sobrescribiera todos los archivos anteriores, XLD agregó un (1)al final del mismo archivo como de

some_song.m4a

a

some_song(1).m4a

Así que ahora quiero eliminar eso (1)de todos los archivos FLAC que convertí.

Sé que probablemente podría haber usado algún programa o incluso un AppleScript para cambiar el nombre de los archivos, pero quería aprender a usar la línea de comando de la vieja escuela.

Sé que find . -name *\(1\).m4atomará todo el archivo FLAC convertido.

A continuación, sé que tengo que hacer algo -execy mvcambiar el nombre de todos los archivos encontrados. Pero lo que no puedo entender es cómo mantener el nombre de archivo original y solo eliminar el (1).

¿Tal vez necesito hacer una captura de expresiones regulares grupales para almacenar la parte del nombre de archivo que no quiero modificar? O tal vez no sea posible hacer todo en una línea y debería crear un script de shell (que no me siento tan cómodo haciendo, pero estoy dispuesto a intentarlo).

¡Cualquier sugerencia o sugerencia es bienvenida! ¡Gracias!

hobbes3
fuente
55
¿Por qué el voto negativo? Parece una pregunta válida ...
no relacionado con su pregunta particular (encendido find) pero que puede estar resolviendo su problema real (convertir archivos de audio), puede estar interesado en echar un vistazo a audiotools.sourceforge.net y a este caso de ejemplo (para macosx lion) invibe.net/ LaurentPerrinet / SciBlog / 2012-04-22
meduz

Respuestas:

13

No intente analizar la findsalida, excepto como último recurso. Es importante darse cuenta de que en los sistemas de archivos Unix, los nombres de los archivos no son cadenas (un error común) sino más bien blobs binarios que pueden contener cualquier carácter excepto /el carácter nulo. Analizar los nombres de los archivos de manera segura y correcta es un dolor suficiente que el 99% de las veces solo querrás evitar hacerlo por completo (solo mira cuán peluda es la sedexpresión en la respuesta de @ yarek e incluso eso no cubre todos los casos) . Afortunadamente, en este caso hay un enfoque mucho más simple:

find . -name '*(1).m4a' -execdir sh -c \
'for arg; do mv "$arg" "${arg%(1).m4a}".m4a; done' _ {} \+
jw013
fuente
enfoque ordenado pero tan peludo como la expresión sed :) +1
yrk
1
falta algo aquí ... ¿dónde está done?
yrk
@yarek Gracias por la captura. La mayor diferencia entre este y el sedenfoque de la tubería es que es mucho más seguro. Todavía es más fácil de leer que la sopa de barra invertida regex, siempre que comprenda algunas construcciones básicas de secuencias de comandos de shell.
jw013
Tienes razón; Esto es mucho más limpio. Y la $argvariable hace que sea mucho más fácil de leer.
hobbes3
1
@DQdlM El fragmento que publiqué anteriormente solo findinvoca shcon una sintaxis POSIX bastante portátil. Para obtener más detalles, puede consultar la sección sobre Expansión de parámetros , la sección sobre comandos compuestos que explica el forbucle y la especificación POSIXfind . Además de esos recursos, con gusto responderé cualquier pregunta específica que tenga.
jw013
6

En Debian y Ubuntu, puedo usarlo rename 's/\(1\)//' *.m4apara resolver su problema.

Dom
fuente
Extraño, puedo hacerlo man rename, pero en realidad no tengo rename: -bash: rename: command not found( which renameno muestra nada).
hobbes3
@ hobbes3 en la Mac aquí man -a renameencuentra rename (2) - syscall, y rename (n) - el comando TCL. No hay rename (1) ni la utilidad en sí.
yrk
1
IIRC, renamees un script perl incluido con los ejemplos incluidos en algunas instalaciones perl, y un par de distribuciones lo incluyen en la ruta porque es un comando conveniente. (@Hobbes quizás puedas encontrarlo en Internet)
Kevin
@Kevin en mi sistema renamees binario normal (no perl). Sin embargo, otra advertencia es que no todas las versiones de renamesoporte regexes. La versión que tengo, por ejemplo, solo le permite hacer reemplazos directos de cadenas, por ejemplorename '(1)' '' *.m4a
Patrick
1
El renamescript Perl solo es instalado por Debian y sus derivados. Otros sistemas Linux tienen una renameutilidad diferente (mostrada por Patrick). OSX no tiene ninguno.
Gilles 'SO- deja de ser malvado'
4

En zsh, usando zmv :

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

En el segundo argumento (el nuevo nombre), $1y se $2refieren a los grupos entre paréntesis (PATTERN)en el patrón fuente. Otra forma de escribir este cambio de nombre es

zmv '(*)' '${1/\(1\)/}'
Gilles 'SO- deja de ser malvado'
fuente
3

El siguiente enfoque le brinda la capacidad de previsualizar / podar los comandos generados antes de ejecutarlos, y es muy portátil: debería funcionar no solo en un mac, no solo con bash y no solo con GNU sed; incluso en sistemas sin findcomando (1) es posible sustituirlo por du(1) sin problemas.

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

Si está satisfecho con los comandos impresos, vuelva a ejecutarlos con | sh -xadjuntos.

Si le preocupan los espacios en los nombres de archivo, agregue otros s para escapar de todos los espacios:

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

Si se esperan otros caracteres especiales, se vuelve un poco más complicado:

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

La primera función convierte todo 'en una forma tal que se toman literalmente cuando están en el medio de '...'una cadena escaneada. La segunda función genera comandos mv cuyos argumentos están encerrados dentro '...'.

yrk
fuente
1
Ese comando no se escapa del nombre de archivo (los espacios, (y todos los demás caracteres especiales) o agrega comillas alrededor del nombre de archivo. Intenté modificar su comando, pero no pude descubrir cómo agregar comillas alrededor de ambos nombres de archivo para el mvcomando. Uno de los resultados resultantes de su comando es 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. Y si ejecuto ese comando me sale -bash: syntax error near unexpected token '('.
hobbes3
se supone que esto es una tarea :) pero está bien, actualizaré la respuesta
yrk
Por cierto, GNU sed puede ejecutar el comando mismo agregando el ecomando después de la sustitución. Por ejemplo, find . -name '*(1).m4a' | sed 's/\(.*\)(1).m4a$/mv & \1.m4a/e'se ejecutará el comando sin canalizar a sh -x.
prisa
@Rush es el único sed que hace eso; y necesita iniciar el shell de todos modos, pero uno nuevo para cada comando (recuerda el problema de la marca , ¿no?)
yrk
2
No creo que debamos votar en contra. Es una solución válida después de todo.
hobbes3
1

Aquí hay un pequeño script que lo hace:

for var in `find . -type f -name "*(1).m4a"`; do
    new=`echo $var | cut -d'(' -f1`;
    mv $var $new.m4a;
done
anupam
fuente
éste se ahogará con archivos con espacios en sus nombres; también requiere almacenamiento temporal lo suficientemente grande para el`find ...`
yrk