Differences between revisions 9 and 16 (spanning 7 versions)
Revision 9 as of 2015-05-15 07:49:57
Size: 1237
Editor: geirha
Comment: printf instead of echo -n, and avoid embedding parameter expansion inside printf's format string
Revision 16 as of 2023-10-26 18:03:57
Size: 1593
Editor: emanuele6
Comment: check exit status of sleep, and avoid repetition of sleep command
Deletions are marked like this. Additions are marked like this.
Line 6: Line 6:
i=0
sp="/-\|"
n=${#sp}
printf ' '
while true; do
# Bash, with GNU sleep
spin() {
  local
i=0
  local sp='/-\|'
  local n=${#sp}
  printf ' '
  while sleep 0.1; do
Line 12: Line 14:
done   done
}
Line 19: Line 22:
If you want it to slow down, put a {{{sleep}}} command inside the loop (after the printf). To slow it down, the `sleep` command is included inside the loop (after the `printf`).
Line 24: Line 27:
sp='/-\|'
printf ' '
while true; do
# POSIX sh
spin() {
  
sp='/-\|'
  printf ' '
  while sleep 1; do
Line 29: Line 34:
done   done
}
Line 32: Line 38:
If you already have a loop which does a lot of work, you can call the following function at the beginning of each iteration to update the spinner: One way to use these spinners in a script is to run them as background processes, and kill them when you're done. For example,
Line 34: Line 41:
sp="/-\|" # POSIX sh
spin & spinpid=$!
# long-running commands here
kill "$spinpid"
}}}

If you already have a loop which does a lot of work, you can write a function that "advances" the spinner one step at a time, and call it at the beginning of each iteration:

{{{
# Bash
sp='/-\|'
Line 36: Line 53:
sn=${#sp}
Line 37: Line 55:
   printf "\b${sp:sc++:1}"
   ((sc==${#sp})) && sc=0
  printf '\b%s' "${sp:sc++%sn:1}"
Line 41: Line 58:
   printf "\r%s\n" "$@"   printf '\r%s\n' "$*"

Can I do a spinner in Bash?

Sure!

# Bash, with GNU sleep
spin() {
  local i=0
  local sp='/-\|'
  local n=${#sp}
  printf ' '
  while sleep 0.1; do
    printf '\b%s' "${sp:i++%n:1}"
  done
}

Each time the loop iterates, it displays the next character in the sp string, wrapping around as it reaches the end. (i is the position of the current character to display and ${#sp} is the length of the sp string).

The \b string is replaced by a 'backspace' character. Alternatively, you could play with \r to go back to the beginning of the line.

To slow it down, the sleep command is included inside the loop (after the printf).

A POSIX equivalent would be:

# POSIX sh
spin() {
  sp='/-\|'
  printf ' '
  while sleep 1; do
    printf '\b%.1s' "$sp"
    sp=${sp#?}${sp%???}
  done
}

One way to use these spinners in a script is to run them as background processes, and kill them when you're done. For example,

# POSIX sh
spin & spinpid=$!
# long-running commands here
kill "$spinpid"

If you already have a loop which does a lot of work, you can write a function that "advances" the spinner one step at a time, and call it at the beginning of each iteration:

# Bash
sp='/-\|'
sc=0
sn=${#sp}
spin() {
    printf '\b%s' "${sp:sc++%sn:1}"
}
endspin() {
    printf '\r%s\n' "$*"
}

until work_done; do
   spin
   some_work ...
done
endspin

A similar technique can be used to build progress bars.


CategoryShell

BashFAQ/034 (last edited 2023-10-26 18:03:57 by emanuele6)