Afficher Spinner en attendant la fin d'un processus

13

Comment puis-je montrer le spinner jusqu'à ce que la ligne de commande termine son travail? En d'autres termes, si j'exécute un script et que je souhaite afficher le spinner pendant que ce script est en cours d'exécution et que le spinner disparaît lorsque le script a terminé, c'est le travail.

Ci-dessous est un code spinner commun:

i=1
sp="/-\|"
echo -n ' '
while true
do
printf "\b${sp:i++%${#sp}:1}"
done

Comment puis-je lier le code de spinner précédent à une commande pour le laisser afficher spinner pendant que la commande est en cours d'exécution et le spinner disparaît lorsque la commande a terminé, c'est le travail? Si j'inclus la commande dans la boucle, elle bouclera avec le spinner, alors quelle est la solution dans ce cas?


la source

Réponses:

21

Demandez à votre whileboucle de surveiller la sortie de votre commande réelle. Je suppose qu'un environnement Linux a des entrées / proc pour chaque PID, mais vous pouvez le découper d'autres façons:

#!/bin/bash
# your real command here, instead of sleep
sleep 7 &
PID=$!
i=1
sp="/-\|"
echo -n ' '
while [ -d /proc/$PID ]
do
  printf "\b${sp:i++%${#sp}:1}"
done
Jeff Schaller
la source
9
Il s'agit d'une boucle occupée qui consommera des ressources CPU. Je suggère d'avoir un certain retard dans votre boucle while.
ACase
16

Ce script shell devrait faire ce que vous cherchez:

#!/usr/bin/env bash

show_spinner()
{
  local -r pid="${1}"
  local -r delay='0.75'
  local spinstr='\|/-'
  local temp
  while ps a | awk '{print $1}' | grep -q "${pid}"; do
    temp="${spinstr#?}"
    printf " [%c]  " "${spinstr}"
    spinstr=${temp}${spinstr%"${temp}"}
    sleep "${delay}"
    printf "\b\b\b\b\b\b"
  done
  printf "    \b\b\b\b"
}

("$@") &
show_spinner "$!"

En supposant que vous stockiez le script shell dans un fichier nommé spinner, vous pouvez l'invoquer comme ceci pour afficher un spinner pendant l' sleep 10exécution de la commande :

$ spinner sleep 10
jsears
la source
Cela suppose que le script shell est appelé spinner, donc non. Je pense que l'exemple est juste, en supposant que vous nommez le script spinner.
jsears
3

Voici un autre spinner fantaisie que vous pouvez utiliser comme ceci:

spinner ping google.com
echo "ping exited with exit code $?"

spinner sleep 10
echo "sleep exited with exit code $?"

Il a 12 thèmes et en choisit un au hasard.

#!/bin/bash
# Shows a spinner while another command is running. Randomly picks one of 12 spinner styles.
# @args command to run (with any parameters) while showing a spinner. 
#       E.g. ‹spinner sleep 10›

function shutdown() {
  tput cnorm # reset cursor
}
trap shutdown EXIT

function cursorBack() {
  echo -en "\033[$1D"
}

function spinner() {
  # make sure we use non-unicode character type locale 
  # (that way it works for any locale as long as the font supports the characters)
  local LC_CTYPE=C

  local pid=$1 # Process Id of the previous running command

  case $(($RANDOM % 12)) in
  0)
    local spin='⠁⠂⠄⡀⢀⠠⠐⠈'
    local charwidth=3
    ;;
  1)
    local spin='-\|/'
    local charwidth=1
    ;;
  2)
    local spin="▁▂▃▄▅▆▇█▇▆▅▄▃▂▁"
    local charwidth=3
    ;;
  3)
    local spin="▉▊▋▌▍▎▏▎▍▌▋▊▉"
    local charwidth=3
    ;;
  4)
    local spin='←↖↑↗→↘↓↙'
    local charwidth=3
    ;;
  5)
    local spin='▖▘▝▗'
    local charwidth=3
    ;;
  6)
    local spin='┤┘┴└├┌┬┐'
    local charwidth=3
    ;;
  7)
    local spin='◢◣◤◥'
    local charwidth=3
    ;;
  8)
    local spin='◰◳◲◱'
    local charwidth=3
    ;;
  9)
    local spin='◴◷◶◵'
    local charwidth=3
    ;;
  10)
    local spin='◐◓◑◒'
    local charwidth=3
    ;;
  11)
    local spin='⣾⣽⣻⢿⡿⣟⣯⣷'
    local charwidth=3
    ;;
  esac

  local i=0
  tput civis # cursor invisible
  while kill -0 $pid 2>/dev/null; do
    local i=$(((i + $charwidth) % ${#spin}))
    printf "%s" "${spin:$i:$charwidth}"

    cursorBack 1
    sleep .1
  done
  tput cnorm
  wait $pid # capture exit code
  return $?
}

("$@") &

spinner $!
Jonas Eberle
la source
2

Si vous voulez un spinner au plus petit dénominateur commun qui fonctionne avec / bin / sh et ne repose pas sur la substitution de paramètre bash étendue, cela devrait fonctionner:

#!/bin/sh

# The command you are waiting on goes between the ( ) here
# The example below returns a non zero return code

(sleep 20 ; /bin/false) &

pid=$! ; i=0
while ps -a | awk '{print $1}' | grep -q "${pid}"
do
    c=`expr ${i} % 4`
    case ${c} in
       0) echo "/\c" ;;
       1) echo "-\c" ;;
       2) echo "\\ \b\c" ;;
       3) echo "|\c" ;;
    esac
    i=`expr ${i} + 1`
    # change the speed of the spinner by altering the 1 below
    sleep 1
    echo "\b\c"
done

# Collect the return code from the background process

wait ${pid}
ret=$?

# You can report on any errors due to a non zero return code here

exit ${ret}
Rob Bartlett
la source