选择案例无法按预期工作

时间:2011-04-21 03:37:42

标签: linux shell select menu case

我写了这个案例选择陈述拒绝工作,我无法弄清楚我做错了什么。任何帮助表示赞赏。感谢。

echo; echo "Did you see a display?"
select YN in "yes" "no" ; do
    case $YN in
        yes)
            echo "$2 at $X x $Y @$REF Hz">>/root/ran.log
            break   
        ;;
        no)
            echo "$2 at $X x $Y @$REF Hz">>/root/didntrun.log
            break   
        ;;
    esac
done

这是代码的这部分的bash -x输出。 #?在屏幕上重复多次并跳过提示用户并跳转到代码的下一部分。

+ echo 'Did you see a display?'
Did you see a display?
+ select yn in '"yes"' '"no"'
1) yes
2) no
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? + case $yn in
#? 

编辑:想象一下,因为在从文件中读取行的循环之间调用了选择代码。将stdin更改为文件会导致select跳过用户提示并尝试从文件读取。现在我需要一种解决方法。

编辑2: 这是调用fnUseResolution函数的代码,其中包含select语句。

res.log在格式中的每一行都有分辨率,例如1920 1080 60

FILE=res.log
BAKIFS=$IFS
IFS=$(echo -en "\n\b")
exec 3<&0
exec 0<$FILE
while read -r LINE
do
    fnUseResolution $LINE app1
    fnUseResolution $LINE app2
    fnUseResolution $LINE app3
done
exec 0<&3
IFS=$BAKIFS

2 个答案:

答案 0 :(得分:2)

这对我来说很好,它会停止并允许我输入12

请参阅以下成绩单:

pax$ cat qq.sh
echo "Did you see a display?"
select YN in "yes" "no" ; do
    case $YN in
        yes)
            echo YES
            break   
        ;;
        no)
            echo NO
            break   
        ;;
    esac
done

pax$ ./qq.sh
Did you see a display?
1) yes
2) no
#? 1
YES

pax$ ./qq.sh
Did you see a display?
1) yes
2) no
#? 2
NO

pax$ _

您确定此时标准输入已连接到您的终端吗?


由于您已经确认我怀疑您的标准输入未连接到终端,因此 通过摆弄文件句柄来修复它是一种有点棘手的方法。

考虑以下代码,它执行您在注释中指定的内容(调用函数接受来自已重定向标准输入的循环内的标准输入):

fn() {
    echo "Did you see a display?"
    select YN in "yes" "no" ; do
        case $YN in
            yes)
                echo YES $YN $REPLY
                break
            ;;
            no)
                echo NO $YN $REPLY
                break
            ;;
        esac
    done
}

echo 'A
B
C
D' | while read ; do
    echo $REPLY
    fn
    echo ====
done

如果您运行此代码,您将看到:

A
Did you see a display?
1) yes
2) no
#? #? #? #? 
=====

这表明输入是在两个读者while readselect之间混合的。

解决这个问题的诀窍是通过更改代码来解除两个读者的关联:

(echo 'A
B
C
D' | while read ; do
    echo $REPLY
    fn <&4
done) 4<&0

这个输出是:

A
Did you see a display?
1) yes
2) no
#? 1                         <- my input.
YES yes 1
=====
B
Did you see a display?
1) yes
2) no
#? 2                         <- my input.
NO no 2
=====
C
Did you see a display?
1) yes
2) no
#? 1                         <- my input.
YES yes 1
=====
D
Did you see a display?
1) yes
2) no
#? 2                         <- my input.
NO no 2
=====

这样做(以它自己的可怕方式)是启动一个子shell来运行你的整个事情,诀窍是子shell首先连接当前标准输入(可能是终端)到文件处理4供以后使用。

子shell中,运行正常的while read循环,将标准输入(文件处理程序0)更改为从echo语句中读取。

但是这里的诀窍是:当你调用你的函数时,你告诉它从文件句柄4而不是当前文件句柄0获取它的标准输入。因为它连接到保存的原始标准输入,它赢了“从while read标准输入(echo的输出)得到任何东西。

这可能需要一些时间来包裹你的脑袋(我记得第一次看到这个时我不得不从地板上摘下脑袋,因为我的头部爆炸了)。但是,一旦你了解它是如何工作的,你就会看到它的优雅: - )

这个输出是:

A
Did you see a display?
1) yes
2) no
#? 1
YES yes 1
=====
B
Did you see a display?
1) yes
2) no
#? 2
NO no 2
=====
C
Did you see a display?
1) yes
2) no
#? 1
YES yes 1
=====
D
Did you see a display?
1) yes
2) no
#? 2
NO no 2
=====

而且,基于你的代码,可能一个好的起点是围绕整个批次以保留标准输入,如:

(FILE=res.log
BAKIFS=$IFS
IFS=$(echo -en "\n\b")
exec 3<&0
exec 0<$FILE
while read -r LINE
do
    fnUseResolution $LINE app1 <&4
    fnUseResolution $LINE app2 <&4
    fnUseResolution $LINE app3 <&4
done
exec 0<&3
IFS=$BAKIFS) 4<&0

我假设你的功能是fnUseResolution

但是,在查看该代码时,为read而不是select使用不同的文件句柄可能更简单,因为您可以比我想象的更能控制它。

试试:

FILE=res.log
BAKIFS=$IFS
IFS=$(echo -en "\n\b")
#exec 3<&0
exec 4<$FILE
while read -u 4 -r LINE
do
    fnUseResolution $LINE app1
    fnUseResolution $LINE app2
    fnUseResolution $LINE app3
done
#exec 0<&3
IFS=$BAKIFS

-u 4选项读取它以使用文件句柄4而不是0,我更改了exec以匹配它。我没有测试过,但它应该正常工作。

通过这样做,你永远不会改变标准输入,所以在功能中它应该没问题。此外,在这种情况下,没有理由在文件句柄3中保存/恢复它,因此我已经对这些exec调用进行了评论。

答案 1 :(得分:0)

这应该有用; Bash将用户响应返回给变量$ REPLY。 如果您输入“是”或“否”,这将起作用。

echo; echo "Did you see a display?"
select YN in "yes" "no" ; do
    case $REPLY in
        yes)
            echo "$2 at $X x $Y @$REF Hz">>/root/ran.log
            break   
        ;;
        no)
            echo "$2 at $X x $Y @$REF Hz">>/root/didntrun.log
            break   
        ;;
        *)
            echo "blah! blah! $REPLY"
            break
    esac
done