2010-08-27 20:02:40 +0000 2010-08-27 20:02:40 +0000
459
459
Advertisement

Hoe voer je een commando uit wanneer een bestand verandert?

Advertisement

Ik wil een snelle en eenvoudige manier om een commando uit te voeren wanneer een bestand verandert. Ik wil iets heel eenvoudigs, iets wat ik op een terminal laat draaien en sluit als ik klaar ben met dat bestand.

Op dit moment gebruik ik dit:

while read; do ./myfile.py ; done

En dan moet ik naar die terminal gaan en op Enter drukken, wanneer ik dat bestand op mijn editor opslaat. Wat ik wil is zoiets als dit:

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

of elke andere oplossing die zo eenvoudig is.

BTW: Ik gebruik Vim, en ik weet dat ik een autocommando kan toevoegen om iets op BufWrite te draaien, maar dit is niet het soort oplossing dat ik nu wil.

Update: Ik wil iets eenvoudigs, indien mogelijk wegwerpbaar. Bovendien wil ik iets in een terminal draaien omdat ik de uitvoer van het programma wil zien (ik wil foutmeldingen zien).

Over de antwoorden: Bedankt voor al je antwoorden! Ze zijn allemaal erg goed, en elk van hen heeft een heel andere aanpak dan de andere. Omdat ik er maar één moet accepteren, accepteer ik degene die ik daadwerkelijk heb gebruikt (het was eenvoudig, snel en gemakkelijk te onthouden), ook al weet ik dat het niet de meest elegante is.

Advertisement

Antwoorden (37)

434
434
434
2010-08-27 20:54:55 +0000

Eenvoudig, met behulp van inotifywait (installeer uw distributie inotify-tools-pakket):

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

of

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

Het eerste fragment is eenvoudiger, maar heeft een belangrijk nadeel: het zal veranderingen missen die worden uitgevoerd terwijl inotifywait niet actief is (in het bijzonder terwijl myfile wel actief is). Het tweede fragment heeft dit defect niet. Let er echter op dat het ervan uitgaat dat de bestandsnaam geen witruimte bevat. Als dat een probleem is, gebruik dan de --format optie om de uitvoer te wijzigen zodat de bestandsnaam niet wordt opgenomen:

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

Hoe dan ook, er is een beperking: als een of ander programma myfile.py vervangt door een ander bestand, in plaats van te schrijven naar het bestaande myfile, zal inotifywait sterven. Veel redacteuren werken op die manier.

Om deze beperking te overwinnen, gebruik je inotifywait in de directory:

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

Of gebruik een ander programma dat dezelfde onderliggende functionaliteit gebruikt, zoals incron (laat je gebeurtenissen registreren wanneer een bestand wordt gewijzigd) of fswatch (een programma dat ook werkt op veel andere Unix-varianten, met behulp van de analogie van Linux-informatie van elke variant).

179
179
179
2013-10-25 09:41:16 +0000

entr http://entrproject.org/ ) biedt een vriendelijker interface om te melden (en ondersteunt ook *BSD & Mac OS X).

Het maakt het zeer eenvoudig om meerdere bestanden te bekijken (alleen beperkt door ulimit -n), neemt het gedoe van het omgaan met bestanden die worden vervangen, en vereist minder bash-syntax:

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

Ik heb het gebruikt op mijn hele project broncodeboom om de unit tests uit te voeren voor de code die ik momenteel aan het wijzigen ben, en het is al een enorme stimulans voor mijn workflow geweest.

Vlaggen zoals -c (het scherm leegmaken tussen de runs) en -d (afsluiten wanneer een nieuw bestand wordt toegevoegd aan een bewaakte map) voegen nog meer flexibiliteit toe, bijvoorbeeld:

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

Vanaf begin 2018 is het nog steeds in actieve ontwikkeling en is het te vinden in Debian & Ubuntu (apt install entr); bouwen vanuit de repo van de auteur was in ieder geval pijnvrij.

112
Advertisement
112
112
2011-06-30 13:34:28 +0000

Ik heb een Python programma geschreven om precies dit te doen, genaamd when-change .

Gebruik is eenvoudig:

when-changed FILE COMMAND...

of om meerdere bestanden te bekijken:

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

FILE kan een directory zijn. Kijk recursief met -r. Gebruik %f om de bestandsnaam door te geven aan de opdracht.

53
53
53
2013-08-20 17:12:47 +0000

