我正在比较的一个或两个字符串值有问题吗?

时间:2019-11-06 04:36:14

标签: bash

我正在尝试使用二进制搜索来显示学生的成绩(如果他们在数组中)。搜索没有问题,但是,显然我没有正确比较条件语句中的数据。无论输入什么名称,elif都会运行。我所比较的至少一个值似乎存在问题。 这是存储在数组中的内容:

Ann:A
Bob:C
Cindy:B
Dean:F
Emily:A
Frank:C
Ginger:D
Hal:B
Ivy:A
Justin:F
Karen:D 

这是我的剧本。

#!/bin/bash

# Create array from student list
studentArray=($(cat ./studentList.dat))

# Ask for student name
echo "Enter Student Name"
studentName=$(read)

# variable to store if a student has been found 
studentFound="false"
# variable to store student grade
studentGrade=""

# start and end index of the studentArray
START=0
END=$((${#studentArray[@]}-1))


# binary search
while [ "$START" -le "$END" ]; do
 MIDDLE=$((START+((END-START)/2)))
 middleItem=$(echo ${studentArray[$MIDDLE]} | cut -d: -f1)

 if [ "$studentName" = "$middleItem" ]; then
  studentFound="true"
  studentGrade=$(echo ${studentArray[$MIDDLE]} | cut -d: -f2)
  break
 elif [[ "$studentName" < "$middleItem" ]]; then
  ((END=MIDDLE-1))
 else
  ((START=MIDDLE+1)) 
 fi
done

if [ "$studentFound" == "true" ]; then
 echo $studentGrade
else
 echo "Sorry, there is no student by that name"
fi

2 个答案:

答案 0 :(得分:2)

此修复程序的简短版本:studentName=$(read)不起作用,请改用read -r studentName

更长的修复程序,包括一些指针:

  • 使用

    将文件读取到数组中
    mapfile -t studentArray < studentList.dat
    

    这避免了您可能会看到的未引用扩展名带来的意外。

  • echoread可以在Bash中组合:

    read -rp "Enter Student Name: " studentName
    

    -r是为了避免反斜杠的解释,而-p可让您指定提示。

  • 避免使用所有大写的变量名:它们更可能与shell和环境变量冲突。而且,Bash具有提供算术上下文的条件构造:

    while ((start <= end)); do
        middle=$((start + (end-start)/2))
        ...
    
  • 要获取用冒号分隔的字符串的第一部分,可以使用参数扩展:

    middleItem=${studentArray[middle]%:*}
    

    请注意,由于索引是算术上下文,因此不需要$

  • 冒号分隔的字符串的第二部分也是如此:

    studentGrade=${studentArray[middle]#*:}
    

总而言之:

#!/usr/bin/env bash

# Create array from student list
mapfile -t studentArray < studentList.dat

# Ask for student name
read -rp "Enter Student Name: " studentName

# Variable to store if a student has been found
studentFound="false"

# Start and end index of the studentArray
start=0
end=$((${#studentArray[@]} - 1))

# Binary search
while ((start <= end)); do
    middle=$((start + ((end - start) / 2)))
    middleItem=${studentArray[middle]%:*}

    if [[ $studentName == "$middleItem" ]]; then
        studentFound="true"
        studentGrade=${studentArray[middle]#*:}
        break
    elif [[ $studentName < $middleItem ]]; then
        ((end = middle - 1))
    else
        ((start = middle + 1))
    fi
done

if [[ $studentFound == "true" ]]; then
    echo "$studentGrade"
else
    echo "Sorry, there is no student by that name"
fi

答案 1 :(得分:1)

该代码错误地使用了read。读取功能将一行读入变量,并且不打印输入行。因此,studentName=$(read)将studentName设置为“

建议的解决方法:

read studentName

旁注:使用脚本执行的最简单的操作之一是在顶部添加'set -x',或使用bash -vx script ...调用脚本。这将提供逐行的信息(包括变量分配),使识别问题变得容易。对于上述脚本,输出将为:

+ studentArray=($(cat ./studentList.dat))
++ cat ./studentList.dat
+ echo 'Enter Student Name'
Enter Student Name
++ read
Hal
    <-- Error here -->
+ studentName=
+ studentFound=false
+ studentGrade=

显示的StudentName设置不正确。