You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Bash脚本的read-while循环改写成支持单字符无回车输入的select菜单

Bash单选交互实现方案与代码优化

核心需求结论

Bash内置的select命令默认依赖行缓冲输入,必须按回车确认,无法原生支持read -n1的无回车单字符输入效果,强行结合需要修改终端属性,反而会增加不必要的复杂度,因此最优方案是优化现有read逻辑,而非切换到select实现。

原始代码问题梳理

  • 外层while true循环无实际作用:所有case分支都直接break,循环仅执行1次
  • 大量重复代码:4个选项中有3个重复定义了wmstream3
  • 存在隐性bug:选项1的wmpos变量未赋值就直接使用
  • 无效输入逻辑不合理:原始代码中输入无效后直接break,不会重新提示用户输入

优化后的实现代码(推荐)

wmstream1="[2:v]lut=a=val*0.7,fade=in:st=5:d=2:alpha=1,fade=out:st=$length1:d=2:alpha=1[v2];"
wmstream2="[v2][tmp2]scale2ref=w=oh*mdar:h=ih*0.1[wm_scaled][video];"
# 提前定义默认值(对应选项1的右上角位置)
wmpos="W-w-50:50"

# 循环直到收到有效输入
while true; do
    read -n1 -p $'Select watermark position:\n1) Top right\n2) Top left\n3) Bottom left\n4) None\n' ans
    echo # 输入后自动换行优化显示
    case $ans in
        1)
            echo "WARNING: defaulting to top-right position."
            break
            ;;
        2)
            echo "Positioning watermark at top left."
            wmpos="50:50"
            break
            ;;
        3)
            echo "Positioning watermark at bottom left."
            wmpos="50:H-h-50"
            break
            ;;
        4)
            echo "Disabling watermark."
            unset wmstream1 wmstream2
            wmstream3="[tmp2]setsar=1[outv];"
            # 直接退出循环,不执行后面的通用wmstream3赋值
            break 2
            ;;
        *)
            echo "Invalid option selected. Select a valid number."
            # 不break,循环重新提示输入
            ;;
    esac
done

# 通用wmstream3赋值,仅选项1/2/3会执行到这里
[[ -v wmstream1 ]] && wmstream3="[video][wm_scaled]overlay=$wmpos:format=auto:shortest=1[outv];"

优化点说明

  • 把无用的外层循环调整为输入校验循环,无效输入时会重新提示用户选择,符合正常交互逻辑
  • 提前定义wmpos默认值,修复原始代码选项1的变量未定义bug
  • 把重复的wmstream3赋值提取到循环外,减少冗余代码
  • 简化变量unset写法,支持一次unset多个变量

强制使用select实现单字符输入的方案(不推荐)

如果确实要使用select结构,可以通过修改终端属性实现无回车输入,实现代码如下:

wmstream1="[2:v]lut=a=val*0.7,fade=in:st=5:d=2:alpha=1,fade=out:st=$length1:d=2:alpha=1[v2];"
wmstream2="[v2][tmp2]scale2ref=w=oh*mdar:h=ih*0.1[wm_scaled][video];"
wmpos="W-w-50:50"

# 保存原有终端配置,关闭行缓冲和回显
old_stty=$(stty -g)
stty -icanon -echo

PS3="Select watermark position: "
select opt in "Top right" "Top left" "Bottom left" "None"; do
    # 直接读取单字符作为选项编号
    REPLY=$(dd bs=1 count=1 2>/dev/null)
    case $REPLY in
        1)
            echo "WARNING: defaulting to top-right position."
            wmstream3="[video][wm_scaled]overlay=$wmpos:format=auto:shortest=1[outv];"
            break
            ;;
        2)
            echo "Positioning watermark at top left."
            wmpos="50:50"
            wmstream3="[video][wm_scaled]overlay=$wmpos:format=auto:shortest=1[outv];"
            break
            ;;
        3)
            echo "Positioning watermark at bottom left."
            wmpos="50:H-h-50"
            wmstream3="[video][wm_scaled]overlay=$wmpos:format=auto:shortest=1[outv];"
            break
            ;;
        4)
            echo "Disabling watermark."
            unset wmstream1 wmstream2
            wmstream3="[tmp2]setsar=1[outv];"
            break
            ;;
        *)
            echo "Invalid option selected. Select a valid number."
            ;;
    esac
done

# 恢复终端默认属性
stty "$old_stty"

该方案需要手动维护终端属性,脚本异常退出时可能导致终端输入异常,因此无特殊需求不建议使用。


内容的提问来源于stack exchange,提问作者Hashim Aziz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 12:06:03