Hoe zit het met dit script? Het gebruikt het stat commando om de toegangstijd van een bestand te krijgen en voert een commando uit wanneer er een wijziging is in de toegangstijd (wanneer het bestand wordt benaderd).

#!/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
30
Advertisement
30
30
2010-08-27 20:12:25 +0000

Oplossing met behulp van Vim:

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

Maar ik wil deze oplossing niet omdat het een beetje vervelend is om te typen, het is een beetje moeilijk om te onthouden wat te typen, precies, en het is een beetje moeilijk om de effecten ervan ongedaan te maken (noodzaak om :au! BufWritePost myfile.py te draaien). Bovendien blokkeert deze oplossing Vim totdat het commando klaar is met uitvoeren.

Ik heb deze oplossing hier toegevoegd voor de volledigheid, omdat het andere mensen kan helpen.

Om de programma-uitvoer weer te geven (en je bewerkingsstroom volledig te verstoren, omdat de uitvoer een paar seconden over je editor zal schrijven, totdat je op Enter drukt), verwijder je het :silent commando.

23
23
23
2012-06-09 23:51:16 +0000

Als u toevallig npm hebt geïnstalleerd, is nodemon waarschijnlijk de gemakkelijkste manier om aan de slag te gaan, vooral op OS X, dat blijkbaar geen aanmeldingshulpmiddelen heeft. Het ondersteunt het uitvoeren van een opdracht wanneer een map wordt gewijzigd.

21
Advertisement
21
21
2016-03-22 14:57:03 +0000

Voor degenen die inotify-tools niet kunnen installeren zoals ik, zou dit nuttig moeten zijn:

watch -d -t -g ls -lR

Dit commando sluit af wanneer de uitvoer verandert, ls -lR geeft een lijst van alle bestanden en mappen met hun grootte en data, dus als een bestand wordt gewijzigd moet het het commando afsluiten, zoals de mens zegt:

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

Ik weet dat dit antwoord door niemand gelezen kan worden, maar ik hoop dat iemand het zou kunnen bereiken.

Opdrachtregel voorbeeld:

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

Open een andere terminal:

~ $ echo "testing" > /tmp/test

Nu zal de eerste terminal 1,2,3

uitvoeren Eenvoudig script voorbeeld:

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

watch -d -t -g ls -lR ${DIR_TO_WATCH} && ${COMMAND}
17
17
17
2015-09-09 21:49:14 +0000

rerun2 op github ) is een 10-lijns Bash script van het formulier:

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

Sla de github versie op als ‘rerun’ op uw PATH, en roep het aan met behulp van:

rerun COMMAND

Het voert COMMANDO uit elke keer dat er een bestandssysteem gebeurtenis wijzigt binnen uw huidige directory (recursief. )

Dingen die men leuk zou kunnen vinden:

  • Het gebruikt inotify, dus is meer responsief dan polling. Fantastisch voor het uitvoeren van sub-milliseconde unit tests, of het renderen van graphviz dot bestanden, elke keer als je op ‘save’ drukt.
  • Omdat het zo snel is, hoef je niet de moeite te nemen om het te vertellen dat je grote subdirs (zoals node_modules) moet negeren, alleen maar om redenen van prestatie.
  • Het is extra super responsief, omdat het slechts één keer inotifywait belt, bij het opstarten, in plaats van het uit te voeren, en de dure hit van het vestigen van horloges, bij elke iteratie.
  • Het zijn slechts 12 regels van Bash
  • Omdat het Bash is, interpreteert het commando’s die je doorgeeft precies alsof je ze op een Bash prompt hebt getypt. (Vermoedelijk is dit minder cool als je een andere shell gebruikt.)
  • Het verliest geen gebeurtenissen die gebeuren terwijl COMMAND aan het uitvoeren is, in tegenstelling tot de meeste andere inotify oplossingen op deze pagina.
  • Bij de eerste gebeurtenis voert het een ‘dode periode’ in voor 0.15 seconden, waarin andere gebeurtenissen worden genegeerd, voordat COMMAND precies één keer wordt uitgevoerd. Dit is zodat de vlaag van gebeurtenissen veroorzaakt door de create-write-move dans die Vi of Emacs doet bij het opslaan van een buffer geen meervoudige moeizame executies van een mogelijk traag lopende testsuite veroorzaakt. Gebeurtenissen die zich dan voordoen tijdens de uitvoering van COMMANDO worden niet genegeerd - ze zullen een tweede dode periode veroorzaken en de daaropvolgende uitvoering.

