I provide this answer to illustrate a similar but more complex use case. Note that the code provided by @Oli is included in my answer.
I want to post process a file when it has changed. Specifically I want to invoke dart-sass on a scss
file to produce a css
file and its map file. Then the css
file is compressed.
My problem is that editing/saving the scss
source file could be done directly through vim (which uses a backup copy when writing the file) or through SFTP (specifically using macOS Transmit). That means the change could be seen with inotifywait
as a pair CREATE
followed by CLOSE_WRITE,CLOSE
or as a single CREATE
(due to the RENAME
cmd through SFTP I think). So I have to launch the processing if I see a CLOSE_WRITE,CLOSE
or a CREATE
which is not followed by something.
Remarks:
- It has to handle multiple concurrent edit/save.
- The temporary files used by Transmit of the form
<filename>_safe_save_<digits>.scss
must not be taken into account.
- The version of
inotify-tools
is 3.20.2.2 and has been compiled from the source (no package manager) to get a recent version with the include
option.
#!/usr/bin/bash
declare -A pids
# $1: full path to source file (src_file_full)
# $2: full path to target file (dst_file_full)
function launch_dart() {
echo "dart"
/opt/dart-sass/sass "$1" "$2" && /usr/bin/gzip -9 -f -k "$2"
}
inotifywait -e close_write,create --include "\.scss$" -mr assets/css |
grep -v -P '(?:\w+)_safe_save_(?:\d+)\.scss$' --line-buffered |
while read dir action file; do
src_file_full="$dir$file"
dst_dir="${dir%assets/css/}"
dst_file="${file%.scss}.css"
dst_file_full="priv/static/css/${dst_dir%/}${dst_file}"
echo "'$action' on file '$file' in directory '$dir' ('$src_file_full')"
echo "dst_dir='$dst_dir', dst_file='$dst_file', dst_file_full='$dst_file_full'"
# if [ "$action" == "DELETE" ]; then
# rm -f "$dst_file_full" "${dst_file_full}.gz" "${dst_file_full}.map"
if [ "$action" == "CREATE" ]; then
echo "create. file size: " $(stat -c%s "$src_file_full")
{ sleep 1; pids[$src_file_full]=0; launch_dart "$src_file_full" "$dst_file_full"; } & pids[$src_file_full]=$!
elif [ "$action" == "CLOSE_WRITE,CLOSE" ]; then
[[ ${pids[$src_file_full]} -gt 0 ]] && kill -9 ${pids[$src_file_full]}
launch_dart "$src_file_full" "$dst_file_full"
fi
done