Vreau o modalitate rapidă și simplă de a executa o comandă ori de câte ori un fișier modificări. Vreau ceva foarte simplu, ceva ce nu va lăsa execută pe un terminal și închideți-l ori de câte ori am'm terminat de lucru cu acest fișier.
În prezent, am'm folosind acest:
while read; do ./myfile.py ; done
Și apoi am nevoie pentru a merge la terminal și apăsați Enter, ori de câte ori am salvat ca fișier de pe editorul meu. Ceea ce vreau eu este ceva de genul:
while sleep_until_file_has_changed myfile.py ; do ./myfile.py ; done
Sau orice alta solutie la fel de ușor ca asta.
BTW: am'm folosind Vim, și știu că pot adăuga un autocommand pentru a rula ceva pe BufWrite, dar acest lucru nu este la fel de soluție vreau acum.
Actualizare: vreau ceva simplu, discardable dacă este posibil. Ce's mai mult, vreau ceva pentru a rula într-un terminal pentru că vreau să văd programul de ieșire (vreau sa vad mesaje de eroare).
Despre răspunsuri: Multumesc pentru toate raspunsurile! Toate acestea sunt foarte bune, și fiecare are o abordare foarte diferită de celelalte. Când am nevoie pentru a accepta numai unul, m-am'm a accepta una pe care am'am folosit de fapt (a fost simplu, rapid și ușor de reținut), chiar dacă știu că nu este cel mai elegant.
Simplu, folosind inotifywait (instala distribuția's inotify-tools
pachet):
while inotifywait -e close_write myfile.py; do ./myfile.py; done
sau
inotifywait -q -m -e close_write myfile.py |
while read -r filename event; do
./myfile.py # or "./$filename"
done
Primul fragment este mai simplă, dar are un dezavantaj semnificativ: va e dor de modificările efectuate în timp ce inotifywait
e't de funcționare (în special în timp ce myfile
se execută). Cel de-al doilea fragment nu't au acest defect. Cu toate acestea, feriți-vă că se presupune că numele de fișier nu't conține spații albe. Dacă asta's o problemă, utilizați --format
opțiunea de a schimba ieșire să nu includă numele de fișier:
inotifywait -q -m -e close_write --format %e myfile.py |
while read events; do
./myfile.py
done
Oricum, există o limitare: dacă un program înlocuiește myfile.py cu un alt fișier, mai degrabă decât scris existente
myfile,
inotifywait` va muri. Mulți editori merge așa.
Pentru a depăși această limitare, utilizarea `inotifywait pe director:
inotifywait -e close_write,moved_to,create -m . |
while read -r directory events filename; do
if [ "$filename" = "myfile.py" ]; then
./myfile.py
fi
done
Alternativ, utilizați un alt instrument care utilizează aceeași bază de funcționalitate, cum ar fi incron (vă permite să înregistreze evenimente atunci când un fișier este modificat) sau fswatch (un instrument care, de asemenea, funcționează pe multe alte variante Unix, folosind fiecare variantă's analogice de Linux's inotify).
entr (http://entrproject.org/) ofera o interfata mai prietenoasa pentru inotify (și sprijină, de asemenea, *BSD & Mac OS X).
Se face foarte usor pentru a specifica mai multe fișiere pentru a viziona (limitat doar de ulimit -n
), ia hassle de a face cu fișiere, fiind înlocuit, și necesită mai puțin bash sintaxa:
$ find . -name '*.py' | entr ./myfile.py
Am'am fost folosind-o în întreaga mea sursă de proiect copac pentru a rula teste unitare pentru codul I'm în prezent modificarea și it's fost un impuls imens pentru fluxul de lucru deja.
Steaguri ca "- c " (a goli ecranul între ruleaza) și -d
(ieșire atunci când un fișier nou este adăugat la un monitorizate director) se adaugă și mai multă flexibilitate, de exemplu, puteți face:
$ while sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done
Ca de la începutul anului 2018 l's încă în dezvoltare activă și poate fi găsit în Debian & Ubuntu (apt instala entr
); construirea de autor's repo a fost fără durere, în orice caz.
Am scris un program in Python pentru a face exact acest lucru numit când-s-a schimbat.
Utilizare este simplu:
when-changed FILE COMMAND...
Sau pentru a viziona mai multe fișiere:
when-changed FILE [FILE ...] -c COMMAND
"DOSAR" poate fi un director. Ceas recursiv cu -r
. Utilizarea %f
a trece numele de fișier pentru a comanda.
Ce zici de scenariul asta? Se folosește stat comandă pentru a obține timp de acces la un fișier și rulează o comandă ori de câte ori există o schimbare în timp de acces (când fișierul este accesat).
#!/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
Soluție folosind Vim:
:au BufWritePost myfile.py :silent !./myfile.py
Dar eu nu't doriți această soluție pentru că's cam enervant sa tip, se's un pic cam greu să-mi amintesc ce de tip, exact, și-l's un pic dificil de a anula efectele sale (nevoie pentru a rula :au! BufWritePost myfile.py
). În plus, această soluție blocuri Vim până când comanda a terminat de executare.
Am'am adăugat această soluție aici doar pentru completitudine, cum ar putea ajuta alte persoane.
Pentru a afișa programul de ieșire (și complet perturba editting flux, ca ieșire se va scrie peste editor pentru câteva secunde, până când apăsați Enter), scoateți `:silent comandă.
Pentru cei care pot't install inotify-tools
ca mine, acest lucru ar trebui să fie util:
uita-te -d -t -g ls-lR`
Această comandă de ieșire, atunci când la ieșire se schimbă, ls-lR
va lista fiecare fișier și director, cu dimensiunea sa și datele, astfel încât dacă un fișier este schimbat ar trebui să ieși din comandă, ca om spune:
-g, --chgexit
Exit when the output of command changes.
Știu că acest răspuns nu poate fi citit de oricine, dar sper ca cineva va ajunge la ea.
Exemplu de linie de comandă:
~ $ cd /tmp
~ $ watch -d -t -g ls -lR && echo "1,2,3"
Deschide un alt terminal:
~ $ echo "testing" > /tmp/test
Acum, primul terminal de ieșire va 1,2,3
Script simplu exemplu:
#!/bin/bash
DIR_TO_WATCH=${1}
COMMAND=${2}
watch -d -t -g ls -lR ${DIR_TO_WATCH} && ${COMMAND}
rerun2
(pe github) este un 10-line Bash script de forma:
#!/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
Salva github versiune ca 'reluare' pe CALEA ta, și de a invoca ajutorul:
rerun COMMAND
Se ruleaza COMANDA de fiecare data acolo's un sistem de fișiere modifica eveniment în directorul curent (recursive.)
Lucrurile s-ar putea ca despre asta:
Lucrurile s-ar putea place despre el:
Acesta este un rafinament de @cychoi's anwer.
Aici's un simplu shell, Bourne shell script care:
f=$1
shift
cmd=$*
tmpf="mktemp /tmp/onchange.XXXXX
"
cp "$f" "$tmpf"
capcana "rm $tmpf; ieșirea 1" 2
în timp ce : ; face
dacă [ "$f" -nt "$tmpf" ]; apoi
cp "$f" "$tmpf"
$cmd
fi
dormi 2
făcut
Aceasta funcționează pe FreeBSD. Singura portabilitate problemă care mă pot gândi este dacă unele alte Unix nu't au mktemp(1) de comandă, dar în acest caz, puteți doar codul de greu la temp de nume de fișier.
dacă aveți nodemon instalat, atunci puteți face acest lucru:
nodemon -w <watch directory> -x "<shell command>" -e ".html"
În cazul meu, am edita html la nivel local și nava-l meu server de la distanță atunci când un fișier modificări.
nodemon -w <watch directory> -x "scp filename [email protected]:/var/www" -e ".html"
Uită-te în Paza, în special cu acest plugin:
https://github.com/hawx/guard-shell
Puteți să-l configurați pentru a urmări orice număr de modele din proiect's director, și executa comenzi atunci când apar modificări. Șansă bună chiar că nu's un plugin disponibil pentru că ceea ce ai're încercarea de a face în primul rând.
Watchdog este un proiect Python, și poate fi doar ceea ce ai're în căutarea pentru:
platformele Suportate
- Linux 2.6 (inotify)
- Mac OS X (FSEvents, kqueue)
- FreeBSD/BSD (kqueue)
- Windows (ReadDirectoryChangesW cu I/O completion ports; ReadDirectoryChangesW lucrător fire)
- OS-independent (secții de disc pentru directorul instantanee și comparându-le periodic; lent și nu este recomandat)
Doar a scris o linie de comandă ambalaj pentru ea watchdog_exec
:
Pe fs eveniment care implică fișierele și directoarele din directorul curent, run echo $src $dst comandă, cu excepția cazului în fs eveniment este modificat, apoi run python $src
comanda.
python -m watchdog_exec . --execute echo --modified python
Folosind scurte argumente, și de restricționare a executa numai atunci când evenimentele implica "main.py":
python -m watchdog_exec . -e echo -a echo -s __main__.py
EDIT: Tocmai am găsit câine de Pază a unui oficial CLI numit watchmedo
, deci, a verifica asta, de asemenea.
Dacă programul generează un fel de jurnal/ieșire, puteți crea un Makefile cu o regulă pentru că log/ieșire care depinde de script-ul dvs. și de a face ceva de genul
while true; do make -s my_target; sleep 1; done
Alternativ, puteți crea o falsă țintă și au de regulă pentru ambele apel script-ul dvs. și atingeți fals țintă (în timp ce încă în funcție de script-ul).
Îmbunătățit Gilles's a răspunde.
Această versiune ruleaza inotifywait
o dată și monitoare pentru evenimente (.e.g.: "modify") ulterior. Astfel că inotifywait` doesn't trebuie să fie re-executat la fiecare eveniment întâlnite.
L's rapid și rapid!(chiar și atunci când monitorizarea mare director recursiv)
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
Îmbunătățit Sebastian's soluție cu "ceas" de comandă:
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
Apel exemplu:
watch_cmd.sh "ls -lR /etc/nginx | grep .conf$" "sudo service nginx reload"
Funcționează, dar fii atent: "ceas", comanda are bug-uri cunoscute (a se vedea om): reacționează la modificări numai în VIZIBIL la borna de piese de -g CMD
de ieșire.
Îmi place simplitatea de timp inotifywait ...; face ...; realizat` cu toate acestea ea are două aspecte:
Pentru acestea am facut un helper script care foloseste inotifywait fără aceste limitări: inotifyexec
Vă sugerez să pun acest script în calea ta, ca în ~/bin/
. Utilizare este descris doar prin rularea comenzii.
Exemplu: inotifyexec "echo test" -r .