Dingen die men niet leuk vindt:

  • Het gebruikt inotify, dus zal niet werken buiten Linuxland.
  • Omdat het inotify gebruikt, zal het kotsen op het proberen te kijken naar mappen die meer bestanden bevatten dan het maximum aantal gebruikers-inotify horloges. Standaard lijkt dit op ongeveer 5.000 tot 8.000 te zijn ingesteld op verschillende machines die ik gebruik, maar het is gemakkelijk te verhogen. Zie https://unix.stackexchange.com/questions/13751/kernel-inotify-watch-limit-reached
  • Er worden geen opdrachten uitgevoerd die Bash aliassen bevatten. Ik zou kunnen zweren dat dit vroeger werkte. In principe, omdat dit Bash is, niet het uitvoeren van COMMAND in een subshell, zou ik verwachten dat dit werkt. Ik zou graag horen of iemand weet waarom het niet werkt. Veel van de andere oplossingen op deze pagina kunnen zulke commando’s ook niet uitvoeren.
  • Persoonlijk zou ik willen dat ik een toets kon indrukken in de terminal waar hij in draait om handmatig een extra uitvoering van COMMAND te veroorzaken. Kan ik dit op de een of andere manier eenvoudigweg toevoegen? Een gelijktijdig lopende ‘while read -n1’ lus die ook uitvoering aanroept?
  • Op dit moment heb ik het gecodeerd om de terminal te wissen en het uitgevoerde COMMAND af te drukken op elke iteratie. Sommige mensen zouden graag commandline-vlaggen willen toevoegen om dit soort dingen uit te schakelen, enz. Maar dit zou de grootte en complexiteit vele malen vergroten.

Dit is een verfijning van @cychoi’s anker.

12
Advertisement
12
12
2010-08-27 21:23:29 +0000

Hier is een eenvoudig shell Bourne-script dat:

  1. Neemt twee argumenten: het te monitoren bestand en een commando (met argumenten, indien nodig)
  2. 2. Kopieert het te bewaken bestand naar de /tmp directory
  3. Controleert elke twee seconden of het te controleren bestand nieuwer is dan de kopie
  4. Als het nieuwer is overschrijft het de kopie met het nieuwere origineel en voert het commando uit 5. Schoont na zichzelf op als je op Ctr-C

drukt Dit werkt op FreeBSD. Het enige portabiliteitsprobleem dat ik kan bedenken is als een andere Unix niet het mktemp(1) commando heeft, maar in dat geval kun je gewoon de naam van het temp bestand hard coderen.

8
8
8
2014-08-08 22:20:09 +0000

als u nodemon hebt geïnstalleerd, dan kunt u dit doen:

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

In mijn geval bewerk ik html lokaal en verzend het naar mijn externe server wanneer een bestand verandert.

nodemon -w <watch directory> -x "scp filename jaym@jay-remote.com:/var/www" -e ".html"
8
Advertisement
8
8
2010-08-27 20:12:59 +0000

Kijk eens naar incron . Het is vergelijkbaar met cron, maar maakt gebruik van inotify events in plaats van tijd.

6
6
6
2014-07-09 13:16:10 +0000

Kijk in Guard, in het bijzonder met deze plugin: https://github.com/hawx/guard-shell

U kunt deze instellen om een willekeurig aantal patronen in de directory van uw project te bekijken en opdrachten uit te voeren wanneer er wijzigingen optreden. De kans is groot dat er zelfs een plugin beschikbaar is voor datgene wat u in de eerste plaats probeert te doen.

6
Advertisement
6
6
2014-01-22 14:55:46 +0000

Een andere oplossing met NodeJs, * fsmonitor ** :

  1. Installeer

    1. Vanaf de opdrachtregel (voorbeeld, controleer de logboeken en “retail” als een logboekbestand verandert)
5
5
5
2015-12-28 10:44:18 +0000
  • Watchdog ** is een Python-project, en is misschien precies wat u zoekt:

Ondersteunde platforms

  • Linux 2. 6 (inotify)
  • Mac OS X (FSEvents, kqueue)
  • FreeBSD/BSD (kqueue)
  • Windows (ReadDirectoryChangesW met I/O-afwerkingspoorten; ReadDirectoryChangesW worker threads)
  • OS-onafhankelijk (de schijf peilen voor snapshots van mappen en deze periodiek vergelijken; langzaam en niet aanbevolen)

