Con respecto al comando de movimiento de Unix

4

Necesito escribir una secuencia de comandos de shell de Unix que mueva los archivos de entrada csv de la carpeta / exp / files al directorio / exp / ready.

Los archivos de entrada csv se escriben en /exp/files carpeta por un servidor FTP cuyo comportamiento no puedo cambiar trivialmente. En tran.sh shell script debo asegurarme de que antes de mover ese archivo de entrada csv desde el directorio / exp / files ya no haya ningún otro proceso escrito en el archivo.

Cómo puedo hacerlo.

user38993
fuente
Por cierto, saber que es un servidor FTP (a diferencia de un proceso arbitrario) realmente cambia el conjunto de respuestas apropiadas; Ciertamente he tenido motivos para actualizar el mío. Por favor, proporcione más información en su pregunta la próxima vez.

Respuestas:

3

No hay una forma portátil de hacerlo. Puedes probar fuser, lsof, inotify, FAM, y otros sin embargo.

Ignacio Vazquez-Abrams
fuente
Buena respuesta, cortes directos al punto. Creo que podrías agregar glib y gamin también
Matt Joiner
3

Intenta usar fuser [FILE]. Se devolverá distinto de cero si el archivo no está en uso.

Aquí hay un código de ejemplo que esperará a que un archivo esté listo para moverse:

#!/bin/sh

FROMDIR='/exp/files'
DESTDIR='/exp/ready'

function move_file_if_ready () {
    if [ -f "$1" ]; then
        while fuser "$1" 2>/dev/null 1>&2 ; do
            sleep 1
        done

        mv "$1" "$DESTDIR"
    fi
}

for "$fn" in "$FROMDIR"/*.csv; do
    move_file_if_ready "$fn"
done
amphetamachine
fuente
1
No está mal, pero todavía tiene una condición de carrera.
dmckee
Muchas gracias. tres procesos de aplicación remota están transfiriendo el archivo de entrada a este directorio. Así que podré saber con este comando del fusor si están escribiendo en el archivo.
@dmckee - Verdad acerca de la condición de carrera, pero asumí que el proceso de escritura solo mantiene el manejador del archivo lo suficientemente abierto para escribirlo, luego lo cierra y nunca lo abre de nuevo.
amphetamachine
Muchas gracias. Estoy planeando verificar si se recibe la última línea dentro del archivo csv y validar el archivo
3

puedes usar lsof

r=$(lsof /exp/files )
if [ ! -z "$r" ] ;then
  mv /exp/files/*csv /exp/ready
fi
user31894
fuente
Muchas gracias. tres procesos de aplicación remota están transfiriendo el archivo de entrada a este directorio. Así que podré saber con este comando lsof si están escribiendo en el archivo.
Pero con tres procesos (asumiendo que son independientes) al escribir en los archivos del directorio, esto no se moverá a menos que los tres estén terminados. Es más modular para usar el fusor y realizar pruebas por archivo.
amphetamachine
Muchas gracias. Estoy planeando verificar si la última línea dentro del archivo csv se recibe y validar el archivo.
2

La forma correcta de hacer esto es hacer que el proceso de escritura de los archivos y renombrarlos o moverlos por su propia voluntad se realice con la escritura. Cualquier otra cosa es propensa a condiciones de carrera y / o problemas de permisos.

Algunos ejemplos particulares de casos de problemas:

  • Si el proceso de mover los archivos se ejecuta como un usuario diferente al de lsof / fuser / etc, la información no se garantiza completa
  • Si el proceso de escritura es un script de shell, puede generar un subproceso que abre el archivo, deja que se cierre, genera otro subproceso, etc. En este escenario lsof, el fusor y herramientas similares podrían mostrar legítimamente que no se pudo acceder al archivo incluso si se iniciará un nuevo subproceso para escribir en él más tarde.

También pueden existir otras condiciones de carrera más sutiles, e independientemente de esto, lsof, fuser y demás no son herramientas POSIX y no están disponibles en todas partes.

Requerir del protocolo que los procesos que escriben los archivos los muevan a la ubicación final al completarse; Es el único enfoque seguro y portátil.

EDITAR: Se ha aclarado que los archivos se escriben no mediante un proceso arbitrario (que puede cerrarlos y volver a abrirlos), sino mediante un servidor FTP. En este caso, incron se puede usar para ejecutar un script arbitrario siempre que un archivo se haya cerrado en este directorio.

Charles Duffy
fuente
Muchas gracias por la información El problema es que tres procesos de aplicación remota están transfiriendo el archivo a este directorio. Así que no debería mover el archivo cuando lo están escribiendo en este directorio / exp / files
@arav - puedes solucionar esto (es decir, yo evitar esto) con un servidor sftp personalizado. (El mío está escrito en Python usando la biblioteca Paramiko; también hay un ftpdlib para escribir servidores FTP estándar en Python, aunque existen muchas razones para evitar FTP).
@arav - ... dicho esto, me parece que otra solución sin condiciones de carrera que funcionaría para usted sería usar inotifywatch o incron para ejecutar un script de su elección cada vez que se complete una actualización.
0

No creo que puedas hacer esto sin modificar los procesos que crean estos archivos. Siempre que tengamos tareas como esta en nuestros sistemas, nos aseguramos de que el proceso que crea el archivo lo haga ejecutable al final. Por lo tanto, el proceso se moverá o postprocesará de alguna otra manera en que dichos archivos puedan verificar el bit ejecutable para asegurarse de que el proceso de origen haya terminado de trabajar con un archivo.

sha
fuente
El problema es que tres procesos de aplicación remota están transfiriendo el archivo a este directorio. Así que puedo comprobar que los tres procesos remotos de la aplicación están completos.