Bir dosya değiştiğinde komut nasıl çalıştırılır?


388

Bir dosya değiştiğinde komutun hızlı ve basit bir şekilde yürütülmesini istiyorum. Çok basit bir şey istiyorum, bir terminalde çalışmayı bırakacağım ve o dosyayla çalışmayı bitirdiğimde onu kapatacağım.

Şu anda, bunu kullanıyorum:

while read; do ./myfile.py ; done

Sonra o terminale gidip Girmek , o dosyayı ne zaman editörüme kaydedersem. İstediğim şey şunun gibi bir şey:

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

Veya bu kadar kolay başka bir çözüm.

BTW: Vim kullanıyorum ve bufWrite'da bir şeyi çalıştırmak için bir otomatik komut ekleyebileceğimi biliyorum, ama bu şimdi istediğim bir çözüm değil.

Güncelleştirme: Mümkünse basit, anlaşılabilir bir şey istiyorum. Dahası, bir terminalde çalışacak bir şey istiyorum çünkü program çıktısını görmek istiyorum (hata mesajlarını görmek istiyorum).

Cevaplar hakkında: Tüm cevaplarınız için teşekkürler! Hepsi çok iyi ve her biri diğerlerinden çok farklı bir yaklaşım sergiliyor. Sadece birini kabul etmem gerektiğine göre, gerçekten kullandığım birini (basit, hızlı ve hatırlanması kolaydı) kabul ediyorum, en şık olmadığını bilmeme rağmen.


Olası çapraz site kopyası: stackoverflow.com/questions/2972765/... (burada konu üzerinde olmasına rağmen =))
Ciro Santilli 新疆改造中心 六四事件 法轮功

bir çapraz site çoğaltılmadan önce başvuruda bulundum ve reddedildi: S;)
Francisco Tapia

4
Jonathan Hartley'nin çözümü, buradaki diğer çözümlere dayanıyor ve en çok oy alan cevapların sahip olduğu büyük sorunları düzeltti: bazı değişiklikler eksik ve verimsiz. Lütfen kabul edilen cevabını, adresinde belirtildiği şekilde değiştirin. github.com/tartley/rerun2 (veya bu kusurlar olmadan başka bir çözüme)
nealmcb

Yanıtlar:


370

Basit, kullanarak inotifywait (dağıtımınızı yükleyin inotify-tools paket):

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

veya

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

İlk pasaj daha basittir ancak olumsuz bir yönü vardır: inotifywait Çalışmıyor (özellikle myfile çalışıyor). İkinci pasajda bu kusur yok. Ancak, dosya adının boşluk içermediğini varsaydığına dikkat edin. Bu bir problemse, kullan --format çıktıyı dosya adını içermeyecek şekilde değiştirme seçeneği:

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

Her iki durumda da bir sınırlama var: eğer bazı programlar yerini alırsa myfile.py var olana yazmak yerine farklı bir dosyayla myfile, inotifywait ölecek. Birçok editör bu şekilde çalışır.

Bu sınırlamayı aşmak için, inotifywait dizinde:

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

Alternatif olarak, aşağıdaki gibi temel işlevleri kullanan başka bir araç kullanın. incron (bir dosya değiştirildiğinde etkinlik kaydetmenizi sağlar) veya fswatch (Linux'un inotify'ının her bir varyantını kullanarak, diğer birçok Unix varyantında da çalışan bir araç).


46
Bunların hepsini (bir kaç tane bash numarasıyla) kullanımı basit bir ortamda sakladım sleep_until_modified.sh betiği şurada mevcut: bitbucket.org/denilsonsa/small_scripts/src
Denilson Sá Maia

14
while sleep_until_modified.sh derivation.tex ; do latexmk -pdf derivation.tex ; done harika. Teşekkür ederim.
Rhys Ulerich

5
inotifywait -e delete_self benim için iyi çalışıyor gibi görünüyor.
Kos

3
Çok basit ancak iki önemli sorunu var: Olaylar kaçırılabilir (döngüdeki tüm olaylar) ve inotifywait'in başlatılması her seferinde büyük özyinelemeli klasörler için bu çözümü yavaşlatır.
Wernight