Schreef er gewoon een opdrachtregel-wrapper voor * watchdog_exec **:

Voorbeeld runs

Op fs gebeurtenis met bestanden en mappen in de huidige directory, run echo $src $dst commando, tenzij het fs gebeurtenis wordt gewijzigd, dan run python $src commando.

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

Met behulp van korte argumenten, en het beperken tot alleen uitvoeren wanneer de gebeurtenissen “ main.py” betreffen:

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

EDIT: Net gevonden heeft Watchdog een officiële CLI genaamd watchmedo, dus controleer dat ook.

5
Advertisement
5
5
2012-07-02 16:36:51 +0000

Onder Linux: “` man watch

watch -n 2 yourcommandto_run ”`

zal het commando om de 2 seconden uitvoeren.

Als het meer dan 2 seconden duurt om het commando uit te voeren, zal het horloge wachten tot het klaar is vooraleer het opnieuw te doen.

4
4
4
2010-08-27 20:37:52 +0000

Als je programma een soort log/output genereert, kun je een Makefile maken met een regel voor die log/output die afhankelijk is van je script en iets doen als

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

. Je kunt ook een nepdoel maken en de regel ervoor hebben zowel je script aanroepen als het nepdoel aanraken (terwijl het nog steeds afhankelijk is van je script).

4
Advertisement
4
4
2014-09-15 23:24:58 +0000
4
4
4
2015-06-17 18:03:51 +0000

Verbeterd op Gilles’ antwoord .

Deze versie draait inotifywait één keer en controleert op gebeurtenissen ( bijv.: modify) daarna. Zodanig dat inotifywait niet opnieuw hoeft te worden uitgevoerd bij elke gebeurtenis.

Het is snel en snel (zelfs wanneer grote mappen recursief worden gemonitord) 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

3
Advertisement
3
3
2010-08-27 20:05:59 +0000

Een beetje meer aan de programmeerkant, maar je wilt zoiets als inotify . Er zijn implementaties in vele talen, zoals jnotify en pyinotify .

Met deze bibliotheek kunt u afzonderlijke bestanden of hele mappen controleren en gebeurtenissen weergeven wanneer een actie wordt ontdekt. De teruggestuurde informatie omvat de bestandsnaam, de actie (aanmaken, wijzigen, hernoemen, verwijderen) en het bestandspad, naast andere nuttige informatie.

3
3
3
2012-11-11 21:48:31 +0000

Voor degenen die op zoek zijn naar een FreeBSD-oplossing is hier de port:

/usr/ports/sysutils/wait_on
3
Advertisement
3
3
2014-04-29 13:56:13 +0000

Ik hou van de eenvoud van while inotifywait ...; do ...; done maar het heeft twee problemen:

  • Bestandswijzigingen die plaatsvinden tijdens de do ...; zullen worden gemist
  • Slow bij gebruik in recursieve modus

Daarom heb ik een helperscript gemaakt dat inotifywait gebruikt zonder die beperkingen: inotifyexec

Ik stel voor dat je dit script op je pad zet, zoals in ~/bin/. Het gebruik wordt beschreven door gewoon het commando uit te voeren.

Voorbeeld: inotifyexec "echo test" -r .

3
3
3
2016-04-12 14:53:44 +0000

Verbeterde Sebastian’s oplossing met watch commando:

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

Bel voorbeeld:

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

Het werkt maar wees voorzichtig: watch commando heeft bekende bugs (zie man): het reageert alleen op veranderingen in VISIBLE in de eindapparatuur van -g CMD.

2
Advertisement
2
2
2017-03-01 20:14:14 +0000

U kunt reflex .

Reflex is een klein hulpmiddel om een map te bekijken en een opdracht opnieuw uit te voeren wanneer bepaalde bestanden veranderen. Het is geweldig voor het automatisch uitvoeren van compile/lint/testtaken en voor het opnieuw laden van uw applicatie wanneer de code verandert.

# Rerun make whenever a .c file changes
reflex -r '\.c$' make
1
1
1
2017-04-05 07:38:43 +0000

Ik heb hier een GIST voor en het gebruik is vrij eenvoudig

watchfiles <cmd> <paths...>

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

1
Advertisement
1
1
2017-06-03 12:10:57 +0000

