Acabo de perder una pequeña parte de mi colección de audio, por un estúpido error que cometí. :-(
DIVERTIDO Tenía una copia de seguridad bastante reciente, pero aún así era irritante. Aparte de la suya, el otro culpable que hizo la travesura fue mv
, que se mostrará de la siguiente manera:
Los archivos de audio tenían un cierto esquema:
ARTIST - Some Title YY.mp3
donde YY
es la especificación año de 2 dígitos.
mkdir 90<invisible control character>
(¡Hasta este momento, no sabía que había escrito un tercer carácter en exceso que era invisible ...!)
En lugar de tener todo en un directorio, quería tener toda la música de los 90 en un solo directorio. Entonces escribí:
find . -name '* 9?.mp3' -exec mv {} 90 \;
No es tan difícil de conseguir la idea de lo que sucedió eh? : ->
El (desastroso) resultado fue una virgen vacío directorio llamado '90 algo '(con algo de ser el carácter de control 'invisible') y un solo archivo llamado '90', sobrescritos n veces.
TODOS LOS ARCHIVOS habían desaparecido. : - (((obviamente)
Wish mv
hubiera verificado a tiempo si la firma del "archivo" de destino (recuerde en * NIX: Everything Is A File ) comienza con un d------
(por ejemplo drwxr-xr-x
). Y, por supuesto, si el destino existe en absoluto. Hay una variante del escenario antes mencionado, en las que simplemente se olvidó de mkdir
la guía en primer lugar. (pero por supuesto, asumiste que está ahí ...)
Incluso nuestra mascota OS-odio empezando por la capital W hace este. Incluso se le solicita que especifique el tipo de destino (¿archivo? ¿Directorio?) Si lo solicita.
Por lo tanto, me pregunto si nosotros * NIXers todavía tenemos que escribirnos un " mv
scriptlet" solo para evitar este tipo de sorpresas no deseadas.
.mp3
debería estar allí con el nombre90
, podría haber sido uno para el que no tenía una copia de seguridad.mv
no es el problema aquí, técnicamente, no sabe que usted está en movimiento una serie de archivos. Está ejecutandomv
una vez para cada archivo. Así es comofind -exec ;
funciona. Si lo hubiera usadofind -exec +
(como en algunos de los comentarios)mv
habría gritado tan pronto como recibiera más de un argumento.mv
de cada archivo puede parecer un poco menos pensada al principio, será (como dije anteriormente) la única solución sensata una vez que los archivos de origen estén dispersos entre varios subdirectorios. Que en mi caso de prueba, los archivos de origen estaban todos en un directorio no significa que sea mi caso de prueba real . Es, de hecho, sólo una simplificación, porque puede elaborar fácilmente en que por mi cuenta más adelante. Además, se hace preguntas menos tiempo para leer debido a su longitud reducida. :)mv
requerir que exista el destino?mv oldfile newfile
es la forma de cambiar el nombre de un archivo, y es una tontería esperarnewfile
que ya exista y sea un directorio.Respuestas:
Se puede añadir una
/
al destino si desea mover los archivos a un directorio. En caso de que el directorio no exista, recibirá un error:En caso de que el directorio exista, mueve el archivo a ese directorio.
fuente
GNU coreutils
mv
ya tiene una opción que especifica que desea mover a un directorio:-t
/--target-directory
. Si el argumento de esa opción no existe,mv
se quejará en lugar de mover todos sus archivos al mismo nombre de archivo.Yo habría escrito su motor de la siguiente manera:
Tenga en cuenta el uso de, en
+
lugar de\;
, agrupar tantos nombres de archivos como sea posible, lo que resulta en una ejecución más rápida.fuente
find . -name '* 9?.mp3' -exec sh -c 'exec mv "$@" 90/' sh {} +
Además, si generalmente planea evitar sobrescrituras accidentales en el futuro, existe la
-i
opciónmv
. Personalmente no puedo pensar en ningún inconveniente si ustedSi necesita sobrescribir algo, simplemente pase la
-f
opción.Los alias solo surten efecto si escribe el comando directamente en un shell interactivo, no para casos como invocación por
find
. Podrías haber corridoy luego se le habría preguntado si
mv
hubiera intentado sobrescribir un archivo existente.fuente
mv
. Este "truco" menos conocido hará que el comando con la barra diagonal inversa antepuesta ignore cualquier definición de alias.find ... -exec mv ...
, entonces necesitarás crear~/bin/mv
(o algún otro directorio apropiado) y hacerlo/bin/mv -i "$@"
, porquefind ... -exec
no mira los alias.env mv
. Menos mecanografía. :) Como mi diseño de teclado local requiere que se presione la tecla MAYÚS para una barra diagonal, siempre preferiría las versiones sin barra (si corresponde).mv
en una ubicación al principio$PATH
sería una solución más limpia. Por otro lado me primarly la casualidad de quemv
por descuido en el intérprete de comandos interactivo (porque pasa rápido). En el momento en que compongo algo más complejo, comofind
unfor
bucle o incluso un script de shell, tiendo a realizar algunas ejecuciones en seco (usandoecho
) para asegurarme de no romper algo. En aquellos casos en que no necesito una mano de retenciónmv
, porque ya estoy poniendo algunos pensamientos en ella.Además de las excelentes respuestas anteriores, me gustaría aclarar por qué no recibió la pregunta sobre si se debe mover los archivos o no.
Si se mueve un archivo a un nuevo nombre, y ese nombre no es un directorio,
mv
se cambie el nombre del archivo con el nuevo nombre.El problema aquí es que estaba utilizando
find
para ejecutarmv
una vez por archivo , no una vez para todos los archivos .Si, en cambio, se había hecho
mv *90.mp3 90
, entoncesmv
habría fallado con el mensaje de error que "el archivo de destino no es un directorio".Otro consejo es utilizar la implementación del tabulador al escribir la ruta de destino. Se le mostrará si el destino es un directorio añadiendo
/
al nombre de destino. También puede utilizarmv -i
que se le pregunte si desea sobrescribir un archivo existente.fuente
mv *90.mp3 90
, mv habría fallado con el mensaje de error de que "el archivo de destino no es un directorio". Ja, sí, ¿por qué tan complicado eh? Uso tu línea y seré feliz. Sin embargo, solo en este caso trivial. :) Porque esta es la forma normal en que hago mis preguntas: las reduciría por simplicidad. Nadie se ha opuestofind
hasta ahora considerando que los archivos de los 90 también podrían estar dispersos en varios subdirectorios que también quiero "atrapar". Si y solo si siempre están en un directorio de origen, sumv
línea es aplicable.mv
comporta, no como una crítica de su elección de herramientas.find
ymv
, por ejemplofind /music -type d -exec mv {}/*90.mp3 targetdir\;
- pero ahora me siento un poco como estoy complicar excesivamente, y el simple uso-i
o-t
es más eficientefind . -type d -exec mv {}/*9?.mp3 target \;
ejemplo funcionó, todavía existiría el riesgo de que elmv
comando se veamv file target
para cada directorio que contenga solo un*9?.mp3
archivo; por lo que todos esos archivos (excepto el último) se perderían.*.mp3
archivos en un árbol de directorios, se podíashopt -s globstar
y ejecute el comando en**/*.mp3
- el**
actuará como unafind
.Como una estrategia alternativa de uso general, me gustaría sugerir convertir este tipo de operación en un script temporal. Prefiero mirar los resultados
find
y convertirlos en unmv
comando a mano, asegurando que entiendo lo que estoy haciendo antes de ejecutar. p.ej.Ahora puedo mirar a través de una lista de nombres de archivo y volver a escribir el contenido del archivo como un comando shell.
ggVGJ
Imv
[esc]
Asomedir/
[esc]
source tmp
en la línea de comando.Es una estrategia conservadora, pero he sido mordido con demasiada frecuencia por comandos mal escritos
-exec
osed
expansiones de shell mal entendidas, y prefiero adoptar un enfoque lento y consistente.En otras palabras: soy demasiado cobarde para usar
-exec
.fuente
:%s/.*/"&"/
paso, porque, en este caso, sabe que cada nombre de archivo contiene al menos un espacio.echo mv
lugar de ejecutarlosmv
y luego eliminarlosecho
si está satisfecho.Otra opción:
es lo mismo que -i, pero no preguntará, fallará.
fuente