5
Bazı sebeplerden dolayı while inotifywait -e close_write myfile.py; do ./myfile.py; done her zaman komutu çalıştırmadan çıkar (bash ve zsh). Bunun çalışması için eklemek gerekiyordu || true, Örneğin: while inotifywait -e close_write myfile.py || true; do ./myfile.py; done
ideasman42

132

entr ( http://entrproject.org/ ), belirtmek için daha kolay bir arayüz sağlar (ve ayrıca * BSD ve Mac OS X'i de destekler).

İzlenecek birden çok dosyayı belirtmeyi çok kolaylaştırır (yalnızca ulimit -n ), değiştirilen dosyalarla uğraşmakta güçlük çeker ve daha az bash sözdizimi gerektirir:

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

Şu anda değiştirdiğim kod için birim sınamalarını çalıştırmak için tüm proje kaynak ağacımda kullanıyorum ve zaten iş akışımda büyük bir artış oldu.

Gibi bayraklar -c (koşular arasındaki ekranı temizleyin) ve -d (izlenen bir dizine yeni bir dosya eklendiğinde çıkın) daha da fazla esneklik ekleyin, örneğin:

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

2018'in başından itibaren hala aktif gelişim içindedir ve Debian'da bulunabilir. Ubuntu ( apt install entr ); Her durumda yazarın deposundan inşa etmek ağrısızdı.


1
Yeni dosyalar ve modifikasyonları işlemez.
Wernight

2
@Wernight - 7 Mayıs 2014 itibariyle entr yeni -d bayrağı; biraz daha uzun soluklu, ama yapabilirsin while sleep 1 ; do find . -name '*.py' | entr -d ./myfile.py ; done yeni dosyalar ile başa çıkmak için.
Paul Fenney

1
entr ayrıca debian repolarda da bulunur, debian jessie / 8.2 den ...
Peter V. Mørch

5
OS X'te bulunan en iyi olanı. fswatch çok fazla korkak olay kapıyor ve nedenini bulmak için zaman harcamak istemiyorum
dtc

3
Bunu belirtmeye değer entr Homebrew’de mevcut brew install entr beklendiği gibi çalışacak
jmarceli

102

Bunu yapmak için bir Python programı yazdım. zaman-değiştirdi .

Kullanımı basit:

when-changed FILE COMMAND...

Veya birden fazla dosyayı izlemek için:

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

FILE bir dizin olabilir. Tekrarlayarak izleyin -r. kullanım %f dosya adını komuta geçirmek için.


1
@ ysangkok evet, kodun son sürümünde :)
joh

4
Şimdi "değiştiğinde pip kurulumu" yapılabilir. Hala güzel çalışıyor. Teşekkürler.
A. L. Flanagan

2
Önce ekranı temizlemek için kullanabilirsiniz. when-changed FILE 'clear; COMMAND'.
Dave James Miller

1
Bu cevap çok daha iyi çünkü ben de Windows'ta yapabiliyorum. Ve bu adam aslında cevabı almak için bir program yazdı.
Wolfpack'08

4
Herkese iyi haber! when-changed şimdi çapraz platform! En son göz atın 0.3.0 sürüm :)
joh

47

Bu senaryoya ne dersin? Kullanır stat Bir dosyanın erişim zamanını almak için komut ve erişim zamanında bir değişiklik olduğunda (dosyaya erişildiğinde) bir komut çalıştırır.

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

1
değil mi stat değiştirilen zaman -ing "bir dosya her değiştiğinde" cevap daha iyi olur mu?
Xen2050

1
Saniyede defalarca stat çalıştırmak, diske birçok okumaya neden olur mu? fstat sistemi çağrısı otomatik olarak bu yanıtları önbelleğe alır mı? Ne zaman değişiklik yapsam c kodumu derlemek için bir tür 'grunt watch' yazmaya çalışıyorum
Oskenso Kashi