Zoals een paar anderen hebben gedaan, heb ik ook een lichtgewicht commandoregeltool geschreven om dit te doen. Het is volledig gedocumenteerd, getest en modulair opgebouwd.

Watch-Do

Installatie

Je kunt het installeren (als je Python3 en pip hebt) met behulp van:

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

Gebruik

Gebruik het direct door het uit te voeren:

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

Eigenschappen Overzicht

  • Ondersteunt bestandsbolling (gebruik -w '*.py' of -w '**/*.py')
  • Voer meerdere commando’s uit op een bestandswijziging (geef de -d vlag nogmaals aan)
  • Onderhoudt dynamisch de lijst met bestanden om te kijken of er gebolling wordt gebruikt (-r om dit aan te zetten)
  • Meerdere manieren om een bestand te “bekijken”:
  • Wijzigingstijd (standaard)
  • Bestands hash
  • Triviaal om een eigen bestand te implementeren (dit is de ModificationTime watcher)
  • Modulair ontwerp. Als je commando’s wilt laten uitvoeren, is het triviaal om bij het openen van een bestand je eigen watcher te schrijven (mechanisme dat bepaalt of de doers moeten worden uitgevoerd).
1
1
1
2016-02-26 19:10:05 +0000

Ik gebruik dit script om het te doen. Ik gebruik inotify in monitor-mode

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

Sla dit op als runatwrite.sh Usage: runatwrite.sh myfile.sh

het zal myfile.sh draaien bij elk schrijven.

1
Advertisement
1
1
2015-09-09 19:36:04 +0000

Ik heb hiervoor een Python-programma geschreven, genaamd rerun .

UPDATE: Dit antwoord is een Python-script dat polls voor wijzigingen uitvoert, wat in sommige omstandigheden nuttig is. Voor een Linux-only Bash script dat gebruik maakt van inotify, zie mijn andere antwoord, zoek op deze pagina naar ‘rerun2’.

Installeren voor Python2 of Python3 met:

pip install --user rerun

en het gebruik is zeer eenvoudig:

rerun "COMMAND"

Het commando wordt verwacht als een enkel argument, niet als een opeenvolging van ruimte-afhankelijke args. Citeer het daarom zoals afgebeeld, wat het aantal extra ontsnappingen die je zou moeten toevoegen, vermindert. Typ het commando zoals je het zou hebben getypt op de commandoregel, maar omringd door aanhalingstekens.

Standaard kijkt het naar alle bestanden in of onder de huidige directory, waarbij zaken als bekende broncontrole dirs, .git, .svn, etc. worden overgeslagen.

Optionele vlaggen bevatten ‘-i NAME’ die veranderingen in benoemde bestanden of directories negeert. Dit kan meerdere malen gegeven worden.

Aangezien het een Python-script is, moet het de opdracht als een sub-proces uitvoeren, en we gebruiken een nieuwe instantie van de huidige shell van de gebruiker om ‘COMMAND’ te interpreteren en te beslissen welk proces daadwerkelijk uitgevoerd moet worden. Als uw commando echter shell-aliassen en dergelijke bevat die zijn gedefinieerd in .bashrc, zullen deze niet worden geladen door de subshell. Om dit op te lossen kunt u een ‘-I’ vlag geven, om interactieve (aka ‘login’) subshells te gebruiken. Dit is langzamer en meer foutgevoelig dan het starten van een gewone shell, omdat het je .bashrc moet bronnen.

Ik gebruik het met Python 3, maar de laatste keer dat ik controleerde werkte rerun nog steeds met Python 2.

Dubbelzijdig zwaard is dat het gebruik maakt van polling in plaats van inotify. Aan de andere kant betekent dit dat het op elk OS werkt. Plus, het is beter dan sommige andere oplossingen die hier worden getoond in termen van het slechts één keer uitvoeren van het gegeven commando voor een aantal wijzigingen in het bestandssysteem, niet één keer per gewijzigd bestand, terwijl het tegelijkertijd het commando een tweede keer uitvoert als er tijdens het uitvoeren van het commando weer bestanden veranderen.

Aan de andere kant betekent polling dat er een 0.0 tot 1.0 seconden vertraging is, en natuurlijk is het langzaam om extreem grote mappen te monitoren. Dat gezegd hebbende, ik ben nog nooit een project tegengekomen dat zo groot is dat dit zelfs maar merkbaar is zolang je ‘-i’ gebruikt om grote dingen zoals je virtualenv en node_modules te negeren.

