|
|||||||
Особенности синтаксиса вызова функций в Bash-скриптах
Время создания: 17.05.2022 17:47
Автор: xintrea
Текстовые метки: linux, bash, функция, вызов, синтаксис, присвоение, переменная
Раздел: Компьютер - Linux - Bash - Программирование на Bash
Запись: xintrea/mytetra_syncro/master/base/1652798878xuy3ix1sim/text.html на raw.github.com
|
|||||||
|
|||||||
Bash - очень странный язык, и при работе с ним программист все время натыкается на различные сюрпризы. Казалось бы, что может проще чем вызов функции? Ведь bash поддерживает функции. Все должно работать! Однако на практике получается, что правильно вызвать функцию не так то просто. Очень легко допустить "элементарную" ошибку, и затем долго отлаживаться, разбираясь что вообще в скрипте происходит. Для начала вот что нужно знать о функциях. Самое главное - в теле функции нельзя просто так использовать вывод в консоль. Все что будет выведено в консоль в теле функции, становится ее возвращаемым значением. Поэтому отлаживаться внутри функции через echo не получится, чтобы не нарушить работу кода, который вызывает функцию. Функция без входных параметров в Bash оформляется так: # Получение IP-адреса текущего хоста getCurrentHostIp () { myIp=$( LANG=C /sbin/ifconfig | sed -ne $'/127.0.0.1/ ! { s/^[ \t]*inet[ \t]\\{1,99\\}\\(addr:\\)\\{0,1\\}\\([0-9.]*\\)[ \t\/].*$/\\2/p; }') # Если найдено несколько основных IP-адресов, выбирается только первый myIp=`echo -n ${myIp} | cut -d ' ' -f 1` echo -n ${myIp} } Функция с входными параметра выглядит так: # Запуск SQL-команд из указанного файла # Параметр 1 - имя файла с SQL-командами # Параметр 2 - имя базы данных (опционально) runPsqlCommandsFromFile () { local fileName=$1 local dbName=$2 if [ ! -f $fileName ]; then echo "Не найден файл с SQL-командами $fileName" exit 1 fi local dbNameLen=`echo -n "$dbName" | wc -c` # Если имя БД не задано if [[ dbNameLen -eq 0 ]]; then sudo -u postgres bash -c "cd /tmp ; psql -f $fileName" else sudo -u postgres bash -c "cd /tmp ; psql -d $dbName -f $fileName" fi } И вот какие особенности есть у вызовов функции. Если функция что-то возвращает, то есть, если она может хоть что-то вывести в стандартный поток, то это возвращаемое значение нужно правильно обрабатывать. Например, вышеприведенная функция getCurrentHostIp() возвращает IP-адрес в виде строки. Вызов функции, которая что-то возвращает необходимо делать так, чтобы ее возвращаемое значение обязательно помещалось в переменную или обрабатывалось каким-нибудь условием. А сам вызов функции должен оборачиваться конструкцией $(...): ip=$(getCurrentHostIp) Если функция ничего не возвращает, то ее вызов надо делать без конструкции $(...): runPsqlCommandsFromFile /tmp/sql.txt Почему так, почему нельзя написать: $(runPsqlCommandsFromFile /tmp/sql.txt) # <----- Так нельзя! Ведь хочется, чтобы все вызова функций выглядели единообразно! А нельзя писать вызов функции, которая ничего не возвращает через $(...) по следующей причине. Эта конструкция, про сути, вызывает выполнение функции, и все, что функция возвращает, просто "разворачивает" на месте вызова функции.
И здесь можно сказать: ха, так у нас функция ничего не возвращает! Поэтому Bash ничего не будет интерпретировать, пропустит это пустое место и поедет дальше. Но проблема в том, что невозможно гарантировать, что внутри функции нет никакого вывода. Если посмотреть на функцию runPsqlCommandsFromFile() то кажется, что она ничего не пишет в стандартный поток (за исключением обработки случая отсутсвия файла, при котором эта функция завершит весь скрипт). Но это только кажется. На деле, вызываемые команды могут генерировать какой-то консольный вывод. Например, команда psql будет выдавать в консоль некоторые подробности своей работы. Теперь вопрос: что произойдет, если Bash попытается интерпретировать эти совершенно не предначеные для интерпретации Bash строки? Да, будет ошибка. Поэтому надо либо гарантировать, что внутри функции действительно ничего не выводится в консоль (например, делать обязательное перенаправление потока вывода), либо помнить об особенности синтаксиса вызова функции, либо, что не очень правильно с точки зрения структуры программы, но может помочь избавиться от проблемы - всегда присваивать результат работы функции в переменную. |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|