If-Then-Else语句中的Grep语句未给出预期结果

时间:2015-03-06 04:09:45

标签: unix grep ksh

该程序的预期结果是通过搜索姓氏从临时文件中删除记录。如果名称在文件中,它将显示一条消息,表明该记录已从文件中删除。该邮件将包含已删除人员的姓氏和名字。如果输入的名称没有记录,则显示一条错误消息,指出该名称不在文件中。错误消息将包含搜索人员的姓氏。

在大多数情况下,我完全想出了这个代码。但是,我遇到的错误给我带来了很多麻烦。

代码如下:

#While loop
            delete_choice="y"           
            until [[ $delete_choice == "n" ]]
            do
            #Create Delete Message
            clear
            echo "                                 Delete Record                                 "
            echo -en '\n'
            echo -en '\n'
            echo "What is the last name of the person you want to delete:"
            read last_name
            if line=$( grep -Fi "$last_name" "$2")
            then
            IFS=: read c1 c2 rest <<< "$line"
            echo -e "Last Name: $c1\nFirst Name: $c2\nSTUDENT RECORD HAS BEEN DELETED FROM FILE"
            sed "/$line/d" $2
            else
            echo "ERROR: $last_name is not in database"
            echo "Would you like to search again (y/n)"
            read delete_choice
            fi
            done
        ;;

那么当我执行此代码时会发生什么,它会显示删除消息并要求我输入姓氏。我输入了一个姓氏&#34; smith&#34;,当我这样做时,它会跳过整个if语句并直接进入循环结束然后让我直接询问我的姓氏是什么我要删除的人。显然它集中在某个地方的grep语句中。另一个奇怪的事情是,如果我输入一个我知道不在其中的名称,它会将我带到else语句并给我错误消息并询问我是否要再次搜索。

任何帮助都会受到赞赏,我一直在用grep声明搜索几个小时,但无法弄明白。

另外:在旁注上有人知道怎么做,所以我可以输入&#34; n&#34;或&#34; N&#34;在Until ... Do语句中保持循环?

修改

好的,我修复了此代码中的所有其他问题,但只有一个问题我无法修复。每次我从文件中删除一个条目时,它都不允许我执行echo命令。

代码如下:

d|D)
            #While loop
            delete_choice="y"       
            while true
            do
                #Create Delete Message
                clear
                echo "                                 Delete Record                                 "
                echo -en '\n'
                echo -en '\n'
                echo "What is the last name of the person you want to delete:"
                read last_name
                if line=$(grep -i "^${last_name}:" "$2")
                then
                    echo "$line" |
                    while IFS=: read c1 c2 rest; do
                        last=$c1
                        first=$c2
                        sed -i "/^$c1:$c2:/d" "$2"
                    done
                    echo -e "Last Name: $last\nFirst Name: $first\nSTUDENT RECORD HAS BEEN DELETED FROM FILE"
                else
                    echo "ERROR: $last_name is not in database"
                    echo "Would you like to search again (y/n):"
                    read delete_choice
                    case $delete_choice in [Nn]) break;; esac
                fi
            done
        ;;

正如您所看到的,我执行了echo命令,但它从未显示过。但是,我可以告诉它,当我退出程序并检查它时,它会从文件中删除该条目。有人知道如何正确显示echo命令吗?

1 个答案:

答案 0 :(得分:0)

您使用的是<<<,这是一种仅限Bash功能。

调试问题的正确方法是使用ksh -x script arg(或者如果您的脚本是纯Bourne shell脚本可能sh -x script arg运行脚本;但这个脚本不是。< / p>

但是,您的代码中有一些特殊之处。请允许我提供重构。

delete_choice="y"           
until [[ "$delete_choice" == "n" ]]
do           # Indent your control structures
    clear
    echo "                                 Delete Record"
    echo # Massive trailing whitespace removed ----------^^^
    echo # Just echo to output a new line
    echo "What is the last name of the person you want to delete:"
    read last_name
    case $last_name in [Nn]) break;; esac      # Exit on "n"
    if line=$(grep -Fi "$last_name" "$2")
    then     # Indent your control structures
        file=$2
        oldIFS=$IFS
        IFS=:
        set -- "$line"   # break input into $1, $2, etc
        IFS=$oldIFS
        echo -e "Last Name: $1\nFirst Name: $2\nI SCREAM IN UPPER CASE"
        sed -i "/^$1:$2:/d" "$file"   # note quoting and -i and changed variable
    else
        echo "ERROR: $last_name is not in database"
        echo "Would you like to search again (y/n)"
        read delete_choice
    fi
done

这里的另一个问题与你的问题无关。在正则表达式中直接执行用户的输入会非常粗心 - 如果有人仅为a输入姓氏怎么办?无论输入有多短,更改后的代码都只会删除一个用户;但也许grep也应该锚定使用更严格的搜索表达式。

数据库中的特殊名称仍有可能与自身不匹配,或者与自身匹配得更多。例如,我使用我的第二个名字,所以在我的全名需要的地方,我经常输入我的名字为&#34; First * Middle Last&#34;在我使用的名字旁边有一个星号,这是我居住的惯例;但是字符串*Middle在正则表达式中不会匹配。

此外,如果没有-ised脚本只会将数据库的副本打印到标准输出。

delete_choice变量未在代码中的任何位置更新,因此您可以将外部循环更改为while true并通过突破循环来处理退出,就像我所做的那样。我没有改变until这个模糊的推测,即你可能会在代码的其他部分中使用它,而这些部分你并没有显示出来。