Önceden izlenecek dosya adını biliyorsanız, bu iyidir. Dosya adını komut dosyasına iletmek daha iyi olur. Çok daha iyi dosya isimleri (örneğin. "Mywatch * .py") geçirirseniz daha iyi olur. Daha da iyisi, diğer çözümlerin bazılarının yaptığı alt dizinlerdeki dosyaları tekrar tekrar çalıştırabilirse olur.
Jonathan Hartley

2
Herkes ağır okumalar hakkında merak ediyorsa, bu senaryoyu Ubuntu 17.04'te 0.05s uyku ile test ettim ve vmstat -d disk erişimini izlemek için Görünüşe göre linux bu tür bir şeyi önbelleğe almak için harika bir iş çıkarmış: D
Oskenso Kashi

"COMMAND" da yazım hatası var, düzeltmeye çalışıyordum ama S.O. "Düzenleme 6 karakterden az olmamalıdır" diyor
user337085

29

Vim kullanarak çözüm:

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

Ancak bu çözümü istemiyorum çünkü yazmak biraz can sıkıcı, ne yazacağımı hatırlamak biraz zor, tam olarak ve etkilerini geri almak biraz zor (çalışması gerekiyor :au! BufWritePost myfile.py ). Ayrıca, bu çözüm komutun çalışmasını bitirene kadar Vim'i de engeller.

Bu çözümü, diğer insanlara yardımcı olabileceği için sadece tamlık için buraya ekledim.

Program çıktısını görüntülemek (ve düzenleme editörünüzün üzerine birkaç saniye yazacağınız için, Enter tuşuna basana kadar düzenleme akışınızı tamamen kesmek için), :silent Komut.


İle birleştiğinde bu oldukça hoş olabilir entr (aşağıya bakınız) - sadece vim'in entr izlemekte olan kukla bir dosyaya dokunmasını sağlayın ve gerisini arka planda kalan entr'e bırakın ... veya tmux send-keys eğer böyle bir ortamda olsaydın :)
Paul Fenney

Güzel! sizin için bir makro yapabilirsiniz .vimrc dosya
ErichBSchulz

24

Eğer olsaydın npm Kurulmuş, nodemon muhtemelen görünüşte araçları inotify olmayan OS X'te başlamak için en kolay yoldur. Bir klasör değiştiğinde komut çalıştırmayı destekler.


3
Ancak, yalnızca .js ve .coffee dosyalarını izler.
zelk

5
Geçerli sürüm herhangi bir komutu desteklemektedir, örneğin: nodemon -x "bundle exec rspec" spec/models/model_spec.rb -w app/models -w spec/models
kek

1
Keşke daha fazla bilgiye sahip olsaydım, ama osx'ın değişiklikleri izlemek için bir metodu var.
ConstantineK

1
OS X'te ayrıca kullanabilirsiniz Daemons'u Başlat Birlikte WatchPaths bağlantımda gösterildiği gibi
Adam Johns

14

rerun2 ( github ), formun 10 satırlık bir Bash komut dosyasıdır:

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

Github sürümünü PATH'nizde 'yeniden çalıştırma' olarak kaydedin ve aşağıdakileri kullanarak çağırın:

rerun COMMAND

Geçerli dizininizde (özyinelemeli) bir dosya sistemi change olayı olduğu her zaman COMMAND ile çalışır.

Bir insanın hoşuna gidebilecek şeyler:

  • İnotify kullanır, yoklamadan daha hassastır. Milisaniye altı birim testlerini yapmak veya 'kaydet' düğmesine her bastığınızda graphviz dot dosyaları oluşturmak için mükemmel.
  • Çok hızlı olduğu için, sadece performans nedenlerinden ötürü büyük alt dizinleri (node_modules gibi) yoksaymasını söylemenize gerek yok.
  • Ekstra süper duyarlıdır, çünkü çalıştırma yerine, her seferinde inotifywait'i bir kez bekler, her seferinde saatler kurmanın pahalı sonucuna neden olur.
  • Sadece 12 satır Bash
  • Bash olduğu için, onları bir Bash isteminde yazdığınız gibi tam olarak ilettiğiniz komutları yorumlar. (Başka bir kabuk kullanıyorsanız, bu muhtemelen daha az soğuktur.)
  • Bu sayfadaki diğer inotify çözümlerinin çoğunun aksine, COMMAND yürütülürken meydana gelen olayları kaybetmez.
  • İlk olayda, COMMAND tam olarak bir kez çalıştırılmadan önce, diğer olayların göz ardı edildiği 0.15 saniye boyunca 'ölü bir döneme' girer. Bu, Vi veya Emacs'in bir tamponu kaydederken yaptığı yazma-yazma-taşıma dansının neden olduğu olayların telaşı, muhtemelen yavaş çalışan bir test takımının birden fazla zahmetli uygulamasına neden olmaz. COMMAND yürütülürken meydana gelen olaylar göz ardı edilmez - ikinci bir ölü döneme ve daha sonra yürütmeye neden olurlar.

Bir kişinin bu konuda sevmediği şeyler:

  • İnotify kullanır, bu nedenle Linuxland dışında çalışmaz.
  • İnotify kullandığı için, maksimum kullanıcı inotify saati sayısından daha fazla dosya içeren dizinleri izlemeye çalışmaktan öteye gidecektir. Varsayılan olarak, bu kullandığım farklı makinelerde yaklaşık 5.000 ila 8.000 olarak ayarlanmış gibi görünüyor, ancak artması kolay. Görmek https://unix.stackexchange.com/questions/13751/kernel-inotify-watch-limit-reached
  • Bash takma adları içeren komutları yerine getirmiyor. Bunun işe yaradığına yemin edebilirim. Prensip olarak, bu Bash olduğundan, COMMAND'ı bir alt kabukta çalıştırmamak, bunun çalışmasını beklerdim. Neden olduğunu bilmeyen birileri varsa duymak isterim. Bu sayfadaki diğer çözümlerin birçoğu da böyle komutları çalıştıramaz.
  • Şahsen, COMMAND'ın ekstra bir şekilde çalıştırılmasına neden olmak için çalıştığı terminalde bir tuşa basabilmeyi diliyorum. Bunu bir şekilde ekleyebilir miyim? Eşzamanlı olarak çalışan '-n1 okurken' döngüsü de çalıştırılan?
  • Şu anda terminali temizlemek ve yürütülen her COMMAND komutunu her yinelemeye yazdırmak için kodladım. Bazı insanlar bunun gibi şeyleri kapatmak için komut satırı bayrakları eklemek isteyebilirler. Fakat bu, boyutu ve karmaşıklığı çok kat arttıracaktır.

Bu, @ cychoi'nin anwer ürününün iyileştirilmesidir.


1
Kullanman gerektiğine inanıyorum "$@" yerine $@, düzgün boşlukları içeren argümanlarla çalışmak için. Ama aynı zamanda kullanıyorsun evalBu durum, kullanıcıyı tekrar çalıştırırken ekstra dikkatli olmaya zorlar.
Denilson Sá Maia

Sağol Denilson. Alıntı yapmanın nerede yapılması gerektiğine dair bir örnek verebilir misiniz? Son 24 saattir kullanıyorum ve şu ana kadar boşluklarla ilgili herhangi bir problem görmedim. dikkatlice bir şey alıntı - sadece olarak çağrılır rerun 'command'. Sadece "$ @" kullandıysam, kullanıcının bunu çağırabileceğini mi söylüyorsun? rerun command (tırnak işaretleri olmadan?) Bu benim için faydalı görünmüyor: Ben genellikle Bash'in yapmasını istemiyorum herhangi emirden geçirmeden önce komutun işlenmesi. Örneğin. Komut "echo $ myvar" içeriyorsa, her yinelemede myvar'ın yeni değerlerini görmek isteyeceğim.
Jonathan Hartley

Gibi bir şey rerun foo "Some File" kırılabilir. Ama kullandığından beri eval, olarak yeniden yazılabilir rerun 'foo "Some File". Bazen yol genişletmenin boşluklar getirebileceğini unutmayın: rerun touch *.foo muhtemelen kırılacak ve kullanma rerun 'touch *.foo' biraz farklı anlamsallığa sahiptir (sadece bir defa veya birden fazla defa gerçekleşen yol genişlemesi).
Denilson Sá Maia

