等待某些进程完成时显示微调器

等待某些进程完成时显示微调器

如何显示微调器直到命令行完成它的工作?换句话说,如果我正在运行一个脚本,并且我想在该脚本运行时显示微调器,并且当脚本完成时微调器会消失,这是工作。

下面是一个常见的微调器代码:

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

如何将以前的微调器代码链接到命令,以使其在命令运行时显示微调器,并在命令完成工作时微调器消失?如果我在循环中包含该命令,它将与微调器一起循环,那么这种情况下的解决方案是什么?

答案1

让你的while循环监视你真正的退出命令。我假设 Linux 环境中每个 PID 都有 /proc 条目,但您可以通过其他方式对其进行切片:

#!/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

答案2

这是另一个精美的旋转器,您可以像这样使用:

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

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

# or, to check out the themes quickly
while spinner sleep 1; do echo; done

它有 12 个主题,并随机选择一个。

#!/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"
  # Mac compatible, but goes back to first column always. See comments
  #echo -en "\r"
}

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 $!

答案3

这个 shell 脚本应该可以满足您的要求:

#!/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 "$!"

假设您将 shell 脚本存储在名为 的文件中spinner,则可以像这样调用它以在命令sleep 10运行时显示微调器:

$ spinner sleep 10

答案4

有一些奇特的旋转器,我敢打赌每个答案都是正确的,尤其是@Jeff Schaller 的,但就我个人而言,作为一名开发人员,我喜欢能够阅读代码并确切地知道发生了什么。当我启动终端时,我想要一个 bash 脚本将所有 git 存储库复制到临时 zip 中,我还想要一个很酷的微调器来配合它,我不确定我的代码是否是最紧凑的,但它绝对有效很好,而且很简单易读。

我不是 bash 最了解的人,但我认为最大的问题是

  • 在后台运行 while 循环(可能对 CPU 来说成本很高,但谁知道呢?)
  • 我仍然可以移动光标,这很烦人
  • 如果我想要多个过程发生,我不知道该怎么做
function runCommand() { 
    load &                                             # calls the loading function
    local whilePID=$!                                  # gets the pid for the loop
    tar -czf ${zipFileToUpdate} ${directoryToBackUp} & # backs up files
    local backupPID=$!                                 # get's back up pid
    wait $backupPID                                    # waits for backup id
    kill $whilePID                                     # kills the while loop
    echo -ne "done"                                    # echos done and removes the spinner
}

function load() { # just a function to hold the spinner loop, here you can put whatever
    while true; do
        echo -ne "/\r"
        sleep .1
        echo -ne "-\r"
        sleep .1
        echo -ne "\ \r"
        sleep .1
        echo -ne "|\r"
        sleep .1
    done
}

runCommand

^ 谈到我提到的关于多个命令的最后一个问题,我想我个人会将所有命令放在一个函数中,然后在后台运行该函数,但它们可能有一堆不同的 PID

经验:

function allCommands() {
    command1;
    command2;
    command3;
    ...;
}

然后在runCommands()函数中

function runCommand() { 
    load &                                             # calls the loading function
    local whilePID=$!                                  # gets the pid for the loop
    allCommands &                                      # run function w/ all cmds
    local allCmdPID=$!
    ...
}

该变量allCmdPID可能与命令切换不同,您可能会等待第一个命令,然后终止加载循环,而其他命令仍在运行。可能的解决方法是:

  • 在 for 循环中获取命令数组
  • 获取命令的pid
  • 等一下
  • 然后继续执行下一个命令

但这一切看起来非常乏味。

相关内容