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 sur ce terminal et appuyer 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, jetable 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.
Réponses:
Simple, en utilisant inotifywait (installez le
inotify-tools
paquet de votre distribution ):ou
Le premier extrait est plus simple, mais il comporte un inconvénient majeur: il manquera les modifications effectuées tant qu'il
inotifywait
n'est pas en cours d'exécution (en particulier lorsqu'ilmyfile
est en cours d'exécution). 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'--format
option pour modifier la sortie afin de ne pas inclure le nom du fichier:Quoi qu'il en soit, il existe une limite: si un programme est remplacé
myfile.py
par un fichier différent, plutôt que d'écrire dans le fichier existantmyfile
, ilinotifywait
va disparaître. Beaucoup d'éditeurs travaillent de cette façon.Pour surmonter cette limitation, utilisez
inotifywait
sur le répertoire:Vous pouvez également utiliser un autre outil qui utilise les mêmes fonctionnalités sous-jacentes, telles 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 d'Unix, en utilisant l'analogue inotify de Linux de chaque variante).
la source
sleep_until_modified.sh
script simple à utiliser , disponible à l' adressewhile sleep_until_modified.sh derivation.tex ; do latexmk -pdf derivation.tex ; done
est fantastique. Je vous remercie.inotifywait -e delete_self
semble bien fonctionner pour moi.while inotifywait -e close_write myfile.py; do ./myfile.py; done
quitte toujours sans exécuter la commande (bash et zsh). Pour que cela fonctionne, je devais ajouter|| true
, par exemple:while inotifywait -e close_write myfile.py || true; do ./myfile.py; done
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: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
(effacer l'écran entre les exécutions) et-d
(quitter lorsqu'un nouveau fichier est ajouté à un répertoire surveillé) ajoutent encore plus de flexibilité. Vous pouvez par exemple: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.la source
-d
drapeau; c'est un peu plus long, mais vous pouvez fairewhile sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done
pour traiter de nouveaux fichiers.brew install entr
fonctionnera comme prévuJ'ai écrit un programme Python pour faire exactement ce qu'on appelle quand-changé .
L'utilisation est simple:
Ou pour regarder plusieurs fichiers:
FILE
peut être un répertoire. Regarder récursivement avec-r
. Utilisez%f
pour passer le nom de fichier à la commande.la source
when-changed FILE 'clear; COMMAND'
.when-changed
est maintenant multi-plateforme! Découvrez la dernière version 0.3.0 :)Que diriez-vous de ce script? Il utilise la
stat
commande pour obtenir le temps d'accès d'un fichier et exécute une commande chaque fois que le temps d'accès est modifié (chaque fois qu'un fichier est utilisé).la source
stat
le temps modifié ne serait pas une meilleure réponse "à chaque changement de fichier"?vmstat -d
en surveillant l'accès au disque. Il semble que linux fasse un travail fantastique pour mettre ce genre de choses en cache: DSolution utilisant Vim:
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 (nécessité de fonctionner
: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
:silent
commande.la source
entr
(voir ci-dessous) - il suffit de faire en sorte que vim touche un fichier factice surveillé par entr, et laissez-le faire le reste en arrière-plan ... outmux send-keys
si vous vous trouvez dans un tel environnement :).vimrc
fichierSi vous vous êtes
npm
installé,nodemon
c’est probablement le moyen le plus simple de commencer, en particulier sous OS X, qui ne dispose apparemment pas d’outils inotify. Il prend en charge l'exécution d'une commande lorsqu'un dossier est modifié.la source
nodemon -x "bundle exec rspec" spec/models/model_spec.rb -w app/models -w spec/models
WatchPaths
clé, comme indiqué dans mon lien.Pour ceux qui ne peuvent pas installer
inotify-tools
comme moi, cela devrait être utile:watch -d -t -g ls -lR
Cette commande se fermera quand la sortie changera,
ls -lR
listera tous les fichiers et répertoires avec leur taille et leurs dates, donc si un fichier est modifié, il devrait quitter la commande, comme le dit l'homme:Je sais que personne ne lira cette réponse, mais j'espère que quelqu'un y parviendra.
Exemple de ligne de commande:
Ouvrez un autre terminal:
Maintenant, le premier terminal va sortir
1,2,3
Exemple de script simple:
la source
watch -d -t -g "ls -lR tmp | sha1sum"
watch from procps-ng 3.3.10
) accepte des secondes flottantes pour son intervalle; ellewatch -n0.2 ...
sera donc interrogée tous les cinq secondes. Bon pour les tests unitaires sains inférieurs à la milliseconde.rerun2
( sur github ) est un script Bash de 10 lignes de la forme:Enregistrez la version de github en tant que "réexécutez" sur votre PATH et appelez-la en utilisant:
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:
Des choses qu'on pourrait ne pas aimer à ce sujet:
Ceci est un raffinement de la réponse de @ cychoi.
la source
"$@"
au lieu de$@
, afin de travailler correctement avec des arguments contenant des espaces. Mais en même temps, vous utilisezeval
, ce qui oblige l’utilisateur de la réexécution à redoubler de prudence lorsqu’il cite.rerun 'command'
. Est -ce que vous venez de dire que si je « $ @ », l'utilisateur pourrait invoquer commererun command
cela ne semble pas aussi utile pour moi (sans les guillemets?): Je ne veux pas généralement Bash faire tout traitement de commande avant de le transmettre à relancer. Par exemple, si la commande contient "echo $ myvar", je souhaiterai voir les nouvelles valeurs de myvar à chaque itération.rerun foo "Some File"
pourrait se briser. Mais puisque vous utilisezeval
, il peut être réécrit commererun 'foo "Some File"
. Notez que parfois l’extension de chemin peut introduire des espaces:rerun touch *.foo
sera probablement brisée et que l’utilisation de larerun 'touch *.foo'
sémantique sera légèrement différente (l’extension de chemin ne se produit qu’une ou plusieurs fois).rerun ls "some file"
pauses à cause des espaces.rerun touch *.foo*
fonctionne normalement, mais échoue si les noms de fichiers correspondant à * .foo contiennent des espaces. Merci de m'aider à comprendre larerun 'touch *.foo'
différence de sémantique, mais je soupçonne que la version avec guillemets simples est la sémantique que je veux: je veux que chaque itération de la réexécution agisse comme si je tapais la commande à nouveau - par conséquent, je veux*.foo
être développé à chaque itération. . Je vais essayer vos suggestions pour examiner leurs effets ...Voici un script shell shell simple qui:
Nettoie après lui-même lorsque vous appuyez sur Ctr-C
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.
la source
$cmd
, mais heureusement, cela est facilement corrigible: abandonner lacmd
variable et exécuter"$@"
. Votre script ne convient pas à la surveillance d'un fichier volumineux, mais cela pourrait être corrigé en le remplaçantcp
partouch -r
(vous avez seulement besoin de la date, pas du contenu). En ce qui concerne la portabilité, le-nt
test nécessite bash, ksh ou zsh.Regardez incron . Il ressemble à cron, mais utilise des événements inotify au lieu de time.
la source
Une autre solution avec NodeJs, fsmonitor :
Installer
À partir de la ligne de commande (exemple, journaux de surveillance et "détail" si un fichier journal est modifié)
la source
tail -F -q *.log
je pense que l'exemple pourrait être résolu .tail -f
n'est-ce pasclear
le terminal?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 s'il existe un plugin disponible pour ce que vous essayez de faire en premier lieu.
la source
Si vous avez installé nodemon , alors vous pouvez faire ceci:
Dans mon cas, je modifie le code HTML localement et l'envoie à mon serveur distant lorsqu'un fichier est modifié.
la source
Sous Linux:
Lance la commande toutes les 2 secondes.
Si votre commande prend plus de 2 secondes à exécuter, la surveillance attendra que l'opération soit terminée avant de recommencer.
la source
Watchdog est un projet Python, et peut être exactement ce que vous cherchez:
Je viens d'écrire un wrapper en ligne de commande pour cela
watchdog_exec
:Exemple fonctionne
Sur l’événement fs impliquant des fichiers et des dossiers du répertoire en cours, exécutez la
echo $src $dst
commande, à moins que l’événement fs ne soit modifié, puis exécutez lapython $src
commande.En utilisant des arguments courts et en limitant l'exécution à des événements impliquant " main .py":
EDIT: Je viens de trouver que Watchdog a un CLI officiel appelé
watchmedo
, alors vérifiez-le également.la source
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:
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).
la source
while sleep 1 ; do something ; done
est légèrement meilleur quewhile true ; do something ; sleep 1 ; done
. Au moins, il s’arrête facilement en appuyant sur Ctrl + C.swarminglogic a écrit un script appelé watchfile.sh , également disponible en tant que GitHub Gist .
la source
stat
les noms de fichiers donnés, s'exécutemd5sum
sur la sortie et réexécute la commande donnée si cette valeur est modifiée. Parce que c'est Bash, je suppose que cela exécute bien la commande donnée exactement comme si vous l'aviez tapée à l'invite de Bash. (En revanche, la plupart des solutions écrites dans d'autres langues ne réussiront pas à exécuter des commandes contenant, par exemple, des alias de shell tels quell
)Amélioré sur la réponse de Gilles .
Cette version est exécutée
inotifywait
une fois et surveille les événements (.eg:)modify
par la suite. Celainotifywait
n'a pas besoin d'ê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)
la source
Un peu plus sur le côté de 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.
la source
Pour ceux d'entre vous qui recherchent une solution FreeBSD, voici le port:
la source
J'aime la simplicité de
while inotifywait ...; do ...; done
cependant il a deux problèmes:do ...;
seront manquéesJ'ai donc créé un script d'assistance qui utilise inotifywait sans ces limitations: inotifyexec
Je vous suggère de mettre ce script sur votre chemin, comme dans
~/bin/
. L'utilisation est décrite en exécutant simplement la commande.Exemple:
inotifyexec "echo test" -r .
la source
Solution améliorée de Sebastian avec la
watch
commande:watch_cmd.sh
:Exemple d'appel:
Cela fonctionne mais soyez prudent: la
watch
commande a des bugs connus (voir man): elle réagit aux changements uniquement dans VISIBLE dans les parties terminales de la-g CMD
sortie.la source
Vous pouvez essayer le réflexe .
Reflex est un petit outil pour regarder un répertoire et réexécuter une commande lorsque certains fichiers changent. C'est idéal pour exécuter automatiquement les tâches de compilation / lint / test et pour recharger votre application lorsque le code change.
la source
Une réponse unique que j'utilise pour suivre un changement de fichier:
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 dessus
~/.kde/share/config/plasma-desktop-appletsrc
; que pour une raison inconnue continue de perdre monSwitchTabsOnHover=false
la source
J'utilise ce script pour le faire. J'utilise inotify en mode moniteur
Enregistrez ceci sous runatwrite.sh
il lancera myfile.sh à chaque écriture.
la source
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 facilement créer, modifier / supprimer des démons / agents.
( exemple pris d'ici )
la source
J'ai un GIST pour cela et l'utilisation est assez simple
https://gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55
la source
Pour les personnes qui trouvent ceci en cherchant des modifications dans un fichier particulier sur Google , la réponse est beaucoup plus simple (inspirée par la réponse de Gilles ).
Si vous voulez faire quelque chose après l' écriture d'un fichier particulier, voici comment:
Enregistrez-le sous, par exemple,
copy_myfile.sh
et placez le.sh
fichier dans le/etc/init.d/
dossier pour le lancer au démarrage.la source
L'outil 'fido' peut être une autre option pour ce besoin. Voir https://www.joedog.org/fido-home/
la source
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:
Usage
Utilisez-le tout de suite en exécutant:
Aperçu des fonctionnalités
-w '*.py'
ou-w '**/*.py'
)-d
nouveau le drapeau)-r
pour l’activer)la source