From b04c0acaedb30eabc27388c179338f96aea4900a Mon Sep 17 00:00:00 2001 From: "Hahn Axel (hahn)" <axel.hahn@unibe.ch> Date: Fri, 17 Jan 2025 13:50:07 +0100 Subject: [PATCH] handle multiple files with spaces; long param options; update help --- onfilechange.sh | 181 ++++++++++++++++++++++++------------------------ 1 file changed, 89 insertions(+), 92 deletions(-) diff --git a/onfilechange.sh b/onfilechange.sh index 0d6f8f6..80ec501 100755 --- a/onfilechange.sh +++ b/onfilechange.sh @@ -23,20 +23,22 @@ # 2019-10-21 v1.03 <axel.hahn@iml.unibe.ch> use stat as default # 2022-03-11 v1.04 <axel.hahn@iml.unibe.ch> shell fixes # 2022-03-11 v1.05 <axel.hahn@iml.unibe.ch> fix: behaviur when trigger command fails; shell fixes; update docs +# 2025-01-17 v1.06 <axel.hahn@unibe.ch> handle multiple files with spaces; long param options; update help # ====================================================================== # ---------------------------------------------------------------------- # CONFIG # ---------------------------------------------------------------------- -bDebug=0 -iSleep=5 +FLAG_DEBUG=0 +typeset -i iSleep=5 sCommand= -sWatchFile= sMode= +aWatchFiles=() + # ---- below are some internal variables -_version=1.05 +_version=1.06 # ---------------------------------------------------------------------- @@ -47,38 +49,55 @@ _version=1.05 function showHelp(){ local _self=$( basename $0 ) cat <<ENDOFHELP + HELP: - This script checks the change of a given fileobjects and triggers - a command if it changes + +${_self} checks the change of a given fileobjects and triggers +a command on file changes. +It can use stat or inotifywait to watch a file change. preferred is stat +because it can be used for not yet existing files. + +SYNTAX: + + ${_self} OPTIONS -c COMAND [FILE] [[... FILE N]] PRAMETERS: - -c [command] - command to execute on a file change - -f [fileobject(s)] - filenames or directories to watch; separate multiple files with - space and put all in quotes - -h - show this help - -i - force inotifywait command - -s - force stat command (default mode) - -v - verbose mode; enable showing debug output - -w [integer] - for stat mode: wait time in seconds betweeen each test or on - missing file; default: 5 sec -EXAMPLES: - $_self -f /home/me/touchfile.txt -c "ls -l" - watch touchfile.txt and make a file listing on change + -c|--command COMMAND + A command to execute on a file change + + -f|--file FILENAME + Filenames or directories to watch; separate multiple files with + space and put all in quotes + DEPRECATED: add all files to watch as parameters - $_self -f "/home/me/touchfile.txt home/me/touchfile2.txt" -c "ls -l" - watch touchfile.txt and touchfile2.txt + -h|--help + show this help - $_self -f /home/me/touchfile.txt -s -w 10 -c "echo hello" - watch touchfile.txt every 10 sec with stat and show "hello" on a - change + -i|--inotifywait + force inotifywait command + + -s|--stat + force stat command (default mode) + + -v + verbose mode; enable showing debug output; it should be the first option + to see handling of other options + + -w|--wait SLEEPTIME + for stat mode: wait time in seconds betweeen each test or on + missing file; default: 5 sec + +EXAMPLES: + + $_self -c "ls -l" /home/me/touchfile.txt + watch touchfile.txt and make a file listing on change + + $_self -c "ls -l" "/home/me/touchfile.txt" "home/me/touchfile2.txt" + watch touchfile.txt and touchfile2.txt + + $_self -s -w 10 -c "echo hello" /home/me/touchfile.txt + watch touchfile.txt every 10 sec with stat and show "hello" on a change ENDOFHELP @@ -86,28 +105,28 @@ ENDOFHELP # write debug output ... if debug is enabled only # -# global (bool) $bDebug +# global (bool) $FLAG_DEBUG # param string text message to show function wd(){ - if [ $bDebug -ne 0 ]; then - echo "[$(date)] DEBUG |" $* + if [ $FLAG_DEBUG -ne 0 ]; then + echo "$*" | while read -r l; do echo "[$(date)] DEBUG | ${l}"; done fi } # list watched files # -# global (string) filename(s) to watch +# global (string) filesAsString list of all files to watch function listFiles(){ echo echo ">>>>> watched files" - ls -ld ${sWatchFile} 2>&1 + eval "ls -ld $filesAsString" } # for stat: helper to get current file status # -# global (string) $sWatchFile +# global (array) $aWatchFiles array of watched files function getFilestatus(){ - for myfile in ${sWatchFile} + for myfile in "${aWatchFiles[@]}" do stat -c "%F %n | perms: %A; user %u (%U) group %g (%G) | size: %s byte | last modification %y" "${myfile}" 2>&1 done @@ -129,9 +148,9 @@ function initFilestatus(){ # global (string) $sTmpFile2 current file status # global (string) $sCommand command to execute function compareFilestatus(){ - getFilestatus >${sTmpFile2} - wd "$(cat ${sTmpFile2})" - if diff ${sTmpFile} ${sTmpFile2}; then + getFilestatus >"${sTmpFile2}" + wd "$(cat "${sTmpFile2}")" + if diff "${sTmpFile}" "${sTmpFile2}"; then wd "No Change" else wd "Change detected." @@ -141,7 +160,7 @@ function compareFilestatus(){ echo rc=$? FAILED. fi wd "Re-Init File status" - mv ${sTmpFile2} ${sTmpFile} + mv "${sTmpFile2}" "${sTmpFile}" echo echo ">>>>> waiting for the next change ..." fi @@ -168,15 +187,12 @@ _______________________________________________________________________| v${_ver ENDOFHEAD if which stat >/dev/null 2>&1; then - echo "INFO: stat command detected" sMode=stat else - echo ERROR: the command stat was not found on your system. if ! which inotifywait >/dev/null 2>&1; then echo ERROR: the command inotifywait was not found on your system. exit 2 fi - echo "INFO: enabling inotifywait command" sMode=inotifywait fi @@ -184,52 +200,29 @@ if [ $# -eq 0 ]; then showHelp exit 0 fi - -while getopts ":c: :v :f: :h :i :s :w:" opt -do - case $opt in - h) - showHelp - exit 0 - ;; - v) - bDebug=1 - wd "debug is now ${bDebug}" - ;; - c) - sCommand=$OPTARG - wd "command is now ${sCommand}" - ;; - f) - sWatchFile=$OPTARG - wd "watch file is now ${sWatchFile}" - ;; - i) - sMode=inotifywait - wd "forcing mode with inotifywait command" - ;; - s) - sMode=stat - wd "forcing mode with stat command" - ;; - w) - typeset -i iSleep=$OPTARG - wd "sleep $iSleep sec" - ;; - :) - echo "ERROR: Option -$opt requires an argument." >&2 - showHelp - exit 1 - esac -done +while [[ "$#" -gt 0 ]]; do case $1 in + -h|--help) showHelp; exit 0;; + -c|--command) sCommand="$2"; wd "command is now ${sCommand}"; shift; shift;; + -f|--file) aWatchFiles+=("$2"); echo "DEPPRECATED: Add all files as parameter instead of using -f option."; wd "watch file $2 was added" ;shift;shift;; + -i|--inotifywait) sMode=inotifywait; wd "forcing mode with inotifywait command"; shift;; + -s|--stat) sMode=stat; wd "forcing mode with inotifywait command"; shift;; + -w|--wait) iSleep=$OPTARG; wd "sleep $iSleep sec"; shift;shift;; + -v|--verbose) FLAG_DEBUG=1; shift;; + *) if grep "^-" <<< "$1" >/dev/null ; then + echo; echo "ERROR: Unknown parameter: $1"; echo; _showHelp; exit 2 + fi + # break; + aWatchFiles+=("$1"); wd "watch file $1 was added" ;shift;; + +esac; done cat <<ENDOFINFO --- summary -checking file [${sWatchFile}] +checking file(s): ${aWatchFiles[@]} with command [${sMode}] with a sleep time of [${iSleep}] seconds -and on change I start the command [${sCommand}] +on change execute command [${sCommand}] ............................................................................... @@ -240,19 +233,23 @@ ENDOFINFO # CHECKS # ---------------------------------------------------------------------- +filesAsString= +for myfile in "${aWatchFiles[@]}" +do + filesAsString+="'${myfile}' " +done + wd "--- checks" -if [ -z "${sWatchFile}" ]; then - echo ERROR: set a check file with param -f +if [ -z "${filesAsString}" ]; then + echo "ERROR: Add one or more files / directories to watch as parameter" exit 1 fi if ! listFiles; then - echo "INFO: file ${sWatchFile} (or one of them) does not exist yet" - # echo "ERROR: file ${sWatchFile} (or one of them) does not exist yet" - # exit 1 + echo "INFO: file ${filesAsString} (or one of them) does not exist yet" fi if [ -z "${sCommand}" ]; then - echo ERROR: set a ${sCommand} with param -s + echo ERROR: set a command with option -c first. exit 1 fi echo @@ -262,7 +259,7 @@ echo # ---------------------------------------------------------------------- echo ">>>>> start" -myset=$(echo "${sWatchFile}" | sha1sum | cut -f 1 -d " ") +myset=$(echo "${aWatchFiles[*]}" | sha1sum | cut -f 1 -d " ") sTmpFile="/tmp/$(basename $0)-${myset}-last.tmp" sTmpFile2="/tmp/$(basename $0)-${myset}-current.tmp" @@ -270,7 +267,7 @@ case $sMode in "inotifywait") while true; do if listFiles >/dev/null 2>&1; then - inotifywait -e attrib -e modify "${sWatchFile}" && execCommand + eval inotifywait -e attrib -e modify "${filesAsString}" && execCommand || exit 1 else echo "ERROR: inotifywait only can notify if all watched files exist." echo "Use parameter -s to use stat for file detection, This mode also allows that a file is deleted." -- GitLab