Select 在循环中不要求输入

Select in loop don't ask for input

我想循环提问(例如,要求确认处理目录中的每个文件)。

这段代码完美运行:

PS3="Dummy question ? "
select CHOICE_MADE in "Ans1" 'Ans2' 'Ans3'; do
    if [[ -n ${CHOICE_MADE} ]]; then
        printf "Choice made : %s\n" "${CHOICE_MADE}"
        break;
    fi
done

我需要循环这个问题(注意我在循环中命名变量,以避免使用默认的 $REPLY 变量):

while read -r TOTO; do
    PS3="Dummy question ? "
    select CHOICE_MADE in Ans1 Ans2 Ans3; do
        if [[ -n ${CHOICE_MADE} ]]; then
            printf "Choice made : %s\n" "${CHOICE_MADE}"
            break;
        fi
    done
done < <(echo Step1 Step2)

Select 不提示任何内容。

我不想使用 whiptail(屏蔽脚本先前的输出)、对话框(需要在 debian 上安装)或任何图形用户界面。

我知道我可以使用 read 来解决我的问题,但我想保持 select 循环。

在此先感谢您的帮助。

你必须注意两件事才能让它发挥作用。

1) `stdin` 使用不当

首先,将 < (echo Step1 Step2) 传递给您的 while 循环,您正在使用 stdin,这就是提示根本不等待任何输入的原因(它已经有!)。

您可以使用 file descriptors:

来摆脱它
exec 3< <(echo Step1 Step2) ### Create fd "3" and put output of echo in it
while read -r TOTO <&3; do
    PS3="Dummy question ? "
    select CHOICE_MADE in Ans1 Ans2 Ans3; do
        if [[ -n ${CHOICE_MADE} ]]; then
            printf "Choice made : %s\n" "${CHOICE_MADE}"
            break
        fi
    done
done
exec 3>&- ### clean fd 3

其余代码我保持不变。

2) `read` 的错误使用

你要想到的另一件事是,read -r会逐行读取你给他的内容,而一个简单的echo Step1 Step2只会产生一行,所以你会循环只是一次。

为了摆脱这种不需要的行为,您将不得不使用其他解决方案。

目前我能想到的一个解决方案是heredoc:

exec 3<< EOF
Step1
Step2
EOF
while read -r TOTO <&3; do
    PS3="Dummy question ? "
    select CHOICE_MADE in Ans1 Ans2 Ans3; do
        if [[ -n ${CHOICE_MADE} ]]; then
            printf "Choice made: %s\n" "${CHOICE_MADE}"
            break
        fi
    done
done
exec 3>&- ### clean fd 3

请注意,不建议使用多个 heredoc,最佳实践建议改用实际文件,因为脚本应该包含逻辑,而不是数据。