Yardım için teşekkürler. Evet: rerun ls "some file" boşluklar nedeniyle kırılıyor. rerun touch *.foo* genellikle çalışır, ancak * .foo ile eşleşen dosya adları boşluk içeriyorsa başarısız olur. Nasıl olduğunu anlamama yardım ettiğin için teşekkürler. rerun 'touch *.foo' farklı anlambilim var, ancak tek tırnaklı sürümün istediğim anlamsal olduğundan şüpheliyim: tekrarlanan her yinelemenin komutu tekrar yazmışım gibi davranmasını istiyorum - bu yüzden istemek *.foo her yinelemede genişletilecek. Etkilerini incelemek için önerilerinizi deneyeceğim ...
Jonathan Hartley

Bu PR hakkında daha fazla tartışma ( github.com/tartley/rerun2/pull/1 ) ve diğerleri.
Jonathan Hartley

12

İşte basit bir kabuk Bourne kabuğu betiği:

  1. İki argüman alır: izlenecek dosya ve bir komut (gerekirse, argümanlarla)
  2. İzlemekte olduğunuz dosyayı / tmp dizinine kopyalar
  3. Her iki saniyede bir, izlemekte olduğunuz dosyanın kopyadan daha yeni olup olmadığını kontrol eder
  4. Eğer daha yeniyse, kopya yeni yeninin üzerine yazar ve komutu çalıştırır.
  5. Ctrl-C tuşlarına bastığınızda kendinden sonra temizler

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

Bu FreeBSD üzerinde çalışır. Aklıma gelen tek taşınabilirlik sorunu, başka bir Unix'in mktemp (1) komutuna sahip olmamasıdır, ancak bu durumda geçici dosya adını yalnızca zor kodlayabilirsiniz.


9
Oy kullanma tek taşınabilir yoldur, ancak çoğu sistemde bir dosya değişikliği bildirim mekanizması vardır (Linux'ta belirtme, FreeBSD'de sıralanma,…). Yaparken ciddi bir alıntı problemin var. $cmd, ama neyse ki kolayca tamir edilebilir: hendek cmd değişken ve yürüt "$@". Komut dosyanız büyük bir dosyayı izlemek için uygun değil, ancak değiştirerek düzeltilebilir cp tarafından touch -r (içeriğe değil, yalnızca tarihe ihtiyacınız var). Taşınabilirlik-bilge -nt Test bash, ksh veya zsh gerektirir.
Gilles

10

Yükleyemeyenler için inotify-tools Benim gibi, bu yararlı olmalı:

watch -d -t -g ls -lR

Çıktı değiştiğinde bu komut çıkacaktır, ls -lR Her dosya ve dizini büyüklüğü ve tarihleriyle birlikte listeleyecektir, bu nedenle eğer bir dosya değiştirilirse komuttan çıkması gerekir.

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

Bu cevabın kimse tarafından okunamayacağını biliyorum, ama umarım birileri ona ulaşır.

Komut satırı örneği:

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

Başka bir terminal aç:

~ $ echo "testing" > /tmp/test

Şimdi ilk terminal çıkacak 1,2,3

Basit komut dosyası örneği:

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

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

4
Güzel kesmek. Test ettim ve listeleme uzun olduğunda ve değiştirilen dosya ekranın dışına düştüğünde sorun yaşıyor gibi görünüyor. Küçük bir değişiklik böyle bir şey olabilir: watch -d -t -g "ls -lR tmp | sha1sum"
Atle

1
çözümünüzü her saniye izlerseniz, sonsuza dek çalışır ve yalnızca bazı dosyalar değişirse MY_COMMAND özelliğini çalıştırın: -n1 "watch -d -t -g-g ls -lR & amp; & MY_COMMAND"
mnesarco

