Mover archivos con "y * provocó un error

Aug 22 2020

Tengo problemas para mover archivos en un script bash. He estado probando diferentes soluciones que encontré aquí, en el mismo problema, pero no puedo encontrar nada que funcione.

mi último intento fue agregar shopt -s dotglob nullglobpero eso no resolvió nada ..

En esta prueba,

jdir0="/media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)"


mv -v "$jdir0/*" "$jdir0/subs/" &>> $debuglog

.. y obtengo:

mv: cannot stat '/media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/*': No such file or directory

pero, si, las hay!

drwxrwx--- 1 root vboxsf   4096 Aug 22 07:06  ../
-rwxrwx--- 1 root vboxsf      0 Aug 21 17:19 'kallee.(222)..nnn.srt'*
-rwxrwx--- 1 root vboxsf 159363 Aug 21 17:26 'movie.test(2929).ismim.mp4'*
drwxrwx--- 1 root vboxsf      0 Aug 22 07:06  subs/

(la razón por la que los nombres son realmente extraños es que antes de que esta función esté probando para eliminar caracteres no válidos)

actualización: Aparentemente obtuve errores intermitentes, y finalmente, después de días, lo rastreé hasta el problema del servidor (donde se almacenaron los archivos). Aparentemente, estos errores ocurrieron si el servidor no había terminado con el cambio de guardado / nombre, y el script le pedía que hiciera algo nuevo. Por ejemplo, cambiar el nombre del archivo A a B, y luego pedirle que cambie el nombre de B a C ANTES de que el servidor haya ejecutado la primera solicitud, lo que resultó en que el servidor dijo: B no existe, lo que por supuesto provocó un código de error.

Respuestas

7 StéphaneChazelas Aug 22 2020 at 05:44

*es un operador global del shell. Debe dejarse sin comillas para que se reconozca como tal. Cuando se cita, /media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/*se pasa literalmente mve mvintenta mover ese archivo llamado *, y no existe tal archivo.

Así que tú necesitas:

mv -v -- "$jdir0"/* "$jdir0/subs/" >> "$debuglog" 2>&1

Para que el shell se expanda "$jdir0"/*en la lista de archivos coincidentes antes de llamar mv.

Usted no quiere nullglobaquí como eso significaría que, en ausencia de archivos que coinciden con que "$jdir0"/*el patrón, mvse invoca con sólo -v, --y media/sf_Mediaserver3/test22/abbamax.(6th.copy)..kansas.(1999)/subs/causando un error de sintaxis confundir por mv.

failglobabortar el comando cuando los elementos globales no coinciden puede ser una mejor opción en ese caso, aunque tenga bashen cuenta que, en ese caso, se cancela de manera inconsistente dependiendo del contexto en el que se invoca el comando, lo que hace que esa opción sea difícil de usar en scripts.

dotglob es permitir que los globos coincidan con archivos ocultos.

Ahora, tenga en cuenta que los globs coinciden con los archivos independientemente de su tipo¹, por lo que los *anteriores también coincidirán subs. Si subses un enlace simbólico a un directorio, mvfelizmente moverá ese subsenlace simbólico a ese directorio, haciendo que todos los movimientos posteriores fallen ya que el subsdirectorio de destino ya no está. Si subses un subdirectorio simple, mvprobablemente se quejará de que no puede mover un directorio a sí mismo.

Entonces, es posible que desee escribirlo en su lugar:

shopt -s extglob
mv -v -- "$jdir0"/!(subs) "$jdir0/subs/" >> "$debuglog" 2>&1

¿Dónde !(pattern)está el operador glob extendido ksh que coincide con cualquier nombre de archivo que no coincide pattern, por lo que aquí se mueve cualquier archivo pero subs.

También tenga en cuenta que en el bashshell, las expansiones de parámetros también deben citarse cuando están en los objetivos de las redirecciones, incluso en instancias de shell no interactivas (excepto cuando bash está en modo POSIX).


¹ a menos que use zsh en lugar de bash y sus calificadores glob, como *(.)para mover solo archivos normales