LINUX.ORG.RU

Облагородить логику bash-скрипта

 


1

1

Привет, ЛОР!

Обучаясь bash велосипедю такое нечто. И вот в case 3 у меня цикл, который ждёт подходящий $ANSWER.

Если отрабатывается case 1 и case 2 то всё корректно - или заново проигрывается скрипт или выход из него.

А в случае case 3 получается, что при выходе из цикла и выходе из case скрипт попадает в старший цикл и поскольку переменная $TIME_LAST пустая, то срабатывает условие и ожидается ввод от пользователя.

Данное поведение подходит, если пользователь хочет повторно завести таймер и не подходит, если он хочет закончить работу.

Т.е. если пользователь ответил Y или ответил N, то всё ок. А если он ответил «qwerty», его переспросили, он ответил N, то всё равно скрипт будет продолжать работу.

Как это организовать по-человечески?

#!/bin/bash
# timer.sh
# Таймер с интерактивным вводом. 
# Умеет звенеть колокольчиком на старых терминалах. 
# На некоторых современных может посылать уведомления

TIME_LAST="$1" # Время таймера
FLAG=TRUE # Флажок
INTEGER=^[0-9]+$ # Шаблон проверки числа. В данном случае целое положительное число, не строка

while [[ "$FLAG" = "TRUE" ]]; do

if [[ -z "$TIME_LAST" ]]; then

	echo -e "\nИспользование: \"`basename $0` время_в_минутах\" или введите в интерактивном режиме"
	echo -e "Введите время в минутах (для отмены нажмите Ctrl+C)\n"
	read TIME_LAST

                until [[ "$TIME_LAST" =~ $INTEGER ]]; do
                echo -e "\nОшибка ввода. \"$TIME_LAST\" не является целым положительным числом.\nПовторите ввод\n"
                read TIME_LAST
                done
                
echo -e "\nОтсчёт $TIME_LAST мин. пошёл!"

fi


sleep $(( $TIME_LAST * 1 )) && echo -e "\nВремя вышло!\a" # ДЛЯ ТЕСТА ТУТ УКАЗАНО УМНОЖЕНИЕ МИНУТ НА 5, А НАДО НА 60!!!

TIME_LAST="" # Подметаем за собой

echo -e "\nХотите завести новый таймер? y / n\n"

read ANSWER

case "$ANSWER" in

#1 case
"Y" | "y" )
;;

#2 case
"N" | "n" )
FLAG=FALSE # Переключается флажок и выход из цикла
;;

#3 case
* )
echo -e "\nВведите \"y\" или \"n\"\n"
# Пока не будет получен нужный ответ переспрашивать
until [ "$ANSWER" = "y" -o "$ANSWER" = "Y" -o "$ANSWER" = "n" -o "$ANSWER" = "N" ]; do 
    read ANSWER
done
;;

esac

done

echo -e "\nBye-bye"

exit 0
★★★★

У вас алгоритмическая проблема, а bash тут поскольку-постольку. Потому, напишите алгоритм в удобном вам псевдокоде, а сюда приходите, когда у вас будет конкретный пример не получаться. Всем что, делать нечего, что охота в вашей портянке копаться?

vodz ★★★★★ ()
Ответ на: комментарий от redgremlin

Тебе проверку валидности надо перед case делать. А ещё лучше, не писать на баше ничего, сложнее пары строк, он для этого не предназначен.

redgremlin ★★★★★ ()
Ответ на: комментарий от vodz

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

kma21 ★★★★ ()
Ответ на: комментарий от redgremlin

Тебе проверку валидности надо перед case делать.

да, надо попробовать. я как-то до этого не додумался. спасибо за идею.

А ещё лучше, не писать на баше ничего, сложнее пары строк, он для этого не предназначен.

ну я бы не сказал, что это шибко сложное что-то.

kma21 ★★★★ ()
Ответ на: комментарий от kma21

ну изначально я и просил помочь с логикой скрипта

Увы, вы опять напираете на свой «скрипт». А вам нужно не скрипт выправлять, а научиться логике вообще и программировании в частности.

Для начала, такие вещи как «запрос да/нет/выйти» лучше организовывать в виде функции, которая не завершится, пока не распознает правильный ввод, тогда по коду возврата функции вы сможете успешно сделать case и не будет путаницы во вложенных циклах.

vodz ★★★★★ ()
Ответ на: комментарий от kma21

Там действительно проще всё заново переписать, чем разбираться в этой каше. Наведи порядок в голове, затем наведи порядок в коде.

Я не прикалываюсь и не издеваюсь, абсолютно серьёзно.

r3lgar ★★★★★ ()
Последнее исправление: r3lgar (всего исправлений: 1)
Ответ на: комментарий от vodz

Увы, вы опять напираете на свой «скрипт». А вам нужно не скрипт выправлять, а научиться логике вообще и программировании в частности.

Но ведь я в шапке так и писал

Обучаясь bash велосипедю такое нечто

Для начала, такие вещи как «запрос да/нет/выйти» лучше организовывать в виде функции, которая не завершится, пока не распознает правильный ввод, тогда по коду возврата функции вы сможете успешно сделать case и не будет путаницы во вложенных циклах.

Спасибо за идею.

kma21 ★★★★ ()

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

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

Shulman ()
Ответ на: комментарий от Shulman

goto мне тоже в голову пришло, но как пишут, goto применяется от невозможности корректно воспользоваться имеющимися вариантами описания алгоритма. короче goto - костыль

kma21 ★★★★ ()
Ответ на: комментарий от Shulman

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

#!/bin/bash

function jumpto
{
    label=$1
    cmd=$(sed -n "/$label:/{:a;n;p;ba};" $0 | grep -v ':$')
    eval "$cmd"
    exit
}

echo -n "Bash has "
if [ 1 -eq 1 ] ; then
  jumpto finish
fi
echo -n "no "                                                                                                                 
finish:                                                                                                                      
echo "goto!"


./test.sh
Bash has goto!

redgremlin ★★★★★ ()
Ответ на: комментарий от redgremlin

Если что-то тьюринг полное, к нему не применимо слово «нету».

anonymous ()
Ответ на: комментарий от kma21

Приятней/понятней будет как-то так:

func1()
func2()
case $REPLY in #по умолчанию read пишет в эту переменную
1)func1
2)func2
*) exit 1


На ввод n можно экситом выходить не мудрствуя.

art_metr ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.