Anna_Repina
@Anna_Repina
Хочу все знать

Почему не отрабатывает exit на третьем уровне скрипта?

Добрый день!
Столкнулись со след. проблемой:
Написали многоуровневое меню при помощи функций, работает без проблем все, кроме выхода.
Примерно на 2-3 уровне меню "Exit" не выходит из скрипта, а возвращается на уровень выше.

Вырезки самих функций прикрепляю ниже по порядку
#!/bin/bash
unem() {
echo -ne "
Choose :
  --------------------------------------- \n | $(ColorGreen '1')          System settings          | \n  ---------------------------------------
  --------------------------------------- \n | $(ColorGreen '2')          Ipmi tools               | \n  ---------------------------------------
  --------------------------------------- \n | $(ColorGreen '3')          Back to previous         | \n  ---------------------------------------
  --------------------------------------- \n | $(ColorGreen '0')          Exit                     | \n  ---------------------------------------
$(ColorBlue 'Choose an option :            ') "
        read b
        case $b in
          1) clear ; ./1_1_system_menu.sh; unem ;;
          2) clear; ./1_1_ipmi_menu.sh ; unem ;;
          3) clear ; menu ;;
          0) exit 0 ;;
        esac
}
unem


Переходим в Ipmi tools

#!/bin/bash
Sens(){
        echo " "
                echo -ne  $(ColorGreen '_SENSORS__')
        echo " "
}

MOFRU(){
        echo " "
                echo -ne  $(ColorGreen '_MOTHER FRU__')
        echo " "
}

BMAC(){
        echo " "
                echo -ne  $(ColorGreen '_BMC MAC__')
        echo " "
}

MMAC(){
        echo " "
                echo -ne  $(ColorGreen '_MOTHER MAC__')
        echo " "
}


############
PMI() {
echo -ne "
  --------------------------------------- \n | $(ColorGreen '1)')     Sensors check                 | \n  ---------------------------------------
  --------------------------------------- \n | $(ColorGreen '2)')Writing Motherboard FRU information| \n  ---------------------------------------
  --------------------------------------- \n | $(ColorGreen '3)')     Writing MAC address  BMC      | \n  ---------------------------------------
  --------------------------------------- \n | $(ColorGreen '4)')  Wtiting MAC address Motherboard  | \n  ---------------------------------------
  --------------------------------------- \n | $(ColorGreen '5)')     Back to previous              | \n  ---------------------------------------
  --------------------------------------- \n | $(ColorGreen '0)')     Exit                          | \n  ---------------------------------------
$(ColorBlue 'Choose an option :            ') "
        read g
        case $g in
          1) clear ; Sens ;;
          2) clear ; MOFRU ;;
          3) clear ; BMAC ;;
          4) clear ; MMAC ;;
          5) clear ; unem ;;
          0) exit;;
        esac
}
PMI


Нажав тут 0 не произойдет ожидаемого выхода из скрипта, а будет возврат в предыдущую менюшку.

Как исправить данную ошибку?
  • Вопрос задан
  • 125 просмотров
Пригласить эксперта
Ответы на вопрос 2
jcmvbkbc
@jcmvbkbc
"I'm here to consult you" © Dogbert
Написали многоуровневое меню при помощи функций, работает без проблем все, кроме выхода.
Примерно на 2-3 уровне меню "Exit" не выходит из скрипта, а возвращается на уровень выше.

всё зависит от того, как эти функции вызываются. Если так:

clear; ./1_1_ipmi_menu.sh ; unem ;;

то разумеется вызов exit внутри скрипта 1_1_ipmi_menu.sh приведёт в возврату в unem, вы же тут отдельный процесс создаёте.
Чтобы exit в функциях приводил к выходу из приложения нужно импортировать (source) функции из этих скриптов и вызывать функции вместо запуска скриптов.
Типа того:
#!/bin/bash
unem() {
        read b
        case $b in
          1) clear ; … ; unem ;;
          2) clear; PMI ; unem ;;
          3) clear ; menu ;;
          0) exit 0 ;;
        esac
}
source 1_1_ipmi_menu.sh
source 1_1_system_menu.sh
unem
Ответ написан
Комментировать
3vi1_0n3
@3vi1_0n3
Я могу предположить, что такая структура скриптов призвана обеспечить определенную независимость каждого подменю. Если брать ровно те скрипты, которые у вас есть, то:
1. Добавляем код возрата в функцию PMI - просто добавляем строчку "return $g" после "esac". Это не сломает существующий скрипт. Но! Придется разбираться с ошибками выполнения вызовов IPMI меню отдельно.
2. Проверяем код возврата в unem
read b
        case $b in
          1) clear ; ./1_1_system_menu.sh && exit; unem ;;
          2) clear; ./1_1_ipmi_menu.sh && exit; unem ;;
          3) clear ; menu ;;
          0) exit 0 ;;
        esac

" && exit" здесь выполнится, если скрипт возвращает 0, что и произойдет, если PMI() вернет 0. Соответственно, при выборе любого другого варианта выхода не будет.

Однако, несмотря на то, что с такими минимальными изменениями оно может работать как надо, все-таки имеет смысл сделать так, как jcmvbkbc уже упомянул - не исполнять скрипты, а включать их. Я не согласен по поводу места в скрипте, куда их включать, я бы поставил source до определения функции unem.
И я лично сделал бы это несколько по-другому. Как-то так:

menu.sh
#!/bin/bash

# Insert necessary sub-menus
. ./ipmi_menu.sh

declare -A MAINITEMS
MAINITEMS['System settings']="echo 'System settings selected'"
MAINITEMS['Ipmi tools']="PMI"
MAINITEMS['Back to previous']="break"
MAINITEMS['Exit']="exit"

while :
do
  select menuitem in "${!MAINITEMS[@]}"
  do
    echo "Menu item: $menuitem"
    ${MAINITEMS[$menuitem]}
  done
done

ipmi_menu.sh
#!/bin/bash

PMI(){
echo "PMI functions"

PMI_TITLES=(\
        "Sensors check" \
        "Writing Motherboard FRU information"\
        "Writing MAC address  BMC"\
        "Wtiting MAC address Motherboard"\
        "Back to previous"\
        "Exit")
PMIITEMS[1]="echo Sensors check"
PMIITEMS[2]="echo fru information"
PMIITEMS[3]="echo mac address"
PMIITEMS[4]="echo mac address motherboard"
PMIITEMS[5]="break"
PMIITEMS[6]="exit"

select pmiitem in "${PMI_TITLES[@]}"
do
  ${PMIITEMS[$REPLY]}
done
}


В menu.sh я использую associative array, это сильно упрощает добавление элементов в главное меню.

В ipmi_menu.sh я использую обычный массив, чтобы соблюсти порядок пунктов меню. Тут PMIITEMS[XXX] будет просто имя функции, содержащейся в файле ipmi_menu.sh

В этом примитивном варианте экран не очищается и перерисовка пунктов текущего меню происходит по нажатию ENTER, зато это должно (по идее) работать в любом, даже самом тупом терминале. Если надо красоты, можно select поменять на echo+read, смысл от этого не поменяется, все равно можно брать список функций из массива.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы