创建 Bash 旋转器

作者:Mitch Frazier

您知道字符序列 "/-\|/-\|" 是做什么用的吗?这是一个基于文本的旋转器。仍然感到困惑,请继续阅读。

您可能已经见过一些长时间运行的控制台程序,它们在运行时会显示一个旋转器。旋转器就是前面提到的字符序列,一个接一个地在屏幕上的同一位置输出,并在每个字符之间暂停。本文中的代码创建了一个在单独进程中运行的旋转器。通过这样做,旋转器以恒定的速率旋转,并且在您的脚本暂停时不会暂停。它还消除了在程序中散布旋转器输出消息的需要。

此外,旋转器从主进程创建的日志文件中读取内容,并在旋转器旁边显示日志文件的最后一行。当日志文件消失时,旋转器退出。

这是主进程的脚本,名为 runner.sh

#!/bin/bash

logfile=/tmp/mylog

echo >$logfile
trap "rm -f $logfile" EXIT

# Output message to log file.
function log_msg()
{
    echo "$*" >>$logfile
}


# Start spinner
sh spinner.sh &

# Perform really long task.
i=0
log_msg "Starting a really long job"
while [[ $i -lt 100 ]]
do
    sleep 1
    let i+=5
    log_msg "$i% complete"
done

sleep 1
echo

顶部的函数用于将消息输出到日志文件。日志文件在程序的顶部初始化为空文件,输出函数将其附加到该文件。

在进入其主循环之前,主进程在后台启动旋转器。之后,它只是暂停一下,输出一条状态消息,然后重复直到它 100% 完成。

以下是旋转器进程

#!/bin/bash

logfile=/tmp/mylog
logsize=0
spinpause=0.10
linelen=0


# Output last line from log file.
function lastout()
{
    local line=$(tail -n 1 $logfile 2>/dev/null)
    if [[ "$line" ]]; then
        echo -n "     $line"

        # Erase any extra from last line.
        local len
        let len=$linelen-${#line}
        while [[ $len -gt 0 ]]
        do
            echo -n " "
            let len--
        done
        linelen=${#line}
    fi
}

# Output a spin character.
function spinout()
{
    local spinchar="$1"
    local sz
    local ll
    if [[ -f $logfile ]]; then
        echo -n -e "\r$spinchar"
        sleep $spinpause

        # Check for new message.
        sz=$(stat --printf '%s' $logfile 2>/dev/null)
        if [[ $sz -gt $logsize ]]; then
            lastout
            logsize=$sz
        fi
    fi
}

if [[ -f $logfile ]]; then
    logsize=$(stat --printf '%s' $logfile 2>/dev/null)
    if [[ $logsize -gt 0 ]]; then
        echo -n " "
        lastout
    fi

    while [[ -f $logfile ]]
    do
        spinout "/"
        spinout "-"
        spinout "\\"
        spinout "|"
        spinout "/"
        spinout "-"
        spinout "\\"
        spinout "|"
    done
    echo
fi

旋转器包含两个函数。第一个函数输出日志文件的最后一行。由于日志文件行始终放置在同一屏幕行上,因此新的日志行可能比上一条日志行短。因此,在输出新行后,该函数会输出空格,直到达到前一条日志行的长度,以便将其完全擦除。

第二个函数输出一个旋转器字符,并暂停字符间的暂停时间。它在旋转器字符之前添加一个回车符,以便所有内容都保留在同一行上。输出旋转器字符后,它会检查自上次输出行以来日志文件的大小是否增加。如果增加了,它会输出新的一行。

旋转器的主循环一个接一个地输出每个旋转器字符。

观看随附的视频以查看其运行情况。

Mitch Frazier 是 Emerson Electric Co. 的嵌入式系统程序员。自 2000 年代初期以来,Mitch 一直是 Linux Journal 的贡献者和朋友。

加载 Disqus 评论