5.2.3 读取输入与用户交互(read、select)

读取输入与用户交互(read、select)#

1. 原理与输入流示意#

文章图片

2. read 基本用法与命令解释#

  • read var:从标准输入读取一行赋值给变量
  • echo:输出变量内容
#!/usr/bin/env bash
# file: /tmp/read_basic.sh
read name
echo "Hello, $name"

执行:

bash /tmp/read_basic.sh
# 输入: alice
# 预期输出: Hello, alice

3. read 常用参数与完整示例(含默认值/超时/静默)#

  • -p 提示信息
  • -t 超时秒数
  • -s 静默输入(密码)
  • -n 读取指定字符数
  • -r 禁止反斜杠转义
#!/usr/bin/env bash
# file: /tmp/read_params.sh

read -p "请输入用户名: " user
read -s -p "请输入密码: " pass
echo
read -t 5 -p "5秒内输入环境(dev/prod): " env
read -n 1 -p "是否继续(y/n): " yn
echo

env=${env:-dev}
echo "user=$user env=$env yn=$yn"

执行:

bash /tmp/read_params.sh
# 预期输出示例: user=alice env=dev yn=y

4. 多变量读取、空输入处理与校验#

#!/usr/bin/env bash
# file: /tmp/read_multi.sh

read -p "输入 host port user: " host port user
host=${host:-127.0.0.1}
port=${port:-3306}

# 简单格式校验:端口是否为数字
if ! [[ "$port" =~ ^[0-9]+$ ]]; then
  echo "端口必须为数字" >&2
  exit 1
fi

echo "host=$host port=$port user=$user"

执行:

bash /tmp/read_multi.sh

5. 从管道或文件读取(逐行处理)#

#!/usr/bin/env bash
# file: /tmp/read_file.sh

while read -r line; do
  echo "line: $line"
done < /etc/hosts

执行:

bash /tmp/read_file.sh

6. select 菜单选择(交互菜单示例)#

  • select 自动生成编号菜单
  • PS3 自定义提示符
#!/usr/bin/env bash
# file: /tmp/select_menu.sh

PS3="请选择环境: "
select env in dev test prod quit; do
  case $env in
    dev|test|prod)
      echo "选择: $env"
      break
      ;;
    quit)
      echo "退出"
      break
      ;;
    *)
      echo "无效选项"
      ;;
  esac
done

执行:

bash /tmp/select_menu.sh
# 输入序号,如 1

7. 组合示例:交互式部署参数采集脚本#

#!/usr/bin/env bash
# file: /tmp/deploy_input.sh

read -p "服务名(service): " svc
read -p "端口(port,默认8080): " port
port=${port:-8080}

PS3="部署环境: "
select env in dev test prod quit; do
  case $env in
    dev|test|prod) break;;
    quit) exit 0;;
    *) echo "无效选项";;
  esac
done

if ! [[ "$port" =~ ^[0-9]+$ ]]; then
  echo "端口非法: $port" >&2
  exit 2
fi

echo "准备部署: service=$svc port=$port env=$env"

执行:

bash /tmp/deploy_input.sh

8. 常见排错与定位#

  • 脚本卡住不继续:检查是否等待输入
    bash strace -p <PID> 2>&1 | tail -n 3 # 若看到 read(...),说明等待输入
  • read 读取不到管道内容:避免在子 shell 中丢失变量
    bash # 错误示例:管道会创建子 shell,变量不回传 echo "a" | while read -r line; do var="$line"; done echo "$var" # 空 # 正确做法:使用重定向 while read -r line; do var="$line"; done < /tmp/file
  • 含反斜杠的路径被转义:使用 -r
    bash read -r path

9. 练习题#

  1. 编写脚本:输入用户名与端口,端口非数字则提示错误并退出。
  2. 编写菜单:选择 start/stop/restart/quit,选择后输出对应动作。
  3. /etc/hosts 读取每行,统计非注释行数量并输出。