无论变量内容如何,​​read都返回true

时间:2014-06-23 08:44:27

标签: bash shell

我有以下代码段:

#!/bin/bash
while true; do
    ls "$1"
    exitstatus=$?
    if [[ $exitstatus != 0 ]]; then
        read -n 1 -p "Retry? (y/n)" ch
                    echo
        if [[ ! $ch =~ [Yy] ]]; then
            break
        fi
    fi
    exit $exitstatus
done

执行此脚本表明无论[[ ! $ch =~ [Yy] ]]的内容如何,​​都会执行$ch

$ ./test.sh /foo
ls: cannot access /foo: No such file or directory
Retry? (y/n)y
$ ./test.sh /foo
ls: cannot access /foo: No such file or directory
Retry? (y/n)n
$

我试着评论一些事情,这似乎表明了预期的行为:

#!/bin/bash
while true; do
    #ls "$1"
    #exitstatus=$?
    #if [[ $exitstatus != 0 ]]; then
        read -n 1 -p "Retry? (y/n)" ch
        if [[ ! $ch =~ [Yy] ]]; then
            break
        fi
    #fi
    #exit $exitstatus
done

在shell中执行以上命令:

$ ./test.sh
Retry? (y/n)y
Retry? (y/n)y
Retry? (y/n)n
$ 

在第一种情况下我做错了什么?

2 个答案:

答案 0 :(得分:3)

第一次尝试后,

exit $exitstatus退出循环。它应该在循环之外。

答案 1 :(得分:1)

您有几个逻辑问题:

(1)您要求重试,但如果答案是y,则您从未读过要测试的新文件名,因此它总是会失败。

(2)当你要求重试的时候也很明显,你就这样做了:你在重试时得到了Y,但是然后只是将用户转入break并且你无处可去:)

read -n 1 -p "Retry? (y/n)" ch
    echo
    if [[ ! $ch =~ [Yy] ]]; then  ## testing for y, then we will retry right! - NOPE, just break :(
        break

(3)那些讨厌而真正的循环。考虑你的循环应该打破什么并使用该测试,而不是永远的循环,并希望在正确的位置打破。然而,绕过你的几个逻辑可以让它像这样工作:

#!/bin/bash

## initialize variables
ch=y
srchfile="$1"

## while loop test for Y or y
while [[ $ch == [Yy] ]]; do

    # attempt listing on srchfile
    ls "$srchfile"
    exitstatus=$?

    # if bad exit status, prompt to retry?
    if [[ $exitstatus != 0 ]]; then
        read -n 1 -p "Retry? (y/n)" ch
        echo
        # test for y or Y answer
        if [[ $ch == [^Yy] ]]; then
            break
        fi

        # if retry, read new filename to test
        read -p "Enter a new name for $srchfile : " srchfile
    else
        # that pesky file has been found, let's do something with it!
        printf "You have successfully found file : %srchfile\n"
        printf "(now do something useful with with it)\n"

        break

    fi
done

exit $exitstatus