Hmmm. rerun is voor mij al jaren onmisbaar - ik gebruik het in principe acht uur per dag voor het uitvoeren van tests, het herbouwen van punt-bestanden terwijl ik ze bewerk, etc. Maar nu ik dit hier kom typen, is het duidelijk dat ik moet overschakelen naar een oplossing die gebruik maakt van inotify (ik gebruik niet langer Windows of OSX.) en is geschreven in Bash (dus het werkt met aliassen zonder extra gepruts).

1
1
1
2015-09-01 04:53:52 +0000

Een oneliner antwoord dat ik gebruik om een bestandswijziging bij te houden:

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

Je hoeft BF niet te initialiseren als je weet dat de eerste datum de starttijd is.

Dit is eenvoudig en draagbaar. Er is hier nog een ander antwoord dat gebaseerd is op dezelfde strategie met behulp van een script. Kijk ook eens.

  • *

Gebruik: Ik gebruik dit om de fouten te debuggen en ~/.kde/share/config/plasma-desktop-appletsrc in de gaten te houden; dat om een of andere onbekende reden mijn SwitchTabsOnHover=false blijft verliezen.

1
Advertisement
1
1
2016-03-22 15:33:56 +0000

Voor degenen die OS X gebruiken, kun je een LaunchAgent gebruiken om een pad/bestand te bekijken op veranderingen en iets te doen als dat gebeurt. FYI - LaunchControl is een goede app om gemakkelijk daemons/agenten te maken/wijzigen/verwijderen.

voorbeeld van hier ) <?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
0
0
2019-11-26 15:53:22 +0000

Als je hier niets nieuws voor wilt installeren, is hier een klein shell-scriptje dat je op je pad kunt zetten (bijv. onder $HOME/bin). Het voert een commando uit wanneer de opgegeven bestanden worden gewijzigd. Bijvoorbeeld:

$ onchange './build' *.txt
#!/bin/sh
cmd="$1"; shift
files="$@"
changed() { tar -c $files | md5sum; } # for on every save use: `stat -c %Z $files`
while true; do
  if ["$(changed)" != "$last"]; then
    last="$(changed)"
    $cmd
  fi
  sleep 1
done

Het taart, en heeft dan de inhoud van de bestanden en/of mappen, dus het zal niet elke keer draaien als je dwangmatig op CTRL-S (of type :w) drukt, maar alleen als er daadwerkelijk iets verandert. Merk op dat het elke seconde zal controleren, dus neem niet te veel op of uw machine kan langzaam worden. Als u wilt dat het op elke save draait, gebruik dan stat in plaats daarvan (zie commentaar). Ook voor mac md5sum heet het md5 als ik me goed herinner.

Keurig trucje: Op het moment dat je het wilt gebruiken, wil je waarschijnlijk het laatste commando dat je net hebt uitgevoerd herhalen, maar dan steeds weer opnieuw. Je kunt de snelkoppeling !! gebruiken om het laatste commando in deze te ‘injecteren’:

$ onchange "!!" *.txt
0
Advertisement
0
0
2018-04-12 18:32:28 +0000

Description

This will watch a file for changes and execute whatever command (including further arguments) was given as second statement. It will also clear the screen and print the time of last execution. Opmerking: je kunt de functie meer (of minder) reactief maken door het aantal seconden te veranderen dat de functie moet slapen na elke cyclus van de lus.

Exemplaargebruik

watch_file my_file.php php my_file.php

Deze regel zal een php-bestand my_file.php bekijken en de php interpreter doorlopen wanneer deze verandert.

Functiedefinitie

function watch_file (){

### Set initial time of file
LTIME=`stat -c %Z $1`
printf "&00133c"
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 "&00133c"
    echo -e "watching: $1 ---- $(date '+%Y-%m-%d %H:%M:%S')\n-------------------------------------------\n"
    ${@:2}
    LTIME=$ATIME
   fi
   sleep 1
done
}

Credit

Dit is in principe een meer algemene versie van het antwoord van VDR.

0
0
0
2018-03-19 20:30:21 +0000

Basisgebruik

Hier is een oplossing die geen installatie van meer software vereist en die uit de doos werkt.

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

Dit commando sluit af onder de volgende voorwaarden:

  • Een regel wordt toegevoegd aan myfile.txt nadat het commando is uitgevoerd
  • De myfile.txt wordt vervangen door een andere nadat het commando is uitgevoerd

