Last active
March 4, 2024 14:44
-
-
Save swarminglogic/8963507 to your computer and use it in GitHub Desktop.
watchfile - monitor file(s) and execute a command when files are changed
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
version=1.0.1 | |
versionDate="2014-02-14" | |
function showHelp() { | |
echo "watchfile - monitor file(s)/command and perform action when changed | |
Possible ways of usage | |
---------------------------------------- | |
Monitor FILE, when modified execute FILE | |
\$ watchfile [options] FILE | |
Monitor FILE, when modified execute CMND [PARAM_1 ..PARAM_N] | |
\$ watchfile [options] FILE CMND [PARAM_1 .. PARAM_N] | |
Monitor FILE_1 .. FILE_N, when modified execute CMND [PARAM_1 ..PARAM_N] | |
\$ watchfile [options] -i FILE_1 .. FILE_N -e CMND [PARAM_1 .. PARAM_N] | |
Monitor output of CMND1, when modified execute CMND2 [PARAM_1 .. PARAM_N] | |
\$ watchfile [options] -s \"CMND1\" -e CMND [PARAM_1 .. PARAM_N] | |
options: | |
-h, --help Show help | |
-d, --delay=N Specify the delay between each monitor update. Default 0.5. | |
--check-content If set it checks file content, instead of just the timestamp. | |
Has no effect with the -s flag set. | |
--no-clear If set, it doesn't clear the screen before executing CMND. | |
-v, --version Outputs version information | |
flags: | |
-s, Next argument specifies monitor command. Requires -e flag. | |
-i, Start listing files to monitor. Requires -e flag. | |
-e, Start listing command to execute. Requires -s or -i or flag. | |
Must be the last flag used (CMND can thus use flags as parameters) | |
Note: If CMND isn't found, and ./CMND is, it automatically uses this command. | |
Note: If the command uses ampersands (&, &&), these must be escaped (\&, \&\&). | |
Examples | |
---------------------------------------- | |
Monitor executable foo.sh, and execute on change | |
$ watchfile foo.sh | |
Monitor python file foo.py, and execute it on change | |
$ watchfile foo.py python foo.py | |
As above, but monitor content (not just timestamp): | |
$ watchfile --check-content foo.py python foo.py | |
Compiling main.cpp file on change: | |
$ watchfile main.cpp g++ -Wall main.cpp -o main | |
Compiling main.cpp file on change, running when compilation succeedes: | |
$ watchfile main.cpp g++ -Wall main.cpp -o main \&\& ./main | |
Compiling project whenever source files changes, and running if it succeedes: | |
$ watchfile -s \"find . -name '*.cpp' -or -name '*.h' | xargs cat\" \\ | |
-e make \&\& ./main | |
See: http://swarminglogic.com/jotting/2014_02_watchfile for more examples | |
Mainted at: https://gist.github.com/swarminglogic/8963507 | |
Author: Roald Fernandez (github@swarminglogic.com) | |
Version: $version ($versionDate) | |
License: CC-zero (public domain) | |
" | |
exit $1 | |
} | |
function parseParameters() { | |
tmp=$@ | |
leftovers="" | |
while test $# -gt 0; do | |
case "$1" in | |
-h|--help) | |
showHelp 0 | |
;; | |
--no-clear) | |
shift | |
flagNoClear=true | |
;; | |
--check-content) | |
shift | |
flagCheckContent=true | |
;; | |
-d) | |
shift | |
delay=$1 | |
shift | |
;; | |
--delay*) | |
delay=`echo $1 | sed -e 's/^[^=]*=//g'` | |
shift | |
;; | |
-v|--version) | |
shift | |
echo "watchfile $version" | |
exit 0 | |
;; | |
-s) | |
shift | |
flagS=true | |
watchcmnd=$1 | |
shift | |
;; | |
-i) | |
shift | |
flagI=true | |
nI=0 | |
for i in `seq 1 $#`; do | |
if [[ ${!i} == -* ]] ; then | |
break; | |
else | |
((++nI)) | |
fi | |
done | |
watchfiles=${@:1:$nI} | |
shift $nI | |
;; | |
-e) | |
shift | |
flagE=true | |
execcmnd=${@:1} | |
break | |
;; | |
-*) | |
leftovers="$leftovers "$1 | |
shift | |
;; | |
*) | |
leftovers="$leftovers "$1 | |
shift | |
;; | |
esac | |
done | |
if [[ $flagE && (! $flagS) && (! $flagI) ]] ; then | |
echo "Error: If -e flag is set, -s or -i flags are required." | |
exit 1 | |
elif [[ ($flagS || $flagI) && ! $flagE ]] ; then | |
echo "Error: If -s or -i flags are set, the -e flags is required." | |
exit 1 | |
elif [[ $flagS && $flagI ]]; then | |
echo "Error: Both -s and -i flags cannot be used simultaneously." | |
exit 1 | |
elif [[ (! $flagE) && (! $flagS) && (! $flagI) ]] ; then | |
set -- $leftovers | |
watchfiles=$1 | |
if [ $# -gt 1 ]; then | |
execcmnd=${@:2} | |
else | |
execcmnd=$watchfiles | |
fi | |
fi | |
} | |
# Exit with help if no parameters | |
if [[ ! $@ ]] ; then showHelp 1; fi | |
# Defaults | |
delay=0.5 | |
# Parse parameters into $watch and $execcmnd variables | |
parseParameters "$@" | |
# Sanitize executable | |
set -- $execcmnd | |
if [[ ! `which $1` ]] && [[ -x ./$1 ]] ; then | |
execcmnd=./$execcmnd | |
elif [[ ! `which $1` ]] && [[ ! -x ./$1 ]] ; then | |
echo "Error: No executable $1 or ./$1 found" | |
exit 1 | |
fi | |
# Main monitoring loop. | |
if [[ -z $watchcmnd ]] ; then | |
if [[ ! $flagCheckContent ]] ; then | |
watchcmnd="stat -c %Y $watchfiles | md5sum" | |
else | |
watchcmnd="cat $watchfiles | md5sum" | |
fi | |
else | |
watchcmnd="$watchcmnd | md5sum" | |
fi | |
md5sum=`eval $watchcmnd` | |
md5sumNow=$md5sum | |
while [[ true ]] | |
do | |
# Loop until some files have changed | |
while [[ "$md5sumNow" = "$md5sum" ]] | |
do | |
sleep $delay | |
md5sumNow=`eval $watchcmnd` | |
done | |
# Execute the file, as it has changed. | |
if [[ ! $flagNoClear ]] ; then | |
clear | |
fi | |
eval $execcmnd | |
md5sum=$md5sumNow | |
done |
Can it be used to monitor and compile CSS files, for e.g compile stylus files to css ?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just changed it a little bit to make it work on OSX https://gist.github.com/thinkxl/3e45880b7d27fc0b1d6d