Esto depende de las herramientas que utilice:veamos algunos casos:
Si ejecuta algo similar a mv /path/to/source/* /path/to/dest/
en un shell, terminará con los 1000 archivos originales moviéndose, los nuevos 300 intactos. Esto proviene del hecho de que el shell expandirá el *
antes de iniciar la operación de movimiento, por lo que cuando el movimiento está en curso, la lista ya está arreglada.
Si usa Nautilus (y otros amigos de GUI), terminará de la misma manera:ejecutará la operación de movimiento en función de los archivos seleccionados; esto no cambia cuando aparecen nuevos archivos.
Si usa su propio programa usando llamadas al sistema a lo largo de la línea de bucle sobre glob
y solo uno mv
hasta glob
permanece vacío, terminará con los 1300 archivos en el nuevo directorio. Esto se debe a que cada nuevo glob
recogerá los nuevos archivos que han aparecido mientras tanto.
Cuando le dice al sistema que mueva todos los archivos de un directorio, enumera todos los archivos y luego comienza a moverlos. Si aparecen nuevos archivos en el directorio, no se agregan a la lista de archivos para mover, por lo que permanecerán en la ubicación original.
Por supuesto, puede programar una forma de mover archivos diferente a mv
que comprobará periódicamente si hay nuevos archivos en el directorio de origen.
El kernel en sí no puede estar "en el medio" de una operación de "mover 1000 archivos". Debe ser mucho más específico sobre qué operación está proponiendo.
Un hilo solo puede mover un archivo a la vez con el rename(*oldpath, const char *newpath)
o renameat
llamadas al sistema (y solo dentro del mismo sistema de archivos). O Linux renameat2
que tiene banderas como RENAME_EXCHANGE
para intercambiar atómicamente dos nombres de rutas, o RENAME_NOREPLACE
a no reemplazar el destino si existe. (por ejemplo, permitir un mv -i
implementación que evita la condición de carrera de stat
y luego rename
, que aún sobrescribiría un archivo creado después de stat
.link
+ unlink
también podría resolver eso, porque link
falla si el nuevo nombre existe.)
Pero cada una de estas llamadas al sistema solo cambia el nombre de una sola entrada de directorio por llamada al sistema . Usando POSIX renameat
con olddirfd
y newdirfd
(abierto con open(O_DIRECTORY)
) le permitiría seguir recorriendo archivos en un directorio incluso si el directorio de origen o de destino en sí mismo había sido renombrado. (El uso de rutas relativas también podría permitir eso con rename()
regulares .)
De todos modos, como dicen las otras respuestas, la mayoría de los programas que usan la llamada al sistema de cambio de nombre obtendrán una lista de nombres de archivo antes de hacer el primer rename
. (Usualmente usando el readdir(3)
Función de biblioteca POSIX como contenedor para llamadas al sistema específicas de la plataforma como Linux getdents
).
Pero si estás hablando de find -exec ... {} \;
para ejecutar un comando por archivo, o el más eficiente -exec {} +
con tantos archivos que no caben en una línea de comando, entonces ciertamente puede tener cambios de nombre mientras sigue escaneando. por ejemplo
find . -name '*.txt' -exec mv -t ../txtfiles {} \; # Intentionally inefficient
Si creaste un nuevo .txt
archivos mientras se ejecutaba, podría ver algunos de ellos en ../txtfiles
. Pero internamente find(1)
habrá usado open(O_DIRECTORY)
y getdents
en .
.
Si una llamada al sistema fuera suficiente para devolver todos las entradas del directorio en .
(que find recorrerá uno a la vez, solo haciendo más llamadas al sistema si es necesario para -type
o recurse, o fork+exec en una coincidencia), entonces la lista es una instantánea de las entradas del directorio en un punto en el tiempo. Más cambios en el directorio no pueden afectar lo que find
lo hace, porque ya tiene una copia del directorio que enumera lo que se repetirá. (Probablemente use internamente readdir(3)
, que devuelve una entrada a la vez, pero dentro de glibc lo sabemos al usar strace find .
que hace un getdents64
llamada al sistema con un tamaño de búfer de count=32768
entradas.)
Pero si el directorio es enorme y/o el kernel no llena find
's, tendrá que hacer una segunda llamada al sistema getdents después de repetir lo que obtuvo la primera vez. Así que tal vez podría ver nuevas entradas después de hacer algunos cambios de nombre.
Pero vea la discusión en los comentarios en otras respuestas:el kernel podría haber tomado una instantánea para nosotros, porque (creo) getdents no puede devolver el mismo nombre de archivo dos veces. Los diferentes sistemas de archivos usan diferentes mecanismos de clasificación/indexación para hacer que el acceso a una entrada en un directorio enorme sea más eficiente que una búsqueda lineal. Por lo tanto, agregar o eliminar un directorio posiblemente tenga otros efectos en el orden de las entradas restantes. Hmm, probablemente sea más probable que los sistemas de archivos mantengan un orden estable y solo actualicen un índice real (como EXT4 dir_index
característica), por lo que la posición de un directorio FD puede ser simplemente una entrada de directorio para reanudar? Realmente no sé cómo el telldir(3)
la interfaz de la biblioteca se asigna a lseek
, o si eso es puramente una cuestión de espacio de usuario para recorrer el búfer obtenido por el espacio de usuario. Pero múltiples getdents
puede ser necesario para obtener todas las entradas de un directorio enorme, por lo que incluso si no se admite la búsqueda, el kernel debe poder registrar una posición actual.
Nota al pie 1:
Para "mover" entre sistemas de archivos, depende del espacio del usuario copiar y desvincular. (por ejemplo, con open
y read+write
, mmap+write
o sendfile(2)
o copy_file_range(2)
, los dos últimos evitan por completo rebotar los datos del archivo a través del espacio del usuario).