Поиск по сайту:

Сценарии оболочки, часть V: Функции в Bash


На этой странице

  1. Введение
    1. Общий синтаксис:

    Привет! Добро пожаловать в серию руководств по написанию сценариев оболочки HowToForges. Если вы хотите прочитать предыдущие выпуски руководства, не стесняйтесь щелкнуть здесь, чтобы перейти к части 4 руководства. В этой части вы узнаете, как эффективно структурировать свои скрипты, создавая функции. К концу этого руководства вы сможете узнать, как создавать функции в оболочке Bash Linux, передавать параметры в ваши функции и возвращать некоторые значения из функции в ваш основной код. Давайте начнем!

    Вступление

    Функция, также известная как подпрограмма в языках программирования, представляет собой набор инструкций, которые выполняют определенную задачу для основной процедуры [1]. Это позволяет программистам разбивать сложный и длинный код на небольшие разделы, которые можно вызывать при необходимости. Каждая функция должна быть вызвана основной подпрограммой для запуска, таким образом, она изолирована от других частей вашего кода, и это создает простой способ тестирования кода. Кроме того, функции можно вызывать в любое время и многократно, что позволяет повторно использовать, оптимизировать и минимизировать коды. Как и большинство языков программирования, оболочка bash также поддерживает функции.

    Общий синтаксис:

    1. Syntax 1:
      function function_name
      {
          ##### set of commands
      }
    2. Syntax 2:
      function_name()
      {
          #### set of commands
      }

    Создание функций

    Bash поддерживает две структуры для функций. При использовании первого синтаксиса вы должны использовать ключевое слово function, за которым следует имя вашей функции, а также открывающие и закрывающие круглые скобки и фигурные скобки, чтобы отделить содержимое ваших функций от вашей основной процедуры. Этот синтаксис покажется вам знакомым, если у вас есть опыт работы с PHP, потому что функции в PHP объявляются таким же образом. Другой синтаксис состоит только из имени функции, открывающих и закрывающих скобок и фигурных скобок.

    #!/bin/bash
    myfunction(){
        echo "My function works!"
    }
    myfunction

    В нашем примере я использовал второй синтаксис. После создания функции myfunction она вызывалась вызовом имени ее функции в нашей основной подпрограмме. Основная подпрограмма будет находиться в любом месте нашего скрипта, которое не было определено как часть нашей функции.

    Теперь давайте изменим наш код, чтобы проверить, можно ли объявлять функции в любом месте нашего скрипта. Рассмотрим код ниже:

    #!/bin/bash
    echo "testing my function"
    myfunction

    myfunction(){
        echo "My function works!"
    }

    Строка 3 в приведенном выше коде возвращает ошибку «команда не найдена». Это означает только то, что:

    The function only works if it is declared before your main routine. The interpreter will return an error if you have declared your function after your main routine.

    Реструктуризация кодов с использованием функций

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

    Например, рассмотрим код ниже:

    #!/bin/bash
    while(true)
    do
        clear
        printf "Choose from the following operations: \n"
        printf "[a]ddition\n[b]Subtraction\n[c]Multiplication\n[d]Division\n"
        printf "################################\n"
        read -p "Your choice: " choice
        case $choice in
        [aA])
            read -p "Enter first integer: " int1
            read -p "Enter second integer: " int2
            res=$((int1+int2))

        ;;
        [bB])
            read -p "Enter first integer: " int1
            read -p "Enter second integer: " int2
        res=$((int1-int2))

        ;;
        [cC])
            read -p "Enter first integer: " int1
            read -p "Enter second integer: " int2
            res=$((int1*int2))

        ;;
        [dD])
            read -p "Enter first integer: " int1
            read -p "Enter second integer: " int2
            res=$((int1/int2))

        ;;
        *)
            res=0
            echo "wrong choice!"
        esac

        echo "The result is: " $res
        read -p "Do you wish to continue? [y]es or [n]o: " ans
        if [ $ans == 'n' ]
            then
             echo "Exiting the script. Have a nice day!"
            break
        else
            continue
        fi

    done

    Сценарий работает хорошо, однако обратите внимание, что строки для приема входных данных повторяются в каждом шаблоне в нашем операторе switch.

    #!/bin/bash
    inputs(){
         read -p "Enter first integer: " int1
        read -p "Enter second integer: " int2
    }

    exitPrompt(){
        read -p "Do you wish to continue? [y]es or [n]o: " ans
        if [ $ans == 'n' ]
        then
            echo "Exiting the script. Have a nice day!"
            break
        else
            continue
        fi
    }

    while(true)
        do
        clear
        printf "Choose from the following operations: \n"
        printf "[a]Addition\n[b]Subtraction\n[c]Multiplication\n[d]Division\n"
        printf "################################\n"
        read -p "Your choice: " choice

        case $choice in
        [aA])
            inputs
            res=$((int1+int2))
        ;;

        [bB])
            inputs
            res=$((int1-int2))
        ;;

        [cC])
            inputs
            res=$((int1*int2))
        ;;

        [dD])
            inputs
            res=$((int1/int2))
        ;;

        *)
            res=0
            echo "wrong choice!"
        esac

        echo "The result is: " $res
        exitPrompt
    done

    Мы улучшили наш код, создав подразделы inputs и exitPrompt. Он работает точно так же с нашим предыдущим кодом, однако наш текущий код легче устранять, поскольку он правильно структурирован.

    Передача параметров в функции

    Как и в большинстве языков программирования, вы можете передавать параметры и обрабатывать эти данные в функциях в bash. В приведенном ниже коде показана процедура передачи значений в сценариях оболочки:

    #!/bin/bash
    myfunction(){
        echo $1
        echo $2
    }

    myfunction "Hello" "World"

    Обратите внимание, что в нашем примере мы добавили значения «Hello» и «World» после того, как вызвали myfunction. Эти значения передаются функции my как параметры и сохраняются в локальной переменной. Однако, в отличие от других языков, интерпретатор сохраняет переданные значения в предопределенные переменные, которые именуются в соответствии с последовательностью передачи параметров, 1 в качестве начального имени до порядка передачи. Обратите внимание, что слово «Hello» хранится в переменной 1, а значение «World» хранится в переменной 2.

    Примечание. 1 и 2 в нашем примере являются локальными переменными и, следовательно, недоступны для других частей скрипта, кроме функции, в которую передаются параметры.

    Например,

    #!/bin/bash
    myfunction(){
        echo $1
        echo $2
    }

    myfunction "Hello" "World"
    echo $1
    echo $2

    Эхо $1 и эхо $2 в последних двух строках нашего скрипта не отображаются, так как интерпретатор не распознает обе переменные, потому что они обе являются локальными для функции my.

    Возврат значений из функций

    Помимо создания функций и передачи им параметров, функции bash могут передавать значения локальной переменной функции в основную процедуру с помощью ключевого слова return. Затем возвращенные значения сохраняются в переменной по умолчанию $? Например, рассмотрим следующий код:

    #!/bin/bash
    add(){
        sum=$(($1+$2))
        return $sum
    }

    read -p "Enter an integer: " int1
    read -p "Enter an integer: " int2
    add $int1 $int2
    echo "The result is: " $?

    В примере мы передаем параметры int1 и int2 в функцию добавления. Затем функция добавления обрабатывает его через строку sum=$ (($1+$2)). Затем значение переменной sum передается в основную процедуру через строку return $sum. По умолчанию значения $sum будут сохранены в переменной по умолчанию $? Наконец, строка echo \Результат:\$? печатает результат.

    Note: Shell scripts can only return a single value.

    В отличие от других языков программирования, сценарии оболочки не могут возвращать из функции несколько значений. Давайте посмотрим на этот пример:

    #!/bin/bash
    add(){
        sum=$(($1+$2))
        dif=$(($1-$2))
        return $sum
    }

    read -p "Enter an integer: " int1
    read -p "Enter an integer: " int2
    add $int1 $int2
    echo "The result is: " $?
    echo "The result is: " $?

    Подвести итог

    Давайте рассмотрим еще один пример, который использует функции, передает им параметры и возвращает значение.

    #!/bin/bash
    #####################
    #Author: HowtoForge #
    #####################

    clear(){
        clear
    }

    bin(){
        bin1=$(echo "obase=2;$1"|bc)
        echo $bin1
    }

    dec(){
        dec1=$(echo "ibase=2;$1"|bc)
        return $dec1
    }

    ########Main#########
        printf "Choose from the following operations:\n[1]Decimal to Binary Conversion\n"
        printf "[2]Binary to Decimal Conversion\n"
        read -p "Your choice: " op
        case $op in

        1)
            read -p "Enter integer number: " int
            bin $int
        ;;

        2)
            read -p "Enter binary number: " int
            dec $int
            echo "The decimal equivalent of $int is $?"
        ;;

        *)
            echo "Wrong Choice!"
        esac

    В данном примере заданный ввод преобразуется как в двоичное, так и в десятичное значение с использованием команд obase и ibase. Строка $ (echo \obase=2;$1\|bc) преобразует заданное десятичное значение в двоичное число и сохраняет его в переменной bin1. Затем мы отобразили значение $bin1 с помощью команды echo.

    Note: It's better to use echo directly when converting from decimal to binary because when you return command to pass a binary value, the bash converts the binary value to decimal before returning it.

    Кроме того, мы преобразовали двоичное значение в десятичное с помощью команды $ (echo \ibase=2;$1\|bc).

    Вы также должны помнить, что интерпретатор способен принимать только 8-битные двоичные цифры. Если вы введете цифру, превышающую 8-битный предел, произойдет переполнение, и старший бит цифры будет отброшен.

    10-битная двоичная цифра 1000001010 возвращает 10, поскольку в соответствии с правилом 8-битной оставшиеся 2 бита в правой части (старший значащий бит) будут опущены, таким образом, 1000001010 станет равным 00001010, что равно 10. Если вы хотите операцию, которая принимает двоичные цифры, превышающие 8 бит, тогда вам нужно создать код вручную.

    Заключение

    Bash имеет функции, очень похожие на языки программирования, чтобы предоставить пользователю множество инструментов и сделать системы Linux более мощными. В этой серии вы расширили свои знания в написании сценариев оболочки с помощью функций. Функции в сценариях оболочки для обеспечения модульности для пользователя, что упрощает устранение неполадок в сценариях и позволяет повторно использовать код.

    Ссылка:

    [1] Словарь английского языка American Heritage®, пятое издание. Авторские права © 2011 г., издательство Houghton Mifflin Harcourt Publishing Company. Опубликовано издательством Houghton Mifflin Harcourt Publishing Company.