web-dev-qa-db-fra.com

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 en cours d'exécution sur un terminal et que je fermerai dès que j'aurai fini de travailler avec ce fichier.

Actuellement, j'utilise ceci:

while read; do ./myfile.py ; done

Et puis je dois aller à ce terminal et appuyez sur Enter, chaque fois que je sauvegarde 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 type de solution que je souhaite maintenant.

Mise à jour: Je veux quelque chose de simple, à jeter si possible. De plus, je veux que quelque chose soit exécuté dans un terminal parce que je veux voir la sortie du programme (je veux voir les messages d'erreur).

À propos des réponses: Merci pour toutes vos réponses! Tous sont très bons et chacun adopte une approche très différente des autres. Comme je n'ai besoin que d'un seul, j'accepte celui que j'ai utilisé (c'était simple, rapide et facile à retenir), même si je sais que ce n'est pas le plus élégant.

418
Denilson Sá Maia

Simple, en utilisant inotifywait (installez le paquet inotify-tools de votre distribution):

while inotifywait -e close_write myfile.py; do ./myfile.py; done

ou

inotifywait -q -m -e close_write myfile.py |
while read -r filename event; do
  ./myfile.py         # or "./$filename"
done

Le premier extrait est plus simple, mais il comporte un inconvénient majeur: les modifications effectuées alors que inotifywait ne fonctionne pas (en particulier lorsque myfile est en cours d'exécution) seront omises. Le deuxième extrait n'a pas ce défaut. Attention toutefois, cela suppose que le nom du fichier ne contient pas d'espaces. Si cela pose un problème, utilisez l'option --format pour modifier le résultat afin de ne pas inclure le nom du fichier:

inotifywait -q -m -e close_write --format %e myfile.py |
while read events; do
  ./myfile.py
done

Dans les deux cas, il existe une limitation: si un programme remplace myfile.py par un fichier différent, plutôt que d'écrire dans la variable myfile existante, inotifywait mourra. Beaucoup d'éditeurs travaillent de cette façon.

Pour surmonter cette limitation, utilisez inotifywait dans le répertoire:

inotifywait -e close_write,moved_to,create -m . |
while read -r directory events filename; do
  if [ "$filename" = "myfile.py" ]; then
    ./myfile.py
  fi
done

Vous pouvez également utiliser un autre outil qui utilise les mêmes fonctionnalités sous-jacentes, tel que incron (vous permet d’enregistrer des événements lorsqu’un fichier est modifié) ou fswatch (un outil qui fonctionne également sur de nombreuses autres variantes Unix, en utilisant chaque option). la variante de l'inotify de Linux).

383
Gilles

entr ( http://entrproject.org/ ) fournit une interface plus conviviale pour inotify (et prend également en charge * BSD et Mac OS X).

Il est très facile de spécifier plusieurs fichiers à regarder (limité uniquement par ulimit -n), simplifie le traitement des fichiers à remplacer et nécessite moins de syntaxe bash:

$ find . -name '*.py' | entr ./myfile.py

Je l'utilise sur l'ensemble de l'arborescence source de mon projet pour exécuter les tests unitaires du code que je suis en train de modifier, ce qui a déjà considérablement dynamisé mon flux de travail.

Les indicateurs tels que -c (effacez l'écran entre les exécutions) et -d (quitte lorsqu'un nouveau fichier est ajouté à un répertoire surveillé) ajoutent encore plus de flexibilité. Vous pouvez par exemple:

$ while sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done

Début 2018, il est toujours en développement actif et peut être trouvé dans Debian & Ubuntu (apt install entr); la construction du dépôt de l'auteur était sans douleur dans tous les cas.

148
Paul Fenney

J'ai écrit un programme Python pour faire exactement ceci appelé quand-changé .

L'utilisation est simple:

when-changed FILE COMMAND...

Ou pour regarder plusieurs fichiers:

when-changed FILE [FILE ...] -c COMMAND

FILE peut être un répertoire. Regardez récursivement avec -r. Utilisez %f pour transmettre le nom de fichier à la commande.

105
joh

Que diriez-vous de ce script? Il utilise la commande stat pour obtenir l'heure d'accès à un fichier et exécute une commande chaque fois qu'il y a une modification de l'heure d'accès (chaque fois qu'un fichier est utilisé).

#!/bin/bash

### Set initial time of file
LTIME=`stat -c %Z /path/to/the/file.txt`

while true    
do
   ATIME=`stat -c %Z /path/to/the/file.txt`

   if [[ "$ATIME" != "$LTIME" ]]
   then    
       echo "RUN COMMAND"
       LTIME=$ATIME
   fi
   sleep 5
done
48
VDR

Solution utilisant Vim:

:au BufWritePost myfile.py :silent !./myfile.py

Mais je ne veux pas de cette solution parce que c’est un peu ennuyeux de taper, c’est un peu difficile de se rappeler quoi taper, exactement, et c’est un peu difficile d’annuler ses effets (il est nécessaire d’exécuter :au! BufWritePost myfile.py). De plus, cette solution bloque Vim jusqu'à l'exécution complète de la commande.

J'ai ajouté cette solution ici juste pour être complet, car cela pourrait aider d'autres personnes.

Pour afficher la sortie du programme (et perturber complètement votre flux d'édition, car la sortie écrira sur votre éditeur pendant quelques secondes, jusqu'à ce que vous appuyiez sur Entrée), supprimez la commande :silent.

30
Denilson Sá Maia

Si vous avez npm installé, nodemon est probablement le moyen le plus simple de commencer, en particulier sous OS X, qui apparemment ne dispose pas d'outils inotify. Il prend en charge l'exécution d'une commande lorsqu'un dossier est modifié.

23
davidtbernal

rerun2 ( sur github ) est un script Bash de 10 lignes de la forme:

#!/usr/bin/env bash

function execute() {
    clear
    echo "$@"
    eval "$@"
}

execute "$@"

inotifywait --quiet --recursive --monitor --event modify --format "%w%f" . \
| while read change; do
    execute "$@"
done

Enregistrez la version de github en tant que "réexécutez" sur votre PATH et appelez-la en utilisant:

rerun COMMAND

Il exécute COMMAND chaque fois qu'il y a un événement de modification du système de fichiers dans votre répertoire actuel (récursif.)

Des choses qu'on pourrait aimer à ce sujet:

  • Il utilise inotify, il est donc plus réactif que polling. Fabuleux pour l'exécution de tests unitaires inférieurs à une milliseconde ou le rendu de fichiers de points graphviz chaque fois que vous cliquez sur "Enregistrer".
  • Parce que c'est si rapide, vous n'avez pas besoin de lui dire d'ignorer les grands sous-répertoires (comme node_modules) uniquement pour des raisons de performances.
  • Il est extrêmement super réactif, car il appelle inotifywait une seule fois, au démarrage, au lieu de l’exécuter, et entraîne le coût onéreux de l’établissement de montres, à chaque itération.
  • C'est juste 12 lignes de Bash
  • Parce que c'est Bash, il interprète les commandes que vous transmettez exactement comme si vous les aviez tapées à l'invite de Bash. (Vraisemblablement, c'est moins cool si vous utilisez un autre Shell.)
  • Il ne perd pas les événements qui se produisent pendant l'exécution de COMMAND, contrairement à la plupart des autres solutions inotify présentées sur cette page.
  • Lors du premier événement, il entre dans une "période morte" de 0,15 seconde, durant laquelle les autres événements sont ignorés, avant que COMMAND ne soit exécuté exactement une fois. Ainsi, la multitude d'événements provoqués par la danse create-write-move que Vi ou Emacs font lors de la sauvegarde d'un tampon ne provoque pas de nombreuses exécutions laborieuses d'une suite de tests potentiellement lente. Tous les événements qui se produisent pendant l'exécution de COMMAND ne sont pas ignorés - ils provoqueront une seconde période d'inactivité et une exécution ultérieure.

Des choses qu'on pourrait ne pas aimer à ce sujet:

  • Il utilise inotify, donc ne fonctionnera pas en dehors de Linuxland.
  • Puisqu'il utilise inotify, il sera difficile d'essayer de regarder les répertoires contenant plus de fichiers que le nombre maximal de surveillances d'utilisateur inotify. Par défaut, cela semble être réglé à environ 5 000 à 8 000 sur les différentes machines que j'utilise, mais il est facile de l'augmenter. Voir https://unix.stackexchange.com/questions/13751/kernel-inotify-watch-limit-reached
  • Il ne parvient pas à exécuter des commandes contenant des alias Bash. Je pourrais jurer que cela fonctionnait. En principe, étant donné qu'il s'agit de Bash et n'exécutant pas COMMAND dans un sous-shell, je m'attendrais à ce que cela fonctionne. J'adorerais entendre Si quelqu'un sait pourquoi. Beaucoup des autres solutions de cette page ne peuvent pas non plus exécuter de telles commandes.
  • Personnellement, j'aimerais pouvoir appuyer sur une touche du terminal dans lequel elle s'exécute pour provoquer manuellement une exécution supplémentaire de COMMAND. Puis-je ajouter ceci d'une manière ou d'une autre, simplement? Une boucle 'en cours de lecture -n1' simultanément exécutée qui appelle également execute?
  • À l'heure actuelle, je l'ai codé pour vider le terminal et imprimer la commande exécutée à chaque itération. Certaines personnes voudront peut-être ajouter des indicateurs de ligne de commande pour désactiver des éléments tels que celui-ci, etc. Mais cela augmenterait considérablement la taille et la complexité.

Ceci est un raffinement de la réponse de @ cychoi.

15
Jonathan Hartley

Pour ceux qui ne peuvent pas installer inotify-tools comme moi, cela devrait être utile:

watch -d -t -g ls -lR

Cette commande se ferme lorsque la sortie change. ls -lR liste tous les fichiers et répertoires avec leur taille et leurs dates. Par conséquent, si un fichier est modifié, il doit quitter la commande, comme le dit l'homme:

-g, --chgexit
          Exit when the output of command changes.

Je sais que personne ne lira cette réponse, mais j'espère que quelqu'un y parviendra.

Exemple de ligne de commande:

~ $ cd /tmp
~ $ watch -d -t -g ls -lR && echo "1,2,3"

Ouvrez un autre terminal:

~ $ echo "testing" > /tmp/test

Maintenant, le premier terminal va sortir 1,2,3

Exemple de script simple:

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

watch -d -t -g ls -lR ${DIR_TO_WATCH} && ${COMMAND}
13
Sebastian

Voici un script simple Shell Bourne Shell qui:

  1. Prend deux arguments: le fichier à surveiller et une commande (avec des arguments, si nécessaire)
  2. Copie le fichier que vous surveillez dans le répertoire/tmp
  3. Vérifie toutes les deux secondes pour voir si le fichier que vous surveillez est plus récent que la copie.
  4. S'il est plus récent, il remplace la copie par l'original plus récent et exécute la commande.
  5. Nettoie tout seul lorsque vous appuyez sur Ctr-C

    #!/bin/sh  
    f=$1  
    shift  
    cmd=$*  
    tmpf="`mktemp /tmp/onchange.XXXXX`"  
    cp "$f" "$tmpf"  
    trap "rm $tmpf; exit 1" 2  
    while : ; do  
        if [ "$f" -nt "$tmpf" ]; then  
            cp "$f" "$tmpf"  
            $cmd  
        fi  
        sleep 2  
    done  
    

Cela fonctionne sur FreeBSD. Le seul problème de portabilité auquel je peux penser est si un autre Unix n’a pas la commande mktemp (1), mais dans ce cas, vous pouvez simplement coder en dur le nom du fichier temporaire.

12
MikeyMike

Regardez incron . Il ressemble à cron, mais utilise des événements inotify au lieu de time.

8
Florian Diesch

Une autre solution avec NodeJs,fsmonitor:

  1. Installer

    Sudo npm install -g fsmonitor
    
  2. À partir de la ligne de commande (exemple, journaux de surveillance et "vente au détail" si un fichier journal est modifié)

    fsmonitor -s -p '+*.log' sh -c "clear; tail -q *.log"
    
6
Atika

Regardez dans Guard, en particulier avec ce plugin:

https://github.com/hawx/guard-Shell

Vous pouvez le configurer pour surveiller n'importe quel nombre de modèles dans le répertoire de votre projet et exécuter des commandes lorsque des modifications sont apportées. Bonne chance, même qu'il existe un plugin disponible pour ce que vous essayez de faire en premier lieu.

6
Wouter Van Vliet

Sous Linux:

man watch

watch -n 2 your_command_to_run

Lance la commande toutes les 2 secondes.

Si l'exécution de votre commande prend plus de 2 secondes, Watch attend que l'opération soit terminée avant de recommencer.

6
Eric Leschinski

si vous avez nodemon installé, alors vous pouvez faire ceci:

nodemon -w <watch directory> -x "<Shell command>" -e ".html"

Dans mon cas, je modifie le code HTML localement et l'envoie à mon serveur distant lorsqu'un fichier est modifié.

nodemon -w <watch directory> -x "scp filename [email protected]:/var/www" -e ".html"
5
Jay

Watchdogest un projet Python, et peut être tout à fait ce que vous cherchez:

Plateformes supportées

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

Je viens d’écrire un wrapper en ligne de commande pour luiwatchdog_exec:

Exemple fonctionne

Sur l’événement fs impliquant des fichiers et des dossiers du répertoire en cours, exécutez la commande echo $src $dst, sauf si l’événement fs est modifié, puis exécutez la commande python $src.

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

En utilisant des arguments courts et en limitant l'exécution à des événements impliquant " main . Py":

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

EDIT: Je viens de trouver que Watchdog a une CLI officielle appelée watchmedo, alors vérifiez-la également.

5
Samuel Marks

Si votre programme génère une sorte de journal/sortie, vous pouvez créer un Makefile avec une règle pour ce journal/sortie qui dépend de votre script et faire quelque chose comme:

while true; do make -s my_target; sleep 1; done

Alternativement, vous pouvez créer une cible factice et faire en sorte que sa règle appelle à la fois votre script et touche la cible factice (tout en dépendant de votre script).

4
ctgPi

Amélioré le réponse de Gilles .

Cette version exécute inotifywait une fois et surveille les événements (par exemple: modify) par la suite. De telle sorte que inotifywait not doit être ré-exécuté à chaque événement rencontré.

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

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
4
cychoi
4
Denilson Sá Maia

Un peu plus sur la programmation, mais vous voulez quelque chose comme inotify . Il existe des implémentations dans de nombreuses langues, telles que jnotify et pyinotify .

Cette bibliothèque vous permet de surveiller des fichiers uniques ou des répertoires entiers et renvoie des événements lorsqu'une action est découverte. Les informations renvoyées incluent le nom du fichier, l'action (créer, modifier, renommer, supprimer) et le chemin du fichier, entre autres informations utiles.

3
John T

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

  • Les modifications de fichiers survenant pendant le do ...; seront manquantes _
  • Lent en mode récursif

J'ai donc créé un script d'assistance 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 en exécutant simplement la commande.

Exemple: inotifyexec "echo test" -r .

3
Wernight

Amélioré La solution de Sebastian avec la commande watch:

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: la commande watch a des bogues connus (voir man): elle réagit aux modifications uniquement dans VISIBLE dans les parties terminales de la sortie -g CMD.

3
alex_1948511

Pour ceux d'entre vous qui recherchent une solution FreeBSD, voici le port:

/usr/ports/sysutils/wait_on
3
akond

Vous pouvez essayer réflexe .

Reflex est un petit outil permettant de surveiller un répertoire et de réexécuter une commande lorsque certains fichiers sont modifiés. C'est idéal pour exécuter automatiquement les tâches de compilation/lint/test et pour recharger votre application lorsque le code change.

# Rerun make whenever a .c file changes
reflex -r '\.c$' make
2
masterxilo

Pour ceux qui utilisent OS X, vous pouvez utiliser un LaunchAgent pour surveiller les modifications apportées à un chemin/fichier et faire quelque chose lorsque cela se produit. FYI - LaunchControl est une bonne application pour créer, modifier ou supprimer des démons/agents.

( exemple pris à partir d'ici )

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN
http://www.Apple.com/DTDs/PropertyList-1.0.dtd>
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>test</string>
    <key>ProgramArguments</key>
    <array>
        <string>say</string>
        <string>yy</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>~/Desktop/</string>
    </array>
</dict>
</plist>
1
Hefewe1zen

J'ai un Gist pour cela et l'utilisation est assez simple

watchfiles <cmd> <paths...>

https://Gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55

1
thiagoh

J'utilise ce script pour le faire. J'utilise inotify en mode moniteur

#!/bin/bash
MONDIR=$(dirname $1)
ARQ=$(basename $1)

inotifywait -mr -e close_write $MONDIR | while read base event file 
do
  if (echo $file |grep -i "$ARQ") ; then
    $1
  fi
done

Enregistrez ceci sous runatwrite.sh

Usage: runatwrite.sh myfile.sh

il lancera myfile.sh à chaque écriture.

1
Fernando Silva

Une réponse unique que j'utilise pour suivre un changement de fichier:

$ while true ; do NX=`stat -c %Z file` ; [[ $BF != $NX ]] && date >> ~/tmp/fchg && BF=$NX || sleep 2 ; done

Vous n'avez pas besoin d'initialiser BF si vous savez que la première date est l'heure de début.

C'est simple et portable. Il existe une autre réponse basée sur la même stratégie en utilisant un script ici. Regardez aussi.


Utilisation: J'utilise ceci pour déboguer et garder un œil sur ~/.kde/share/config/plasma-desktop-appletsrc; que pour une raison inconnue continue à perdre mon SwitchTabsOnHover=false

1
Dr Beco

Utilisation de base

Voici une solution qui ne nécessite pas l’installation de logiciels supplémentaires et qui fonctionne tout de suite.

tail -q --follow=name myfile.txt | head -n 0

Cette commande se ferme dans les conditions suivantes:

  • Une ligne est ajoutée à myfile.txt après l'exécution de la commande.
  • Le myfile.txt est remplacé par un autre après l'exécution de la commande

Vous dites que vous utilisez vim, et vim remplacera le fichier lors de l'enregistrement. J'ai testé cela fonctionne avec vim.

Vous pouvez ignorer le résultat de cette commande, il peut mentionner quelque chose comme:

tail: «myfile.txt» a été remplacé; suite à la fin du nouveau fichier

Utilisation avancée

Vous pouvez combiner cela avec timeout pour renvoyer true ou false. Vous pouvez l'utiliser comme ceci:

délai d'attente 5s bash -c 'queue -q --follow = nom pipe 2>/dev/null | head -n 0 '&& echo a changé || echo timeout

Discussion

tail utilise inotify sous le capot. C'est ainsi que vous obtenez ce comportement asynchrone sophistiqué sans interrogation. Il existe probablement un autre programme unix standard qui utilise inotify que nous pouvons utiliser plus élégamment.

Parfois, ces commandes se terminent immédiatement, mais si vous les exécutez immédiatement une seconde fois, elles fonctionnent comme indiqué. J'ai commis une erreur quelque part, aidez-moi à corriger ceci.

Sur RHEL, je peux utiliser:

délai d'attente 5s sh -c 'gio monitor pipe | head -n 0 '&& echo a changé || echo timeout

Mais je ne suis pas sûr que ce soit portable.

0
William Entriken

find peut faire l'affaire.

while true; do
    find /path/to/watched/file -ctime 1s | xargs do-what-you-will
done

find -ctime 1s imprime le nom du fichier s'il était changé dans le dernier 1s.

0
lvijay

L'outil 'fido' peut être une autre option pour ce besoin. Voir https://www.joedog.org/fido-home/

0
David Ramirez

Pour les personnes qui trouvent ceci en recherchant des modifications dans un fichier particulier, la réponse est beaucoup plus simple (inspiré par la réponse de Gilles ).

Si vous voulez faire quelque chose après un fichier particulier a été écrit, voici comment:

while true; do
  inotifywait -e modify /path/to/file
  # Do something *after* a write occurs, e.g. copy the file
  /bin/cp /path/to/file /new/path
done

Enregistrez ceci sous, par exemple, copy_myfile.sh et placez le fichier .sh dans le dossier /etc/init.d/ pour le lancer au démarrage.

0
LondonRob

Comme quelques-uns l'ont fait, j'ai également écrit un outil de ligne de commande léger pour le faire. Il est entièrement documenté, testé et modulaire.

Watch-Do

Installation

Vous pouvez l'installer (si vous avez Python3 et pip) en utilisant:

pip3 install git+https://github.com/vimist/watch-do

Usage

Utilisez-le tout de suite en exécutant:

watch-do -w my_file -d 'echo %f changed'

Présentation des fonctionnalités

  • Prend en charge le transfert de fichier (utilisez -w '*.py' ou -w '**/*.py')
  • Exécuter plusieurs commandes sur un changement de fichier (spécifiez simplement l'indicateur -d à nouveau)
  • Tient à jour de manière dynamique la liste des fichiers à surveiller si l’utilisation de la méthode de balayage est utilisée (-r pour l’activer)
  • Plusieurs façons de "regarder" un fichier:
    • Heure de modification (par défaut)
    • Hachage de fichier
    • Trivial pour implémenter le vôtre (c'est le ModificationTime watcher)
  • Conception modulaire. Si vous souhaitez que des commandes soient exécutées, lorsqu’un fichier est utilisé, il est simple d’écrire votre propre observateur (mécanisme qui détermine si les analyses doivent être exécutées).
0
vimist

J'ai écrit un programme Python pour faire exactement cela, appelé rerun .

UPDATE: Cette réponse est un script Python qui interroge les modifications, ce qui est utile dans certaines circonstances. Pour un script Bash exclusivement Linux qui utilise inotify, consultez mon autre réponse, recherchez "rerun2" dans cette page.

Installez pour Python2 ou Python3 avec:

pip install --user rerun

et l'utilisation est très simple:

rerun "COMMAND"

La commande est attendue sous la forme d'un argument unique et non d'une séquence d'arguments séparés par des espaces. Citez-le comme indiqué, ce qui réduit les fuites supplémentaires que vous auriez à ajouter. Tapez simplement la commande comme vous l’auriez tapée sur la ligne de commande, mais entre guillemets.

Par défaut, il surveille tous les fichiers dans ou sous le répertoire en cours, en ignorant des éléments tels que les répertoires de contrôle de code source connus, .git, .svn, etc.

Les indicateurs facultatifs incluent «-i NAME», qui ignore les modifications apportées aux fichiers ou aux répertoires nommés. Cela peut être donné plusieurs fois.

S'agissant d'un script Python, il doit exécuter la commande en tant que sous-processus. Nous utilisons une nouvelle instance du shell actuel de l'utilisateur pour interpréter 'COMMAND' et décider du processus à exécuter. Cependant, si votre commande contient des alias de shell et similaires définis dans .bashrc, ils ne seront pas chargés par le sous-shell. Pour résoudre ce problème, vous pouvez attribuer à nouveau un indicateur «-I», afin d'utiliser des sous-shell interactifs (ou «login»). C’est plus lent et plus sujet aux erreurs que de démarrer un shell classique, car il doit générer votre fichier .bashrc.

Je l’utilise avec Python 3, mais la dernière fois que j’ai vérifié, j’exécutais toujours avec Python 2.

L'épée à double tranchant est qu'il utilise polling au lieu d'inotify. En revanche, cela signifie que cela fonctionne sur tous les systèmes d'exploitation. De plus, c'est mieux que certaines autres solutions présentées ici en termes d'exécution de la commande donnée une seule fois pour une série de modifications du système de fichiers, et non une fois par fichier modifié, tout en exécutant la commande une seconde fois si des fichiers sont modifiés à nouveau. pendant que la commande est en cours d'exécution.

Par contre, l'interrogation signifie qu'il y a une latence de 0,0 à 1,0 seconde et qu'il est bien sûr lent à surveiller des annuaires extrêmement volumineux. Cela dit, je n’ai jamais rencontré un projet assez important pour que cela soit visible même si vous utilisez '-i' pour ignorer de grandes choses comme virtualenv et node_modules.

Hmmm. rerun m'est indispensable depuis des années - je l'utilise en fait huit heures par jour pour exécuter des tests, reconstruire des fichiers de points à mesure que je les édite, etc. Mais maintenant, je viens de taper ceci ici, il est clair que je dois passer à un solution qui utilise inotify (je n’utilise plus Windows ni OSX.) et qui est écrite en Bash (elle fonctionne donc avec des alias sans fiddling supplémentaire.)

0
Jonathan Hartley

La description

Ceci surveillera les modifications dans un fichier et exécutera la commande (y compris les arguments supplémentaires) a été donnée en tant que deuxième instruction. Cela effacera également l'écran et imprimera l'heure de la dernière exécution. Remarque: vous pouvez rendre la fonction plus (ou moins) réactive en modifiant le nombre de secondes pendant lesquelles la fonction doit dormir après chaque cycle de boucle while.

Exemple d'utilisation

watch_file my_file.php php my_file.php

Cette ligne va regarder un fichier php my_file.php et exécuter un interprète php chaque fois que cela change.


Définition de fonction

function watch_file (){

### Set initial time of file
LTIME=`stat -c %Z $1`
printf "\033c"
echo -e "watching: $1 ---- $(date '+%Y-%m-%d %H:%M:%S')\n-------------------------------------------\n"
${@:2}

while true
do
   ATIME=`stat -c %Z $1`

   if [[ "$ATIME" != "$LTIME" ]]
   then
    printf "\033c"
    echo -e "watching: $1 ---- $(date '+%Y-%m-%d %H:%M:%S')\n-------------------------------------------\n"
    ${@:2}
    LTIME=$ATIME
   fi
   sleep 1
done
}

Crédit

Ceci est fondamentalement une version plus générale de la réponse de VDR.

0
petermeissner