¿Cómo copiar todos los archivos en una carpeta, excepto los archivos que se están escribiendo?

12

Descargo varios archivos a una carpeta a downloadingtravés de HTTPie . Un script bash tiene como objetivo procesar los archivos descargados, y traté de copiar los archivos descargados a otra carpeta como

find /folder/downloading -type f -exec mv '{}' /folder/downloaded \;

pero esto también copia los archivos, que aún no se han terminado. Intenté limitar la transferencia a archivos más antiguos agregando -mmin +5al comando. ¿Cuál es el comando eficiente para dejar que los archivos se escriban y transferir solo los archivos descargados?

Googlebot
fuente
Si copia al mismo sistema de archivos, y configura el descargador para que no cambie el nombre (descargue para %.partluego cambiar el nombre a%). Entonces, si el descargador se comporta bien (no hace nada más extraño), entonces debería poder cambiar el nombre de los mvarchivos ( ).
ctrl-alt-delor
1
¿Qué tipo de procesamiento estás tratando de hacer? Lo más probable es que haya una opción mucho más simple disponible, como usar una tubería.
cabeza de jardín

Respuestas:

11

No es muy eficiente, pero podrías hacer:

find /folder/downloading -type f -exec sh -c '
  for file do
    lsof -F a "$file" | grep -q w || mv "$file" /folder/downloaded
  done' sh {} +

Es decir comprueban que el archivo no está en la lista con un writo amodo l acceso en el li st de opluma files antes mo ving.

La psmiscimplementación de lo fuserque normalmente se encuentra en los sistemas operativos basados ​​en Linux tiene una -wfunción (para verificar si hay archivos abiertos para escribir), pero desafortunadamente solo funciona -kpara eliminar los procesos correspondientes. Sin embargo, parece que todavía puede usarlo usando la pseudo-señal 0 que no hace nada:

find /folder/downloading -type f -exec sh -c '
  for file do
    fuser -s -w -k -0 "$file"  || mv "$file" /folder/downloaded
  done' sh {} +

Elimine el -s(o incluso reemplácelo con -v) si desea ver qué proceso (s) está (n) impidiendo el movimiento.

Tenga en cuenta que si no está ejecutando esos comandos como superusuario, solo obtendrá información sobre sus procesos. Si los procesos de descarga de los archivos se ejecutan como un usuario diferente, permanecerán sin ser detectados.

También tenga en cuenta que, a menos que mueva los archivos a un sistema de archivos diferente, mover los archivos no impedirá que el proceso que se está escribiendo actualmente en el archivo termine de escribir en él.

Sin embargo, dependiendo de lo que han sido diseñados para hacer después, podrían confundirse si después de terminar la escritura, el archivo ya no está allí (por ejemplo, si quieren cambiar algunos atributos del archivo después de descargarlo y también lo hacen no a través del descriptor de archivo (como chmod()vs fchmod(), o utimes()que no se puede hacer a través de un descriptor de archivo)).

Stéphane Chazelas
fuente
Pregunta de Shell: creo que entiendo su código con una excepción. El -execse ejecuta shcon un comando ( -c '...') y {} +le dice que ponga más de un resultado en ese comando a la vez. Lo que no entiendo es por qué hay otro shdespués del comando. ¿Qué me estoy perdiendo?
Joe
2
@ Joe, eso es lo que entra en el guión en línea $0. Es decir, le da un nombre a ese script en línea. Ese nombre puede usarse en mensajes de error como, <name>: fuser: command not foundpor ejemplo, por shlo que generalmente es una buena opción en este caso para dejar en claro qué informa ese mensaje de error (eso también sería lo que sería si no presentamos ningún argumento después del guión en línea).
Stéphane Chazelas