11

I am looking for a script that creates a rotation animation using character /,-, | and \.

If you continuously switch between these characters it should look like its rotating. How to make this?

Anonymous Platypus
  • 3,730
  • 10
  • 33
  • 51

4 Answers4

24

Use that script:

#!/bin/bash

chars="/-\|"

while :; do
  for (( i=0; i<${#chars}; i++ )); do
    sleep 0.5
    echo -en "${chars:$i:1}" "\r"
  done
done

The while loop runs infinite. The for loop runs trough each character of the string given in $chars. echo prints the character, with a carriage return \r, but without linebreak -n. -e forces echo to interpret escape sequences such as \r. There's a delay of 0.5 seconds between each change.

chaos
  • 27,106
  • 12
  • 74
  • 77
  • Clever, +1, but why not `printf "%s\r" "${chars:$i:1}"`? – terdon May 15 '15 at 17:26
  • 1
    @terdon first thought was `echo`... but of course `printf` works too. ^^ – chaos May 15 '15 at 18:09
  • You can try it without the for loop: `chars="/-\|"; while sleep 0.5; do echo -en "${chars:$(( i=(i+1) % ${#chars} )):1}" "\r"; done` – eitan Mar 09 '21 at 16:47
  • The `offset` and `length` parts of `${var:offset:length}` are already arithmetic expressions, so we can remove some of the syntax: `echo -en "${chars: i = (i + 1) % ${#chars} : 1}"` – glenn jackman Nov 16 '22 at 14:57
22

Here's an example using \b, which tells the terminal emulator to move the cursor one column to the left, in order to keep overwriting the same character over and over.

#!/usr/bin/env bash

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

printf 'Doing important work '
spinner &

sleep 10  # sleeping for 10 seconds is important work

kill "$!" # kill the spinner
printf '\n'

See BashFAQ 34 for more.

CelticParser
  • 231
  • 2
  • 4
  • 8
geirha
  • 45,233
  • 13
  • 70
  • 67
  • 7
    Great code. I would make one small modification, though. After running `spinner &`, I would store the pid in a local variable `spinner_pid=$!` and then replace the kill call with `kill $spinner_pid &>/dev/null` – dberm22 May 15 '15 at 13:04
  • I would like to add `tput civis #hide cursor` and `tput cnorm #show cursor` – Ishtiyaq Husain May 21 '20 at 20:00
1

very minimal way of writing using printf

sh-5.1$ while true ; do for i in \\ "|" / "-"; do printf "$i" ; sleep 0.1 ; printf "\b" ; done ; done
1

Since you don't explicitly ask for bash, a little plug for the fish shell, where this can be solved beautifully IMO:

set -l symbols ◷ ◶ ◵ ◴
while sleep 0.5
    echo -e -n "\b$symbols[1]"
    set -l symbols $symbols[2..-1] $symbols[1]
end

In this case, symbols is an array variable, and the contents if it are rotated/shifted, because $symbols[2..-1] are all entries but the first.

Pompei2
  • 111
  • 2