Bash. Как обойтись без goto

Bash. Как обойтись без gotoЕсли вы программировали в командой оболочке cmd в Windows, то вы, возможно, использовали оператор goto для того, чтобы выполнять различные блоки операторов. В bash нет оператора goto, и он, в общем, и не нужен. Однако, при переходе от cmd к bash может возникнуть вопрос, как же обойтись без goto в bash. Процесс выполнения скрипта в этих оболочках различается, тем не менее, можно написать в любой из них скрипт, который будет работать точно так же, как и скрипт в другой оболочке. 

Пример 1: Несколько блоков, из которых должен выполниться только один.

Скрипт на cmd:

@echo off
if %1 == 1 goto LABEL1
if %1 == 2 goto LABEL2
if %1 == 3 goto LABEL3
goto END

:LABEL1
echo Parameter: 1
goto END

:LABEL2
echo Parameter: 2
goto END

:LABEL3
echo Parameter: 3
:END

Пример очень простой, между меткой и оператором goto может быть значительно большее количество команд, конечно же. И для операторов после LABEL3 переход нам не нужен, потому что и так уже достигнут конец скрипта.

Скрипт на bash:

#!/bin/bash

label1(){
echo "Parameter: 1"
}

label2(){
echo "Parameter: 2"
}

label3(){
echo "Parameter: 3"
}

if [ "$1" == "1" ]; then label1; fi
if [ "$1" == "2" ]; then label2; fi
if [ "$1" == "3" ]; then label3; fi

В целом скрипты выполняются абсолютно идентичным способом. Различия вот в чем. В bash необходимо определить функцию до того, как она будет вызвана в первый раз. В cmd не используются функции, поэтому гибкость алгоритма обеспечивается непосредственными переходами при помощи goto на метку. Метка может быть в любом месте скрипта, как до команды перехода, так и после. В плане гибкости cmd имеет некоторое преимущество в том смысле, что метку можно вставить в любое место скрипта. Но bash с использованием функций позволяет сделать скрипт более строгим, более предсказуемым.

А в плане результата данный пример и в cmd, и в bash одинаков. Главное понять, что в cmd сам скрипт является целиком линейным, а в bash за счет возможности создания функций не является, так как сама функция представляется при ее вызове как обычная команда.

Пример 2: При соблюдении условия будет выполняться дополнительная часть команд.

Скрипт на cmd:

@echo off
if %1 == 1 goto LABEL1
if %1 == 2 goto LABEL2
if %1 == 3 goto LABEL3
goto END

:LABEL1
echo Parameter: 1
:LABEL2
echo Parameter: 1 or 2
goto END

:LABEL3
echo Parameter: 3
:END

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

:LABEL1
echo Parameter: 1
  :LABEL2
  echo Parameter: 1 or 2
  goto END

Такой вариант в bash будет выглядеть следующим образом:

#!/bin/bash

label2(){
echo "Parameter: 1 or 2"
}

label1(){
echo "Parameter: 1"
label2
}

label3(){
echo "Parameter: 3"
}

if [ "$1" == "1" ]; then label1; fi
if [ "$1" == "2" ]; then label2; fi
if [ "$1" == "3" ]; then label3; fi

Вложенный блок выделяется в отдельную функцию label2, вызов которой осуществляется из label1. НО! Эта функция должна быть УЖЕ ОПРЕДЕЛЕНА к моменту первого вызова, поэтому в скрипте она должна находиться ВЫШЕ функции label1.

Bash. Как обойтись без goto: 6 комментариев

  1. #kstn

    Имхо тогда уж лучше

    case "$1" in
    1) label1 ;;
    2) label2 ;;
    3) label3 ;;
    esac

    или уж

    if [ "$1" == "1" ]; then label1;
    elif [ "$1" == "2" ]; then label2;
    elif [ "$1" == "3" ]; then label3;
    fi

    хотя первое, имхо, читабельнее

    1. mnorin Автор записи

      Тогда параллель будет не такая явная. В примере я хотел как раз показать практически идентичность основного логического блока. А вообще да, оптимизация наш друг.

      1. Антон

        Добрый день! а как сделать так что бы после выполнения функции выполнение скрипта продолжилось в цикле сорри за мою безграмотность))

        напримере простого угадай число….

        #!/bin/bash
        ran=$(shuf -i 0-100 -n 1 )
        echo "Enter number: "
        echo $ran
        read numb
        
        label1(){
        echo " Enter again:"
        read numb
        }
        
        if [ "$ran" \ "$numb" ]
        then
          echo "Больше :"
          label1
        elif [ "$ran = $numb" ]
        then
           echo "Угадал!!!!!!"
        fi
        
        1. Maxim Norin Автор записи

          Добрый день. Как-то так:

          #!/bin/bash                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                        
          while true                                                                                                                                                                                                                                    
          do                                                                                                                                                                                                                                            
            numb=-1
            ran=$(shuf -i 0-100 -n 1)
            while true
            do
              read -p "Enter number or q to quit: " numb
              # Exit if entered "q"
              [ "$numb" = "q" ] && exit
              if [ $ran -gt $numb ]
              then
                echo -n "Bigger. "
              elif [ $ran -lt $numb  ]
              then
                echo -n "Smaller. "
              else
                echo "TA-DA!!!"
                break;
              fi
            done
          done
          
          1. Anton

            Благодарю! вопрос зачем numb=-1 в начале?

            1. Maxim Norin Автор записи

              Уже не нужна, можно удалить :-)

Обсуждение закрыто.