Je zegt dat je gebruik maakt van vim, en vim zal het bestand vervangen bij het opslaan. Ik heb getest dat dit werkt met vim.

Je kunt de uitvoer van dit commando negeren, het kan iets zeggen als:

tail: myfile.txt’ is vervangen; na einde van nieuw bestand

Geavanceerd gebruik

kun je dit combineren met timeout om waar of onwaar terug te geven. Je kunt het zo gebruiken:

timeout 5s bash -c ‘tail -q –follow=naam pijp 2> /dev/null | head -n 0’ && echo changed | echo timeout

Discussion

tail gebruikt inotify onder de motorkap. Zo krijg je dit fancy asynchroon gedrag zonder enige peiling. Er is waarschijnlijk een ander standaard unix programma dat inotify gebruikt en dat we eleganter kunnen misbruiken.

Soms gaan deze commando’s meteen weg, maar als je ze meteen een tweede keer uitvoert dan werken ze zoals geadverteerd. Ik heb ergens een off-by-one fout gemaakt, help me alstublieft dit te corrigeren.

Op RHEL kan ik gebruiken:

timeout 5s sh -c ‘gio monitor pipe | head -n 0’ && echo veranderd | echo timeout

Maar ik weet niet zeker of dat draagbaar is.

0
Advertisement
0
0
2019-01-28 16:51:42 +0000

find kan de truc doen.

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

find -ctime 1s drukt de bestandsnaam af als deze gewijzigd was in de laatste 1s.

0
0
0
2015-05-13 15:21:33 +0000

Voor mensen die dit vinden bij Googling voor wijzigingen in een bepaald bestand, is het antwoord veel eenvoudiger (geïnspireerd op Gilles’ antwoord ).

Als je iets na een bepaald bestand wilt doen, dan is hier hoe:

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

Sla dit op als bijvoorbeeld copy_myfile.sh en plaats het .sh-bestand in de /etc/init.d/-map om het bij het opstarten te laten draaien.

0
Advertisement
0
0
2019-03-21 11:33:37 +0000

Ik had een iets andere situatie. Maar ik denk dat dit nuttig kan zijn voor iemand die deze vraag leest.

Ik moest op de hoogte worden gebracht wanneer een logboekbestand van grootte veranderde, maar dat hoeft niet meteen. En het kon dagen of weken duren, dus ik kon inotify (dat toch niet geïnstalleerd/geactiveerd was op die server) niet gebruiken op de commandoregel (ik wilde nohup of iets dergelijks niet gebruiken). Dus besloot ik een bash script te draaien op cron om

te controleren. Het script schrijft de bestandsgrootte van het bekeken bestand in een tekstbestand en op elke cron run en controleert, of die waarde is veranderd en mailt de laatste regel naar mij als

#!/bin/bash
FILE_TO_WATCH="/path/to/log_file.log"
FILESIZE_FILE="/path_to/record.txt"
SUBJECT="Log file 'log_file.log' has changed"
MAILTO="info@example.com"
BODY="Last line of log file:\n"
LAST_LINES=1

# get old recorded file size from file
OLD_FILESIZE=$(cat "${FILESIZE_FILE}")
# write current file size into file
stat --printf="%s" "${FILE_TO_WATCH}" > "${FILESIZE_FILE}"
# get new recorded file size from file
NEW_FILESIZE=$(cat "${FILESIZE_FILE}")

if ["${OLD_FILESIZE}" != "${NEW_FILESIZE}"]; then
    echo -e "${BODY}"$(tail -${LAST_LINES} ${FILE_TO_WATCH}) | mail -s "${SUBJECT}" "${MAILTO}"
fi
``` is veranderd.
0
0
0
2019-11-23 23:41:53 +0000

Bekijk https://github.com/watchexec/watchexec .

watchexec is een eenvoudige, op zichzelf staande tool die een pad bekijkt en een opdracht uitvoert wanneer het wijzigingen detecteert.

Example

Bekijk alle JavaScript-, CSS- en HTML-bestanden in de huidige directory en alle subdirectories voor wijzigingen, die worden uitgevoerd wanneer een wijziging wordt gedetecteerd:

$ watchexec --exts js,css,html make

0
Advertisement
0
0
2017-03-20 13:52:53 +0000

De ‘fido’ tool kan een andere optie zijn voor deze behoefte. Zie https://www.joedog.org/fido-home/

Advertisement