Last active
December 19, 2024 23:04
-
-
Save StrangeRanger/12e9b8292dc0d499a4fea42fdda93c03 to your computer and use it in GitHub Desktop.
spinning-waiting-stick.sh
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
#!/usr/bin/env bash | |
# | |
# Sometimes, it's helpful to show users that a background process is running and the | |
# script is awaiting its completion. A common approach is to display a spinner in the | |
# terminal until the process finishes. This script offers two methods to implement such | |
# a spinner, catering to different needs and scenarios. | |
# | |
######################################################################################## | |
####[ Global Variables ]################################################################ | |
## Used to colorize output. | |
C_GREEN="$(printf '\033[0;32m')" | |
C_BLUE="$(printf '\033[0;34m')" | |
C_NC="$(printf '\033[0m')" | |
C_CLRLN="$(printf '\r\033[K')" | |
readonly C_GREEN C_BLUE C_NC C_CLRLN | |
## Short-hand colorized messages. | |
readonly C_SUCCESS="${C_GREEN}==>${C_NC} " | |
readonly C_INFO="${C_BLUE}==>${C_NC} " | |
# The number of iterations to run in each loop. | |
readonly C_STOP_AT=1000000 | |
# Enable debugging output. | |
readonly DEBUG=true | |
####[ Functions ]####################################################################### | |
#### | |
# This version of the spinning stick will wait for a specific process to finish running | |
# before it stops spinning. | |
# | |
# WHEN TO USE: | |
# This version of the spinning stick is ideal when you want to wait for a specific | |
# process to finish running before continuing with the rest of the script. | |
# | |
# PARAMETERS: | |
# - $1: pid (Required) | |
# - The process ID of the process that the spinning stick will be waiting for. | |
spinner_one() { | |
local pid="$1" | |
local spin='-\|/' | |
local i=0 | |
## While the specified process is running, output a new character from the $spin | |
## variable to create the illusion of a spinning stick. | |
while kill -0 "$pid" 2>/dev/null; do | |
i=$(( (i+1) % 4 )) | |
# ${parameter:offset:length} -> ${spin:$i:1} | |
printf "%sPerforming action: %s" "$C_CLRLN" "${spin:$i:1}" | |
sleep 0.1 | |
done | |
} | |
#### | |
# This version of the spinning stick will continue to spin until the function is stopped | |
# or killed. | |
# | |
# WHEN TO USE: | |
# This version of the spinning stick is ideal when you want to display a spinning | |
# stick as a background process. This is great when you need to perform a task where | |
# modifications to a variable must persist. | |
spinner_two() { | |
local spin='-\|/' | |
local i=0 | |
## Continuously output a new character from the $spin variable to create the | |
## illusion of a spinning stick. | |
while true; do | |
i=$(( (i+1) % 4 )) | |
# ${parameter:offset:length} -> ${spin:$i:1} | |
printf "%sPerforming action: %s" "$C_CLRLN" "${spin:$i:1}" | |
sleep 0.1 | |
done | |
} | |
####[ Main ]############################################################################ | |
### | |
### [ Example of Using 'spinner_one' ] | |
### | |
### In the following example, I run a loop that will increment a variable from 0 to | |
### 1,000,000. This loop will run as a subprocess in the background. The 'spinner_one' | |
### function will display a spinning stick that will continue to spin until the | |
### subprocess is finished running. | |
### | |
iteration=0 | |
echo -e "${C_INFO}Executing 'spinner_one'" | |
[[ "$DEBUG" == true ]] && start_time=$(date +%s%N) | |
## Operations that will run in the background, while the spinning stick is displayed. | |
{ | |
for ((i = 0; i <= C_STOP_AT; i++)); do | |
iteration="$i" | |
done | |
printf "%sOutput of 'iteration': %s\n" "$C_CLRLN" "${C_GREEN}${iteration}${C_NC}" | |
} & | |
spinner_one "$!" | |
if [[ "$DEBUG" == true ]]; then | |
end_time=$(date +%s%N) | |
elapsed=$(( (end_time - start_time)/1000000 )) | |
echo -e "${C_SUCCESS}Done with 'spinner_one' in ${elapsed} ms\n" | |
else | |
echo -e "${C_SUCCESS}Done with 'spinner_one' example\n" | |
fi | |
### | |
### [ Example of Using 'spinner_two' ] | |
### | |
### In the following example, I run a loop that will increment a variable from 0 to | |
### 1,000,000. Compared to the previous example, the 'spinner_two' function will run in | |
### the background instead of the operations. This is because I want the changes to the | |
### 'iteration' variable to persist. | |
### | |
iteration=0 | |
echo -e "${C_INFO}Executing 'spinner_two'" | |
[[ "$DEBUG" == true ]] && start_time=$(date +%s%N) | |
# Start the spinner. | |
spinner_two & | |
spinner_pid=$! | |
# Main workload runs in the main shell. | |
for ((i = 0; i <= C_STOP_AT; i++)); do | |
iteration="$i" | |
done | |
# Work is done; stop the spinner. | |
kill "$spinner_pid" 2>/dev/null | |
wait "$spinner_pid" 2>/dev/null | |
# Clean up and output the result. | |
printf "%sOutput of 'iteration': %s\n" "$C_CLRLN" "${C_GREEN}${iteration}${C_NC}" | |
if [[ "$DEBUG" == true ]]; then | |
end_time=$(date +%s%N) | |
elapsed=$(( (end_time - start_time)/1000000 )) | |
echo "${C_SUCCESS}Done with 'spinner_two' in ${elapsed} ms" | |
else | |
echo -e "${C_SUCCESS}Done with 'spinner_two' example\n" | |
fi |
Author
StrangeRanger
commented
Jun 7, 2021
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment