Linux PS3 环境变量详解

PS3 是什么?

PS3Third Prompt String)是 第三提示符,专门用于 select 命令的菜单提示符。它控制交互式菜单选择时显示的提示信息。

基本语法

select 变量 in 选项列表
do
    命令
done

默认设置

# 默认 PS3 值
#?   (井号问号加空格)

基础示例

1. 简单菜单

PS3="请选择一个数字: "
select opt in "苹果" "香蕉" "橙子" "退出"
do
    case $opt in
        "苹果") echo "你选择了苹果";;
        "香蕉") echo "你选择了香蕉";;
        "橙子") echo "你选择了橙子";;
        "退出") break;;
        *) echo "无效选择";;
    esac
done

输出:

1) 苹果
2) 香蕉
3) 橙子
4) 退出
请选择一个数字: 

2. 查看当前 PS3

echo $PS3
echo "$PS3"

自定义 PS3 示例

1. 简单提示

export PS3="请输入选项编号: "

# 或永久设置
echo 'export PS3="请输入选项编号: "' >> ~/.bashrc

2. 带颜色的 PS3

# 绿色提示
export PS3=$'\033[32m请选择 > \033[0m'

# 黄色带箭头
export PS3=$'\033[33m➤ 请选择: \033[0m'

# 使用 $'...' 语法支持转义序列
export PS3=$'\e[1;36m选择编号: \e[0m'

3. 包含变量信息的 PS3

# 显示当前用户名
export PS3="你好 $USER,请选择: "

# 显示时间
export PS3="$(date '+%H:%M') 请选择: "

4. 多行 PS3

export PS3=$'\\n===============\n请选择编号: '

完整应用示例

示例 1:文件操作菜单

#!/bin/bash
# menu.sh

PS3="请选择操作: "
options=("列出文件" "查看日期" "创建目录" "退出")

select opt in "${options[@]}"
do
    case $REPLY in
        1)
            ls -la
            ;;
        2)
            date
            ;;
        3)
            echo "输入目录名: "
            read dirname
            mkdir "$dirname"
            ;;
        4)
            echo "再见!"
            break
            ;;
        *)
            echo "无效选项 $REPLY"
            ;;
    esac
done

示例 2:系统信息菜单

#!/bin/bash

PS3=$'\033[1;34m选择功能:\033[0m '
echo "=== 系统管理菜单 ==="

select cmd in \
    "显示系统信息" \
    "显示磁盘使用" \
    "显示内存信息" \
    "显示登录用户" \
    "退出"
do
    case $cmd in
        "显示系统信息")
            uname -a
            ;;
        "显示磁盘使用")
            df -h
            ;;
        "显示内存信息")
            free -h
            ;;
        "显示登录用户")
            who
            ;;
        "退出")
            echo "退出菜单"
            break
            ;;
        *)
            echo "无效选择,请输入 1-5"
            ;;
    esac
    echo ""
done

示例 3:带默认值的菜单

#!/bin/bash

PS3="选择水果 (默认1): "
fruits=("苹果" "香蕉" "橙子" "葡萄")

# 设置默认选择
DEFAULT=1

select fruit in "${fruits[@]}"
do
    # 如果直接回车,使用默认值
    if [[ -z "$REPLY" ]]; then
        REPLY=$DEFAULT
    fi
    
    case $REPLY in
        1|2|3|4)
            echo "你选择了: $fruit"
            echo "编号是: $REPLY"
            ;;
        *)
            echo "无效选择: $REPLY"
            continue
            ;;
    esac
    break
done

高级用法

1. 动态 PS3

#!/bin/bash

# PS3 根据菜单内容变化
menu_items=("开始" "停止" "重启" "状态")
PS3="服务操作 (1-${#menu_items[@]}): "

select item in "${menu_items[@]}"
do
    echo "执行: $item"
    break
done

2. 嵌套菜单

#!/bin/bash

main_menu() {
    PS3="主菜单 > "
    select main_opt in "系统" "网络" "退出"
    do
        case $main_opt in
            "系统")
                system_menu
                ;;
            "网络")
                network_menu
                ;;
            "退出")
                exit 0
                ;;
        esac
    done
}

system_menu() {
    local PS3="系统菜单 > "
    select sys_opt in "CPU信息" "内存信息" "返回"
    do
        case $sys_opt in
            "CPU信息")
                lscpu
                ;;
            "内存信息")
                free -h
                ;;
            "返回")
                return
                ;;
        esac
    done
}

network_menu() {
    local PS3="网络菜单 > "
    select net_opt in "IP地址" "网络连接" "返回"
    do
        case $net_opt in
            "IP地址")
                ip addr show
                ;;
            "网络连接")
                ss -tuln
                ;;
            "返回")
                return
                ;;
        esac
    done
}

main_menu

3. 带验证的菜单

#!/bin/bash

PS3="选择 (输入数字或名称): "

