loop.sh
1 ## \brief Control the loops within your scripts (pause/stop them). 2 ## \desc The loop.sh library provides functions to control loops within shells scripts. 3 ## When used, it allows to control the execution of already running loops from whatever 4 ## location or terminal. It is therefore possible to pause a script from another terminal 5 ## without hitting Control-Z in the shell process running the script. 6 ## 7 ## This execution control mechanism can even allow to control several loops and inner loops 8 ## (nested loops) at the same time, or make different scripts dependents on each other. 9 10 ## \example In a script: 11 ## \example-code bash 12 ## #!/bin/bash 13 ## source $(shellm-core-path) 14 ## shellm source shellm/loop 15 ## 16 ## loop init "script.loop" 17 ## 18 ## i=0 19 ## while true; do 20 ## 21 ## loop control "script.loop" || break 22 ## 23 ## echo "$i" 24 ## (( i++ )) 25 ## sleep 1 26 ## done 27 28 ## \example Then, from another terminal: 29 ## \example-code console 30 ## $ loop pause "script.loop" 31 ## $ loop resume "script.loop" 32 ## $ loop stop "script.loop" 33 34 ## \function loop_alive <NAME> 35 ## \function-brief Check if the loop is alive (exists and not paused). 36 ## \function-argument NAME The name of the loop to check. 37 ## \function-return 0 The loop is alive. 38 ## \function-return 1 The loop is not alive. 39 loop_alive() { 40 loop_exists "$1" && ! loop_paused "$1" 41 } 42 43 ## \function loop_control <NAME> 44 ## \function-brief Wait as long as the loop is paused, return 1 when it's dead. 45 ## Use this function like this: `loop_control $NAME || break` 46 ## This function is a shortcut for: 47 ## if loop_paused $NAME; then 48 ## loop_wait $NAME 49 ## elif loop_dead $NAME; then 50 ## break 51 ## fi 52 ## \function-argument NAME The name of the loop to control. 53 loop_control() { 54 if loop_paused "$1"; then 55 loop_wait "$1" 56 elif loop_dead "$1"; then 57 return 1 58 fi 59 } 60 61 ## \function loop_dead <NAME> 62 ## \function-brief Check if the loop is dead. 63 ## \function-argument NAME The name of the loop to check. 64 ## \function-return 0 The loop is dead. 65 ## \function-return 1 The loop is not dead. 66 loop_dead() { 67 ! loop_exists "$1" 68 } 69 70 ## \function loop_exists <NAME> 71 ## \function-brief Check if the loop exists. 72 ## \function-argument NAME The name of the loop to check. 73 ## \function-return 0 The loop exists. 74 ## \function-return 1 The loop does not exist. 75 loop_exists() { 76 [ -f "${__loop_datadir}/$1" ] 77 } 78 79 ## \function loop_init <NAME> 80 ## \function-brief Initialize a loop. 81 ## \function-argument NAME The name of the loop to initialize. 82 ## \function-return 0 The loop was correctly initialized. 83 ## \function-return 1 The loop was already initialized. 84 ## \function-stderr A warning when the loop was already initialized. 85 loop_init() { 86 if ! loop_exists "$1"; then 87 touch "${__loop_datadir}/$1" 88 else 89 echo "loop: '$1' already initialized" >&2 90 return 1 91 fi 92 } 93 94 ## \function loop_pause <NAME> 95 ## \function-brief Pause a loop. 96 ## \function-argument NAME The name of the loop to pause. 97 ## \function-return 0 The loop existed and was paused. 98 ## \function-return 1 The loop did not exist. 99 loop_pause() { 100 if loop_exists "$1"; then 101 echo "paused" > "${__loop_datadir}/$1" 102 else 103 return 1 104 fi 105 } 106 107 ## \function loop_paused <NAME> 108 ## \function-brief Check if the loop is paused. 109 ## \function-argument NAME The name of the loop to check. 110 ## \function-return 0 The loop is paused. 111 ## \function-return 1 The loop is not paused. 112 loop_paused() { 113 if ! grep -q paused "${__loop_datadir}/$1" 2>/dev/null; then 114 return 1 115 fi 116 } 117 118 ## \function loop_resume <NAME> 119 ## \function-brief Resume a loop. 120 ## \function-argument NAME The name of the loop to resume. 121 ## \function-return 0 The loop existed and was resumed. 122 ## \function-return 1 The loop did not exist. 123 loop_resume() { 124 if loop_exists "$1"; then 125 echo "" > "${__loop_datadir}/$1" 126 else 127 return 1 128 fi 129 } 130 131 ## \function loop_stop <NAME> 132 ## \function-brief Stop a loop. 133 ## \function-argument NAME The name of the loop to stop. 134 ## \function-return 0 The loop existed and was stopped. 135 ## \function-return 1 The loop did not exist. 136 loop_stop() { 137 rm "${__loop_datadir}/$1" 2>/dev/null 138 } 139 140 ## \function loop_wait <NAME> 141 ## \function-brief Wait as long as a loop is paused. 142 ## \function-argument NAME The name of the loop to wait. 143 loop_wait() { 144 while loop_paused "$1"; do 145 sleep 1; 146 done 147 } 148 149 ## \function loop_list 150 ## \function-brief List the currently existing loops. 151 ## \function-stdout The existing loops. 152 loop_list() { 153 local loop_file 154 find "${__loop_datadir}" -type f | while read -r loop_file; do 155 echo "${loop_file##*/}" 156 done 157 } 158 159 ## \function loop <COMMAND> <NAME> 160 ## \function-brief Main wrapper function accepting subcommands. 161 ## COMMAND can be the following: 162 ## 163 ## - `alive`: return True if the loop is alive, False otherwise. 164 ## - `control`: shortcut for loop paused? wait. loop dead? break. 165 ## - `dead`: return True if the loop is dead, False otherwise. 166 ## - `exists`: return True if loop has been initialized, False otherwise. 167 ## - `init`: init a new loop control and start it. 168 ## - `pause`: pause the loop. It will wait until resumed or stopped. 169 ## - `resume`: resume the loop. 170 ## - `stop`: definitely stop the loop. 171 ## - `wait`: wait as long as loop is paused. 172 ## \function-argument COMMAND The subcommand to run. 173 ## \function-argument NAME The name of the loop on which to act. 174 ## \function-return ? The return code of the subcommand. 175 ## \function-return 1 When the subcommand is unknown. 176 ## \function-stderr Warning when unknown subcommmand. 177 loop() { 178 __loop_datadir="/tmp/loop" 179 180 ! [ -d "${__loop_datadir}" ] && mkdir "${__loop_datadir}" 181 182 local loop_command="$1" 183 local var="$2" 184 185 case "${loop_command}" in 186 alive) loop_alive "${var}" ;; 187 control) loop_control "${var}" ;; 188 dead) loop_dead "${var}" ;; 189 exists) loop_exists "${var}" ;; 190 init) loop_init "${var}" ;; 191 list) loop_list ;; 192 pause) loop_pause "${var}" ;; 193 paused) loop_paused "${var}" ;; 194 resume) loop_resume "${var}" ;; 195 stop) loop_stop "${var}" ;; 196 wait) loop_wait "${var}" ;; 197 *) 198 echo "loop: unknow command '${loop_command}'" >&2 199 return 1 200 ;; 201 esac 202 }