Есть ли проблема с одним или обоими сравниваемыми строковыми значениями? - PullRequest
0 голосов
/ 06 ноября 2019

Я пытаюсь использовать бинарный поиск, чтобы отобразить оценку ученика, если он находится в массиве. В моем поиске нет проблем, однако я, по-видимому, неправильно сравниваю данные в моих условных утверждениях. 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 ]

2 голосов
/ 06 ноября 2019

Очень короткая версия исправления: studentName=$(read) не работает, вместо этого используйте read -r studentName.

Более длинное исправление, включая несколько указателей:

  • чтение файла в массив с использованием

    mapfile -t studentArray < studentList.dat
    

    Это позволяет избежать неожиданностей от раскрытия без кавычек, которое вы могли бы увидеть в противном случае.

  • echo и read могутбыть объединенным в Bash:

    read -rp "Enter Student Name: " studentName
    

    -r позволяет избежать интерпретации обратной косой черты, а -p позволяет указать приглашение.

  • Избегать всех переменных в верхнем регистреимена: они чаще конфликтуют с переменными оболочки и окружения. Кроме того, 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 голос
/ 06 ноября 2019

Код использует read неправильно. Функция чтения считывает строку в переменную (и) и не печатает строку ввода. Поэтому studentName=$(read) установите studentName на ''

Предлагаемое исправление:

read studentName

Примечание: одна из самых простых вещей, которые можно сделать со сценарием, это добавить 'set -x' кtop или вызовите скрипт с помощью 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 не был установлен правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...