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
相关产品推荐
相关产品推荐

