Question Concernant la commande de déplacement Unix


Je dois écrire un script de shell Unix tran.sh qui déplace les fichiers d'entrée csv du dossier / exp / files vers le répertoire / exp / ready.

Les fichiers d'entrée csv sont écrits dans /exp/files dossier par un serveur FTP dont le comportement ne peut pas changer trivialement. Dans tran.sh script shell Je dois m'assurer, avant de déplacer ce fichier d'entrée csv du répertoire / exp / files, qu'aucun autre processus n'écrit dans le fichier.

Comment puis-je le faire.


4
2018-02-22 04:19


origine


BTW - sachant qu'il s'agit d'un serveur FTP (par opposition à un processus arbitraire) change vraiment l'ensemble des réponses appropriées; J'ai certainement eu raison de mettre à jour le mien. S'il vous plaît fournir plus d'informations dans votre question la prochaine fois.


Réponses:


Il n'y a pas de moyen portable de le faire. Tu peux essayer fuser, lsof, inotify, FAMet d'autres si.


3
2018-02-22 04:21



belle réponse, coupe droit au but. Je pense que vous pouvez ajouter glib et gamin aussi - Matt Joiner


Essayez d'utiliser fuser [FILE]. Il retournera non nul si le fichier n'est pas utilisé.

Voici un exemple de code qui attendra qu'un fichier soit prêt à être déplacé:

#!/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

3
2018-02-22 04:22



Pas mal, mais il y a toujours une condition de course. - dmckee
Merci beaucoup. trois processus d'application distants transfèrent le fichier d'entrée vers ce répertoire. Donc, je serai capable de savoir avec cette commande de fusion s'ils écrivent dans le fichier.
@dmckee - Vrai à propos de la condition de concurrence, mais j'ai supposé que le processus qui écrit ne contenait que le descripteur de fichier ouvert suffisamment longtemps pour y écrire, puis le ferme, pour ne jamais l'ouvrir à nouveau. - amphetamachine
Merci beaucoup. Je compte vérifier si la dernière ligne du fichier csv est reçue et valider le fichier


vous pouvez utiliser lsof

r=$(lsof /exp/files )
if [ ! -z "$r" ] ;then
  mv /exp/files/*csv /exp/ready
fi

3
2018-02-22 04:31



Merci beaucoup. trois processus d'application distants transfèrent le fichier d'entrée vers ce répertoire. Je pourrai donc savoir avec cette commande lsof s’ils écrivent dans le fichier.
Mais avec trois processus (en supposant qu'ils soient indépendants) écrivant dans les fichiers du répertoire, cela ne bougera pas à moins que les trois soient terminés. Il est plus modulaire d'utiliser une unité de fusion et de tester chaque fichier. - amphetamachine
Merci beaucoup. Je prévois de vérifier si la dernière ligne du fichier csv est reçue et de valider le fichier.


La bonne façon de faire est de faire en sorte que le processus écrivant les fichiers et les renommer ou les déplacer de sa propre initiative une fois terminé avec l'écriture. Toute autre chose est sujette à des conditions de course et / ou à des problèmes de permission.

Quelques exemples particuliers de cas problématiques:

  • Si le processus de déplacement des fichiers est différent de lsof / fuser / etc, les informations ne sont pas garanties complètes
  • Si le processus d'écriture est un script shell, il peut générer un sous-processus qui ouvre le fichier, le ferme, crée un autre sous-processus, etc. Dans ce scénario, lsof, fuser et outils similaires peuvent légitimement afficher le fichier comme non accessible même si d'autres sous-processus seront lancés pour y écrire plus tard.

D'autres conditions de course plus subtiles peuvent également exister - et indépendamment, lsof, fuser et autres ne sont pas des outils POSIX et ne sont pas disponibles partout.

Exiger du protocole que les processus qui écrivent les fichiers les déplacent vers leur emplacement final une fois terminés eux-mêmes; c'est la seule approche sûre et portable.

EDIT: Il a été précisé que les fichiers ne sont pas écrits par un processus arbitraire (qui peut les fermer et les rouvrir) mais par un serveur FTP. Dans ce cas, incron peut être utilisé pour exécuter un script arbitraire chaque fois qu'un fichier a été fermé dans ce répertoire.


2
2018-02-22 04:43



Merci beaucoup pour l'info Le problème est que trois processus d'application distants transfèrent le fichier vers ce répertoire. Donc, je ne devrais pas déplacer le fichier quand ils l'écrivent dans le répertoire / exp / files
@arav - vous pouvez contourner cela (c'est-à-dire je contourner ce problème) avec un serveur sftp personnalisé. (Le mien est écrit en Python en utilisant la bibliothèque Paramiko; il y a aussi un ftpdlib pour écrire des serveurs FTP standard en Python, bien que les raisons pour éviter le FTP soient nombreuses).
@arav - ... cela dit, cela me semble être une autre solution sans conditions de course, car vous utiliseriez inotifywatch ou incron pour exécuter un script de votre choix chaque fois qu'une mise à jour est terminée.


Je ne pense pas que vous puissiez le faire sans modifier les processus qui créent ces fichiers. Chaque fois que nous avons une tâche comme celle-là dans nos systèmes, nous nous assurons que le processus qui crée un fichier le rende exécutable à la toute fin. Ainsi, les processus qui déplaceront ou post-traiteront d'une autre manière de tels fichiers peuvent vérifier le bit exécutable pour s'assurer que le processus d'origine a fini de travailler avec un fichier.


0
2018-02-22 04:52



Le problème est que trois processus d’application distants transfèrent le fichier vers ce répertoire. Je peux donc vérifier que les trois processus d'application distants sont terminés.