Bash脚本仅在终端宽度变化时生成表格边框失效问题求助
问题描述
这段Bash脚本是每秒循环执行的一部分,目标是生成适配终端宽度的三列表格顶部边框:终端窗口大小变化时重新生成边框,宽度不变时直接复用之前生成的边框变量以提升绘制效率。但目前函数的else分支无法正常输出内容,变量似乎无法在下次循环中被保留,核心难点是需要用函数参数作为变量名存储边框,供后续循环读取。
核心问题分析
- 变量作用域问题:原脚本中用
eval创建的变量默认是函数局部变量,循环每次调用函数时局部变量会被销毁,下次循环无法读取到之前存储的边框值;即使尝试过declare -g也被注释掉了,导致全局变量未成功创建。 - 初始值处理问题:第一次循环时
term_width为空,term_width_previous没有被初始化,导致table_resized的判断逻辑在第一次执行时异常,后续循环的宽度对比也受影响。
修复方案
1. 确保边框变量为全局变量
替换原脚本中创建变量的代码,用declare -g直接创建全局变量,替代不安全的eval:
# 替换原有的eval或注释的declare行 declare -g "$border_id"="$border_value"
这样函数内部创建的变量会被提升到全局作用域,下次循环调用函数时能直接读取到之前存储的值。
2. 修正终端宽度的初始对比逻辑
在循环开始处初始化term_width_previous,避免第一次循环时变量为空:
# 初始化上一次终端宽度(第一次循环时用当前值) term_width_previous=${term_width_previous:-$(tput cols)} # 获取当前终端宽度 term_width=$(tput cols) # 判断是否调整过大小 table_resized=$([ "$term_width" != "$term_width_previous" ] && echo "yes" || echo "no")
3. 优化边框生成效率(可选)
用printf的格式化功能替代循环生成重复字符,代码更简洁高效:
比如生成第一列横线可以改成:
border_value+=$(printf "%${col1_width}s" "" | tr ' ' '═')
修正后的完整脚本片段
# 初始化上一次终端宽度(第一次循环时用当前值) term_width_previous=${term_width_previous:-$(tput cols)} # 获取终端宽度 term_width=$(tput cols) # 判断自上次循环后终端是否调整大小 table_resized=$([ "$term_width" != "$term_width_previous" ] && echo "yes" || echo "no") # 根据终端宽度计算列宽 col1_width=16 col2_width=16 col3_width=$((term_width - col1_width - col2_width - 13)) # 13为填充和边框占用宽度 col4_width=10 # 语法:print_table_border "id" "左边框字符" "列文本或═" print_table_border() { border_id=$1 if [ "$table_resized" = "yes" ]; then border_value="" border_value+=$(printf " ") border_value+=$(printf "$2") ## 左边框 # 第一列 - 显示文本或横线 if [ "$3" = "═" ]; then # 用printf+tr替代循环生成横线 border_value+=$(printf "%${col1_width}s" "" | tr ' ' '═') else col1_text=$3 col1_text_length="${#col1_text}" border_value+=$(printf " $col1_text") # 计算剩余空格数并填充 remaining_spaces=$((col1_width - col1_text_length - 1)) border_value+=$(printf "%${remaining_spaces}s" "") fi border_value+=$(printf "$4") border_value+=$(printf "%${col2_width}s" "" | tr ' ' "$5") border_value+=$(printf "$6") # 第三列横线 third_col_length=$((term_width - col1_width - col2_width - 6)) border_value+=$(printf "%${third_col_length}s" "" | tr ' ' "$7") border_value+=$(printf "$8") border_value+=$(printf " \n") # 创建全局变量存储边框 declare -g "$border_id"="$border_value" printf "%s" "${!border_id}" # 打印生成的行 else # 打印存储的全局变量内容 printf "%s" "${!border_id}" # 打印存储的行 fi } print_table_border "sm_top_border" "╔" "═" "╦" "═" "╦" "═" "╗" # 循环末尾更新上一次宽度 term_width_previous=$term_width
内容的提问来源于stack exchange,提问作者saltedlolly
相关产品推荐
相关产品推荐

