627 votes

Comment exécuter une commande à chaque fois qu'un fichier est modifié ?

Je veux un moyen simple et rapide d'exécuter une commande à chaque fois qu'un fichier est modifié. Je veux quelque chose de très simple, quelque chose que je laisserai tourner sur un terminal et que je fermerai dès que j'aurai fini de travailler sur ce fichier.

Actuellement, j'utilise ceci :

while read; do ./myfile.py ; done

Et ensuite je dois aller dans ce terminal et appuyer sur Enter chaque fois que j'enregistre ce fichier sur mon éditeur. Ce que je veux, c'est quelque chose comme ça :

while sleep_until_file_has_changed myfile.py ; do ./myfile.py ; done

Ou toute autre solution aussi simple que cela.

BTW : J'utilise Vim, et je sais que je peux ajouter une autocommande pour exécuter quelque chose sur BufWrite, mais ce n'est pas le genre de solution que je veux maintenant.

Mise à jour : Je veux quelque chose de simple, jetable si possible. De plus, je veux quelque chose qui s'exécute dans un terminal car je veux voir la sortie du programme (je veux voir les messages d'erreur).

A propos des réponses : Merci pour toutes vos réponses ! Elles sont toutes très bonnes, et chacune adopte une approche très différente des autres. Comme je ne dois en accepter qu'une seule, j'accepte celle que j'ai effectivement utilisée (elle était simple, rapide et facile à mémoriser), même si je sais qu'elle n'est pas la plus élégante.

0 votes

Possibilité de duplication de site croisé de : stackoverflow.com/questions/2972765/ ( bien qu'ici c'est le sujet =) )

0 votes

J'ai déjà référencé un duplicate cross site et il a été refusé :S ;)

4 votes

La solution de Jonathan Hartley s'appuie sur d'autres solutions proposées ici et corrige les gros problèmes des réponses les plus votées : absence de certaines modifications et inefficacité. Veuillez changer la réponse acceptée par la sienne, qui est également maintenue sur github à l'adresse suivante github.com/tartley/rerun2 (ou à une autre solution sans ces défauts)

7voto

Samuel Marks Points 171

Chien de garde est un projet Python, et peut être ce que vous recherchez :

Plateformes prises en charge

  • Linux 2.6 (inotify)
  • Mac OS X (FSEvents, kqueue)
  • FreeBSD/BSD (kqueue)
  • Windows (ReadDirectoryChangesW avec ports d'achèvement d'E/S ; threads de travail ReadDirectoryChangesW)
  • Indépendant du système d'exploitation (interrogation du disque pour obtenir des instantanés de répertoire et comparaison périodique ; lent et non recommandé).

J'ai juste écrit une enveloppe de ligne de commande pour cela watchdog_exec :

Exemples d'exécution

Sur l'événement fs impliquant des fichiers et des dossiers dans le répertoire actuel, exécutez echo $src $dst sauf si l'événement fs est modifié, alors exécutez la commande python $src commandement.

python -m watchdog_exec . --execute echo --modified python

L'utilisation d'arguments courts, et la restriction de l'exécution uniquement lorsque les événements impliquent " principal .py" :

python -m watchdog_exec . -e echo -a echo -s __main__.py

EDIT : Je viens de découvrir que Watchdog a un CLI officiel appelé watchmedo alors vérifiez cela aussi.

6voto

Wernight Points 611

J'aime la simplicité de while inotifywait ...; do ...; done Cependant, il y a deux problèmes :

  • Les changements de fichiers qui se produisent pendant le do ...; sera seront manqués
  • Lent en cas d'utilisation en mode récursif

C'est pourquoi j'ai créé une aide script qui utilise inotifywait sans ces limitations : inotifyexec

Je vous suggère de mettre ce script dans votre chemin, comme dans ~/bin/ . L'utilisation est décrite par la simple exécution de la commande.

Exemple : inotifyexec "echo test" -r .

0 votes

Mise à jour du script pour supporter la correspondance de motifs regex.

0 votes

Les deux problèmes sont résolus en utilisant inotifywait en mode "--monitor". Voir la réponse de cychoi.

6voto

JohnMilton Points 133

Amélioré La réponse de Gilles .

Cette version fonctionne inotifywait une fois et surveille les événements (.e.g. : modify ) par la suite. Telle que inotifywait n'a pas doivent être ré-exécutés à chaque événement rencontré.

C'est rapide ! <em>(même lors de la surveillance récursive d'un grand répertoire)</em>

inotifywait --quiet --monitor --event modify FILE | while read; do
    # trim the trailing space from inotifywait output
    REPLY=${REPLY% }
    filename=${REPLY%% *}
    # do whatever you want with the $filename
done

0 votes

C'est la meilleure réponse de la page pour les utilisateurs de Linux uniquement. Remplacez le truc à l'intérieur de la boucle par 'execute $@', et l'utilisateur pourrait appeler ce script en passant sa propre commande à exécuter. Cela fonctionne même avec les commandes qui contiennent des alias script si vous le sourcez, en utilisant quelque chose comme ". scriptname COMMAND". Ceci trouvera toujours scriptname sur le PATH.

0 votes

Je pense que vous voulez dire 'pendant la lecture de REPLY' ?

1 votes

Merci pour la clarification. Non merci pour la mise en phase ! J'aurais supprimé ces commentaires, mais bien sûr, je ne le ferai pas maintenant.

5voto

Denilson Sá Maia Points 11713

2 votes

Il s'agit d'un Bash script de 200 lignes avec de nombreuses fonctionnalités qui interroge stat sur les noms de fichiers donnés, exécute md5sum sur la sortie, et ré-exécute la commande donnée si cette valeur change. Parce que c'est Bash, je soupçonne qu'il fait un bon travail pour exécuter la commande donnée exactement comme si vous l'aviez tapée à une invite Bash. (En revanche, la plupart des solutions ici écrites dans d'autres langages échoueront à exécuter des commandes qui, par exemple, contiennent des alias Shell tels que ll )

5voto

alex_1948511 Points 159

Amélioration de La solution de Sébastien con watch commandement :

watch_cmd.sh :

#!/bin/bash
WATCH_COMMAND=${1}
COMMAND=${2}

while true; do
  watch -d -g "${WATCH_COMMAND}"
  ${COMMAND}
  sleep 1     # to allow break script by Ctrl+c
done

Exemple d'appel :

watch_cmd.sh "ls -lR /etc/nginx | grep .conf$" "sudo service nginx reload"

Cela fonctionne mais soyez prudent : watch a des bogues connus (voir man) : elle réagit aux changements uniquement dans VISIBLE dans les parties terminales de -g CMD sortie.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X