options=("选项一" "选项二" "选项三")

while true; do
    select opt in "${options[@]}" "退出"
    do
        case $opt in
            "退出")
                echo "再见!"
                exit 0
                ;;
            "")
                echo "无效选择: $REPLY"
                echo "可用选项:"
                for i in "${!options[@]}"; do
                    echo "$((i+1))) ${options[$i]}"
                done
                ;;
            *)
                echo "你选择了: $opt"
                # 执行相关操作
                ;;
        esac
        break
    done
done

PS3 的特殊变量

在 select 循环中,这些变量很有用:

变量含义
$REPLY用户输入的内容(字符串)
$opt 或 $变量名选择的选项文本
${#array[@]}选项数量

实用技巧

1. 重新显示菜单

#!/bin/bash

show_menu() {
    echo "=== 菜单 ==="
    select item in "选项1" "选项2" "退出"
    do
        case $item in
            "选项1") echo "执行选项1";;
            "选项2") echo "执行选项2";;
            "退出") break;;
            *) echo "无效选择"; continue;;
        esac
        # 执行后暂停,按回车继续显示菜单
        read -p "按回车继续..."
        return 1  # 触发重新显示菜单
    done
}

PS3="请选择: "
while show_menu; do
    :  # 空循环
done

2. 使用数组动态生成菜单

#!/bin/bash

# 动态获取目录中的文件
files=(*.txt)
if [ ${#files[@]} -eq 0 ]; then
    echo "没有找到txt文件"
    exit 1
fi

PS3="选择要编辑的文件: "
select file in "${files[@]}" "退出"
do
    case $file in
        "退出")
            break
            ;;
        "")
            echo "无效选择"
            ;;
        *)
            nano "$file"
            ;;
    esac
done

3. 处理空格和特殊字符

#!/bin/bash

# 使用 IFS 控制分隔符
IFS=$'\n'  # 按换行分割

PS3="选择: "
options=(
    "包含空格 的选项"
    "普通选项"
    "特殊&字符"
)

select opt in "${options[@]}"
do
    echo "选择了: '$opt'"
    break
done

IFS=$' \t\n'  # 恢复默认

故障排除

1. PS3 颜色不显示?

# 错误:普通字符串不支持转义
PS3="\033[31m提示\033[0m"  # 不会显示颜色

# 正确:使用 $'...' 语法
PS3=$'\033[31m提示\033[0m'

# 或使用 echo -e
PS3=$(echo -e "\033[31m提示\033[0m")

2. 菜单显示不正常?

# 确保选项是数组
options=("第一项" "第二项" "第三项")  # 正确
options="第一项 第二项 第三项"        # 错误

# 正确使用
select opt in "${options[@]}"  # 正确
select opt in $options         # 错误

3. 用户输入非数字?

PS3="请选择: "
select opt in "A" "B" "C"
do
    # $REPLY 包含用户输入的原始内容
    if ! [[ "$REPLY" =~ ^[0-9]+$ ]]; then
        echo "请输入数字"
        continue
    fi
    
    if [ "$REPLY" -lt 1 ] || [ "$REPLY" -gt 3 ]; then
        echo "请输入 1-3"
        continue
    fi
    
    echo "你选择了: $opt"
    break
done

与其他提示符的比较

特性PS3 (select菜单)PS1 (主提示符)PS2 (继续提示符)PS4 (调试提示符)
主要用途交互式菜单选择普通命令输入多行命令继续调试模式跟踪
显示时机select命令执行时每次命令前命令未完成时set -x 调试时
常用自定义菜单操作提示个性化命令行继续输入提示调试信息前缀
默认值#?\u@\h:\w\$>+

最佳实践

  1. 明确提示:让用户清楚需要做什么

    PS3="请输入选项编号 (1-3): "
    
  2. 添加颜色:提高可读性(但不要过度)

    PS3=$'\e[1;33m选择: \e[0m'
    
  3. 包含上下文:可以显示当前状态

    PS3="[$USER@$(hostname)] 选择: "
    
  4. 保持简洁:提示符不要太长

    # 好
    PS3="> "
    
    # 不好(太长)
    PS3="请从以下选项中选择一个合适的操作编号: "
    
  5. 考虑国际化:如果需要多语言支持

    if [ "$LANG" = "zh_CN.UTF-8" ]; then
        PS3="请选择: "
    else
        PS3="Please select: "
    fi
    

实际应用场景

  1. 配置脚本菜单
  2. 安装程序选项
  3. 系统管理工具
  4. 交互式设置向导
  5. 数据选择界面

我的推荐配置

# 简洁实用的 PS3
export PS3=$'\033[1;36m选择 > \033[0m'

# 或带边框的版本
export PS3=$'\n\033[1;37m[\033[1;33m?\033[1;37m]\033[0m 选择编号: '

PS3 是创建用户友好交互脚本的强大工具,合理使用可以大大提升脚本的易用性!

更多推荐