Saatimin sürümü (Linux'ta, watch from procps-ng 3.3.10 ) aralığı için kayan saniye kabul eder, bu nedenle watch -n0.2 ... saniyenin beşte birini yoklayacak. Bu sağlıklı milisaniye altı birim testi için iyi.
Jonathan Hartley

8

Şuna bir bak incron . Bu cron'a benzer, ancak zaman yerine inotify olaylarını kullanır.


Bu çalışmak için yapılabilir, ancak bir incron girişi oluşturmak, bu sayfadaki diğer çözümlere kıyasla oldukça emek yoğun bir işlemdir.
Jonathan Hartley

7

NodeJs ile başka bir çözüm, fsmonitor :

  1. kurmak

    sudo npm install -g fsmonitor
    
  2. Komut satırından (örneğin, günlükleri izleyin ve bir günlük dosyası değişirse "perakende")

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

Yan not: örnek tarafından çözülebilir tail -F -q *.log, Bence.
Volker Siegel

6

Linux altında:

man watch

watch -n 2 your_command_to_run

Her 2 saniyede bir komutu çalıştıracak.

Komutunuzun çalışması 2 saniyeden uzun sürerse, tekrar yapmadan önce saatiniz bekleyecektir.


Bu oldukça basittir, ancak bir miktar atık olsa da, stillerde canlı değişiklikler yapmak gibi geliştirme işleri için kolaydır.
Xeoncross

2
Komutun çalışması iki saniyeden uzun sürerse ne olur?
thirtythreeforty

@thirtyreeforty Ubuntu üzerinde yapılan hızlı bir deney, komutun çalışması ne kadar sürerse sürsün, saatin iki saniye bekleyeceğini gösteriyor. FWIW, uyku süresi '-n' ile minimum 0.1 saniyeye kadar belirlenebilir.
Jonathan Hartley

5

Özellikle bu eklenti ile Guard'a bakın:

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

Projenizin dizinindeki herhangi bir sayıda deseni izlemek için ayarlayabilirsiniz ve değişiklikler olduğunda komutları uygulayabilirsiniz. İlk etapta yapmaya çalıştığınız şey için bir eklenti olsa bile iyi bir şans.


5

eğer varsa nodemon yüklü, o zaman bunu yapabilirsiniz:

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

Benim durumumda html'yi yerel olarak düzenlerim ve bir dosya değiştiğinde uzak sunucuma gönderirim.

nodemon -w <watch directory> -x "scp filename jaym@jay-remote.com:/var/www" -e ".html"

4

Programınız bir tür günlük / çıktı oluşturuyorsa, betiğinize bağlı olan bu günlük / çıktı için bir kural içeren bir Makefile oluşturabilir ve bir şey yapabilir

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

Alternatif olarak, bir sahte hedef oluşturabilir ve bununla ilgili kuralın betiğinizi çağırmasını ve sahte hedefe dokunmasını sağlayabilirsiniz (yine de betiğinize bağlı olarak).


11
while sleep 1 ; do something ; done biraz daha iyidir while true ; do something ; sleep 1 ; done. En azından Ctrl + C tuşlarına basıldığında kolayca durur.
Denilson Sá Maia

Uykuyu kaldırmak yoğun bir döngüye neden olur mu (CPU ısı üreten ve bir dizüstü bilgisayarda pil ömrüne zarar veren)?
Steven Lu

2
@StevenLu: hayır, uyku yoğun bir bekleme değil. Sorun şu ki eğer uyku vücutta ise, Control-C uykuyu öldürür ve döngü baştan başlar. Döngünün yeniden başlatılmasının güç kullanımı önemsizdir. Bir terminalde kendin dene. Vücutta uyuduysanız, çalışması için Control-C'yi tutmanız gerekir.
Janus Troelsen

Sağ. Sanırım kaçırdım ve uykunun hala döngü koşulu olarak mevcut olduğunu görmedim. Bu küçük çimdik oldukça harika.
Steven Lu

4

2
Bu, anket içeren bir özellik dolu 200 satır Bash betiğidir. stat Verilen dosya adlarında çalıştırma md5sum çıktıda ve bu değer değişirse verilen komutu yeniden çalıştırır. Bash olduğu için, verilen komutu tam olarak Bash komut isteminde yazdığınız gibi çalıştırmanın iyi bir iş çıkardığından şüpheleniyorum. (Buna karşılık, burada diğer dillerde yazılmış çözümlerin çoğu, örneğin kabuk takma adları içeren komutları yerine getirmede başarısız olur. ll )
Jonathan Hartley

4

bekçi köpeği bir Python projesidir ve tam olarak aradığınız şey olabilir:

Desteklenen platformlar

  • Linux 2.6 (belirtilmemiş)
  • Mac OS X (FSEvents, sıra)
  • FreeBSD / BSD (sıra)
  • Windows (G / Ç tamamlama bağlantı noktalarına sahip ReadDirectoryChangesW; ReadDirectoryChangesW çalışan konuları)
  • İşletim sisteminden bağımsız (dizini anlık görüntüler için yoklama ve düzenli aralıklarla karşılaştırma yapma; yavaş ve önerilmez)

Sadece bunun için bir komut satırı sarıcı yazdı watchdog_exec:

Örnek çalıştırmalar

Geçerli dizindeki dosya ve klasörleri içeren fs olayında, çalıştır echo $src $dst komutu, fs olayı değiştirilmediği sürece çalıştır python $src Komut.

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

Kısa argümanlar kullanmak ve yalnızca olaylar içerdiğinde yürütmekle kısıtlamak " ana ".Py:

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

EDIT: Sadece Watchdog adında resmi bir CLI var bulundu watchmedo, öyleyse bunu da kontrol et.


4

Üzerine geliştirilmiş Gilles'in cevabı .

Bu sürüm çalışıyor inotifywait bir kez ve olayları izler (.e.g .: modify ) bundan sonra. Öyle ki inotifywait değil Karşılaşılan her olayda tekrar idam edilmesi gerekiyor.

Hızlı ve hızlı! (büyük dizini özyinelemeli olarak izlerken bile)

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

Bu sayfada sadece Linux kullanıcıları için en iyi cevaptır. Döngü içindeki öğeleri 'execute $ @' ile değiştirin ve kullanıcı bu komut dosyasını çalıştırmak için kendi komutunu kullanarak arayabilir. ". Scriptname COMMAND" gibi bir şey kullanarak, kaynak kullanıyorsanız kabuk takma adları içeren komutlarla bile çalışır. Bu yine de PATH üzerinde komut dosyası adını bulacaktır.
Jonathan Hartley

Bence 'REPLY okurken' yazmayı mı düşünüyorsun?
Jonathan Hartley

1
Bu düzeltmeleri kendime ait bir cevaba çevirdim: 'rerun2' için bu sayfayı ara
Jonathan Hartley

1
Fu * king El Kitabı'nı okuyarak, yani help read, If no NAMEs are supplied, the line read is stored in the REPLY variable..
cychoi

1
açıklama için teşekkürler. Aşamaları için teşekkürler! Bu yorumları silerdim ama elbette şimdi söylemeyeceğim.
Jonathan Hartley

3

Programlama tarafında biraz daha, ama gibi bir şey istiyorum Inotify . Gibi birçok dilde uygulamalar vardır, jnotify ve pyinotify .

Bu kitaplık, tek tek dosyaları veya tüm dizinleri izlemenizi sağlar ve bir eylem bulunduğunda olayları döndürür. Dönen bilgiler, diğer faydalı bilgilerin yanı sıra dosya adını, eylemi (oluştur, değiştir, yeniden adlandır, sil) ve dosya yolunu da içerir.


3

FreeBSD çözümü arayanlar için, işte liman:

/usr/ports/sysutils/wait_on

3

Sadeliği severim while inotifywait ...; do ...; done ancak iki sorunu var:

  • Sırasında gerçekleşen dosya değişiklikleri do ...; irade kaçırılmak, özlenmek
  • Yavaş özyinelemeli modda kullanırken

Bu nedenle kullanan bir komut dosyası yaptım inotifywait bu sınırlamalar olmadan: inotifyexec

Bu betiği, kendi ~/bin/. Kullanım sadece komutu çalıştırarak açıklanmaktadır.

Örnek: inotifyexec "echo test" -r .


Regex desen eşleşmesini desteklemek için komut dosyasını güncelleştirildi.
Wernight

Her iki sorun da "--monitor" modunda inotifywait kullanılarak çözüldü. Cychoi'nin cevabına bakınız.
Jonathan Hartley

3

Gelişmiş Sebastian'ın çözümü ile watch komut:

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

Çağrı örneği:

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

Çalışıyor ama dikkatli olun: watch komutunun bilinen hataları var (erkeğe bakınız): sadece VISIBLE’deki değişikliklere tepki verir. -g CMD çıktı.


2

Deneyebilirsin refleks .

Refleks, bir dizini izlemek ve belirli dosyalar değiştiğinde komutu yeniden çalıştırmak için kullanılan küçük bir araçtır. Derleme / lint / test görevlerini otomatik olarak çalıştırmak ve kod değiştiğinde uygulamanızı yeniden yüklemek için harika.

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

Alet hakkında biraz alıntı yapabilir misiniz? Hızlı bir okuma var yazılım nasıl tavsiye edilir rehberlik için.
bertieb

1

Bir dosya değişikliğini takip etmek için kullandığım oneliner bir cevap:

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

İlk tarihin başlangıç ​​zamanı olduğunu biliyorsanız, BF'yi başlatmanız gerekmez.

Bu basit ve taşınabilir. Burada bir betiği kullanarak aynı stratejiye dayalı başka bir cevap var. Ayrıca bir göz atın.


Kullanım: Bunu hata ayıklamak ve takip etmek için kullanıyorum ~/.kde/share/config/plasma-desktop-appletsrc; bilinmeyen bir nedenden dolayı benim kaybediyorum SwitchTabsOnHover=false


1

Bunu yapmak için bu betiği kullanıyorum. Monitör modunda inotify kullanıyorum

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

Bunu runatwrite.sh olarak kaydedin

Usage: runatwrite.sh myfile.sh

her yazımda myfile.sh dosyasını çalıştıracak.


1

OS X kullananlar için, değişikliklerin yolunu / dosyasını izlemek ve bu olduğunda bir şey yapmak için bir LaunchAgent kullanabilirsiniz. FYI - LaunchControl kolayca daemons / ajanları yapmak / değiştirmek / kaldırmak için iyi bir uygulama.

( buradan alınmış örnek )

<?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>


0

Bu değişiklikleri Googling'te bulan kişiler için belirli dosya, cevap çok basittir (tarafından ilham Gilles'in cevabı ).

