一键脚本
bash <(curl -sL gitee.com/meimolihan/cmdbox/raw/master/ops-script/shell-alert-box.sh) "第1行内容" "第2行内容"
bash <(curl -sL ../ops-script/shell-alert-box.sh) "第1行内容" "第2行内容"
效果预览
带警告词版
无警告词版
补充说明
warn_box 是一个用于在终端输出带有装饰边框的警告或提示框的 Bash 函数。该函数会自动计算最长内容行的宽度,根据内容是否包含中文字符自动调整内部宽度(中文/全角算 2 个字符,其它算 1 个字符),并绘制对应的上下横线、左右竖线以及角标字符。支持自定义上下留白行数,以及通过第一个纯数字参数指定留白数量。适用于 Bash 4+ 且环境支持 UTF-8 locale 的系统。
功能特点
- 自动宽度计算:根据内容自动计算显示宽度,中文全角字符计为 2 个宽度
- 可配置上下留白:通过参数指定顶部和底部的空白行数
- 双模式可选:一版带有“警告”黄色边框文字,另一版纯提示洋红色边框无警告词
- 宽度自适应:如果内容宽度小于最小阈值(默认 6),会自动扩展至最小尺寸
- 彩色边框:使用 ANSI 转义序列实现颜色显示(黄色/洋红+白色内容)
- 兼容性好:仅依赖 Bash 内置功能,无需外部工具
参数说明
| 变量 | 默认值 | 说明 |
|---|---|---|
pad |
1 | 上下留白行数;若第一个参数为纯数字,则使用该数值作为留白行数 |
lines |
- | 要显示的内容行,作为剩余参数传入 |
函数调用格式:warn_box [留白行数] "第1行" "第2行" ...
- 如果第一个参数是纯数字,它将被作为上下留白的行数,并从参数列表中移除;
- 否则默认使用 1 行作为上下留白;
- 其余所有参数均作为内容行显示。
用法示例
# 默认用法(1行上下留白,带警告词版)
warn_box \
' 我是第一行内容 ' \
' 我是第二行内容 '
# 指定留白行数
warn_box 2 \
' 内容行 1 ' \
' 内容行 2 ' \
' 内容行 3 '
# 无警告词版(洋红边框)
warn_box 0 \
' 提示内容 1 ' \
' 提示内容 2 '
# 两行留白 + 带警告词
warn_box 2 \
' 警告信息测试 ' \
' 这是第二行 '
注意事项
- 脚本依赖 Bash 4+ 及 UTF-8 locale,若系统 locale 为非 UTF-8,中文宽度计算可能不正确
- 内容行中的特殊字符可能会影响宽度计算结果,建议使用纯文本或简单的 Unicode 字符
- 颜色显示取决于终端是否支持 256 色彩范围,若不支持则会显示为普通文字而非彩色
- 最小框宽度限制为 6 个字符宽,若内容非常短仍会保持最小尺寸
- 该函数在脚本中定义,直接
source或者在终端中复制函数定义后使用
脚本源码
带警告词版(黄色边框 + “警告”)
cat > /tmp/warn_box.sh <<'EOF'
#!/bin/bash
__warn_box_width() {
local s=$1 i c cp width=0
local len=${#s}
for ((i = 0; i < len; i++)); do
c=${s:i:1}
printf -v cp '%d' "'$c" 2>/dev/null || cp=63
if (( (cp>=0x1100 && cp<=0x115F) || (cp>=0x2E80 && cp<=0x303E) || \
(cp>=0x3041 && cp<=0x33FF) || (cp>=0x3400 && cp<=0x4DBF) || \
(cp>=0x4E00 && cp<=0x9FFF) || (cp>=0xA000 && cp<=0xA4CF) || \
(cp>=0xAC00 && cp<=0xD7A3) || (cp>=0xF900 && cp<=0xFAFF) || \
(cp>=0xFE30 && cp<=0xFE6F) || (cp>=0xFF00 && cp<=0xFF60) || \
(cp>=0xFFE0 && cp<=0xFFE6) || (cp>=0x1F300 && cp<=0x1F64F) )); then
width=$((width + 2))
else
width=$((width + 1))
fi
done
printf '%d' "$width"
}
warn_box() {
local gl_huang=$'\033[38;5;11m' # 黄色(边框 + “警告”)
local gl_bai=$'\033[38;5;15m' # 白色(内容)
local reset=$'\033[0m'
local pad=1
if [[ $1 =~ ^[0-9]+$ ]]; then
pad=$1
shift
fi
local lines=("$@")
local max=0 l w
for l in "${lines[@]}"; do
w=$(__warn_box_width "$l")
(( w > max )) && max=$w
done
local W=$max
(( W < 6 )) && W=6
local top_bar bot_bar
printf -v top_bar '%*s' $((W - 6)) ''
top_bar=${top_bar// /─}
printf -v bot_bar '%*s' "$W" ''
bot_bar=${bot_bar// /─}
printf '%s╭ 警告 %s╮%s\n' "$gl_huang" "$top_bar" "$reset"
for ((i = 0; i < pad; i++)); do
printf '%s│%*s│%s\n' "$gl_huang" "$W" "" "$reset"
done
for l in "${lines[@]}"; do
w=$(__warn_box_width "$l")
printf '%s│%s%s%s%*s%s│%s\n' \
"$gl_huang" "$gl_bai" "$l" "$reset" \
$((W - w)) "" "$gl_huang" "$reset"
done
for ((i = 0; i < pad; i++)); do
printf '%s│%*s│%s\n' "$gl_huang" "$W" "" "$reset"
done
printf '%s╰%s╯%s\n' "$gl_huang" "$bot_bar" "$reset"
}
warn_box 0 \
' 我是第一行内容 ' \
' 我是第二行内容 '
EOF
sed -i 's/\r$//'/tmp/warn_box.sh
chmod +x /tmp/warn_box.sh
bash /tmp/warn_box.sh
无警告词版(洋红边框)
cat > /tmp/warn_box.sh <<'EOF'
#!/bin/bash
__warn_box_width() {
local s=$1 i c cp width=0
local len=${#s}
for ((i = 0; i < len; i++)); do
c=${s:i:1}
printf -v cp '%d' "'$c" 2>/dev/null || cp=63
if (( (cp>=0x1100 && cp<=0x115F) || (cp>=0x2E80 && cp<=0x303E) || \
(cp>=0x3041 && cp<=0x33FF) || (cp>=0x3400 && cp<=0x4DBF) || \
(cp>=0x4E00 && cp<=0x9FFF) || (cp>=0xA000 && cp<=0xA4CF) || \
(cp>=0xAC00 && cp<=0xD7A3) || (cp>=0xF900 && cp<=0xFAFF) || \
(cp>=0xFE30 && cp<=0xFE6F) || (cp>=0xFF00 && cp<=0xFF60) || \
(cp>=0xFFE0 && cp<=0xFFE6) || (cp>=0x1F300 && cp<=0x1F64F) )); then
width=$((width + 2))
else
width=$((width + 1))
fi
done
printf '%d' "$width"
}
warn_box() {
local gl_bai=$'\033[38;5;15m' # 白色(内容)
local gl_zi=$'\033[38;5;13m' # 洋红(边框)
local reset=$'\033[0m'
local pad=1
if [[ $1 =~ ^[0-9]+$ ]]; then
pad=$1
shift
fi
local lines=("$@")
local max=0 l w
for l in "${lines[@]}"; do
w=$(__warn_box_width "$l")
(( w > max )) && max=$w
done
local W=$max
(( W < 1 )) && W=1
local bar
printf -v bar '%*s' "$W" ''
bar=${bar// /─}
printf '%s╭%s╮%s\n' "$gl_zi" "$bar" "$reset"
for ((i = 0; i < pad; i++)); do
printf '%s│%*s│%s\n' "$gl_zi" "$W" "" "$reset"
done
for l in "${lines[@]}"; do
w=$(__warn_box_width "$l")
printf '%s│%s%s%s%*s%s│%s\n' \
"$gl_zi" "$gl_bai" "$l" "$reset" \
$((W - w)) "" "$gl_zi" "$reset"
done
for ((i = 0; i < pad; i++)); do
printf '%s│%*s│%s\n' "$gl_zi" "$W" "" "$reset"
done
printf '%s╰%s╯%s\n' "$gl_zi" "$bar" "$reset"
}
warn_box 0 \
' 我是第一行内容 ' \
' 我是第二行内容 '
EOF
sed -i 's/\r$//'/tmp/warn_box.sh
chmod +x /tmp/warn_box.sh
bash /tmp/warn_box.sh
创建本地脚本
new_script="new_test.sh"
cat > "$new_script" << 'EOF'
# 粘贴脚本源码
EOF
# 保留本地脚本,去掉 rm -f "$new_script"
chmod +x "$new_script" && ./"$new_script" && rm -f "$new_script"