You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash缓动文字函数首次调用变量加载延迟,终端颜色显示异常求助

问题:Bash函数首次调用时颜色转义序列不生效,第二次正常

我写了一个Bash函数,用ease_in_expo缓动函数逐字符显示文本,同时用tput定义的终端颜色渲染文本。但函数仅在第二次调用时正常显示颜色,首次调用时终端会直接输出转义序列而非彩色文本。

原代码

#!/usr/bin/env bash

# Easing function: ease_in_expo
ease_in_expo() {
    local t=$1
    echo "scale=4; if ($t == 0) 0 else 1 * e(10 * ($t - 1))" | bc -l
}

animate_text_with_ease_in_expo() {
    text="$1"
    delay="$2"

    # Regular Colors
    RESET=$(tput sgr0)         # Text Reset
    BLACK=$(tput setaf 0)      # Black
    RED=$(tput setaf 1)        # Red
    GREEN=$(tput setaf 2)      # Green
    YELLOW=$(tput setaf 3)     # Yellow
    BLUE=$(tput setaf 4)       # Blue
    PURPLE=$(tput setaf 5)     # Purple
    CYAN=$(tput setaf 6)       # Cyan
    WHITE=$(tput setaf 7)      # White

    for ((i = 0; i < ${#text}; i++)); do
        progress=$(ease_in_expo "$((i + 1)) / ${#text}")
        sleep "$(echo "$delay * $progress" | bc -l)"

        # Write the string to output
        echo -n "${text:$i:1}"
    done
}

animate_text_with_ease_in_expo "Tutti ${RED}frutti${RESET}, oh ${CYAN}rooty${RESET}; A wop bop b-luma b-lop bam ${GREEN}boom." 0.30

现象

  • 首次通过. string-problem.sh调用时,输出为:
    Tutti \033[0;31mfrutti, oh \033[0;36mrooty; A wop bop b-luma b-lop bam boom.
    
  • 第二次在当前shell中手动调用animate_text_with_ease_in_expo ...时,文本正常显示对应颜色。

原因

当用source(.)方式加载脚本时,函数调用的参数会在脚本加载阶段被解析,但此时颜色变量(${RED}等)是在函数内部定义的,还未被赋值。因此首次调用时,参数中的${RED}只是被当作普通字符串传递,没有被替换为tput生成的ANSI转义序列。而第二次调用时,函数已经执行过一次,颜色变量已被定义在当前shell环境中,参数中的变量会被正确展开。

修复方案

将颜色变量的定义移到函数外部,让脚本加载时就初始化这些变量,这样函数调用参数中的颜色变量会在调用前就被正确替换:

#!/usr/bin/env bash

# 提前定义颜色变量,脚本加载时即执行tput生成转义序列
RESET=$(tput sgr0)         # Text Reset
BLACK=$(tput setaf 0)      # Black
RED=$(tput setaf 1)        # Red
GREEN=$(tput setaf 2)      # Green
YELLOW=$(tput setaf 3)     # Yellow
BLUE=$(tput setaf 4)       # Blue
PURPLE=$(tput setaf 5)     # Purple
CYAN=$(tput setaf 6)       # Cyan
WHITE=$(tput setaf 7)      # White

# Easing function: ease_in_expo
ease_in_expo() {
    local t=$1
    echo "scale=4; if ($t == 0) 0 else 1 * e(10 * ($t - 1))" | bc -l
}

animate_text_with_ease_in_expo() {
    text="$1"
    delay="$2"

    for ((i = 0; i < ${#text}; i++)); do
        # 替换整数除法为浮点除法,确保progress计算正确
        progress=$(ease_in_expo "$(echo "scale=4; ($i + 1) / ${#text}" | bc -l)")
        sleep "$(echo "$delay * $progress" | bc -l)"

        # Write the string to output
        echo -n "${text:$i:1}"
    done
    # 添加换行,避免光标停在文本末尾
    echo
}

animate_text_with_ease_in_expo "Tutti ${RED}frutti${RESET}, oh ${CYAN}rooty${RESET}; A wop bop b-luma b-lop bam ${GREEN}boom." 0.30

额外修复说明

原代码中progress=$(ease_in_expo "$((i + 1)) / ${#text}")存在整数除法问题:$((...))会丢弃小数部分,当i+1小于文本长度时,结果始终为0,导致缓动函数完全失效。修复后改用bc做浮点除法,确保progress能正确生成0到1之间的数值,让缓动效果正常工作。

内容的提问来源于stack exchange,提问作者broen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 17:42:22