Bir şey yapmak istiyorsan sonra belirli bir dosyaya yazılmıştır, işte size:

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

Bunu, örneğin copy_myfile.sh ve koymak .sh içine dosya /etc/init.d/ Başlangıçta çalışması için klasör.


Giles'in cevabını, her yinelemede beklenmedik bir şekilde beklediğine cevap vermeyen yanıtını paylaşarak, çok büyük dizinleri tekrar tekrar izlemek için tepkisiz olabilir. Bunun düzeltilmesi için cychoi'nin cevabına bakınız.
Jonathan Hartley


0

Diğer bazılarının yaptığı gibi, bunu yapmak için hafif bir komut satırı aracı da yazdım. Tamamen belgelenmiştir, test edilmiştir ve modülerdir.

İzle-Do

Kurulum

(Python3 ve pip kullanıyorsanız) kullanarak kurabilirsiniz:

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

kullanım

Çalıştırarak hemen kullanın:

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

Özelliklere genel bakış

  • Dosya taşmayı destekler (kullanım -w '*.py' veya -w '**/*.py' )
  • Bir dosya değişikliğinde birden çok komut çalıştırın (yalnızca -d tekrar işaretleyin)
  • Küreselleşme kullanılıyorsa izlenmesi gereken dosyaların listesini dinamik olarak tutar ( -r Bunu açmak için)
  • Bir dosyayı "izlemenin" birden çok yolu:
    • Değiştirme zamanı (varsayılan)
    • Dosya karması
    • Kendinizinkini uygulama için önemsiz (bu ModificationTime gözlemcisi)
  • Modüler tasarım. Komutların çalıştırılmasını istiyorsanız, bir dosyaya erişildiğinde, kendi izleyicinizi yazmanız önemsizdir (makinelerin çalıştırılıp çalıştırılmayacağını belirleyen mekanizma).
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.