функция вызова объявлена ​​ниже

15

Можно ли вызвать функцию, которая объявлена ​​ниже в bash?

пример

if [ "$input" = "yes" ]; then
    YES_FUNCTION
elif [ "$input" = "no" ]; then
    NO_FUNCTION
else
    exit 0;
fi

YES_FUNCTION()
{
  .....
  .....
}

NO_FUNCTION()
{
  .....
  .....
}
msp9011
источник

Ответы:

36

Как и другие говорили, вы не можете этого сделать.

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

Например

#!/bin/sh

main() {
    if [ "$1" = yes ]; then
        do_task_this
    else
        do_task_that
    fi
}

do_task_this() {
    ...
} 
do_task_that() {
    ...
} 

main "$@"; exit

Когда мы вызываем mainв конце файла, все функции уже определены. Явный переход "$@"к mainтребуется , чтобы аргументы командной строки сценария видимого в функции.

Явное exitв той же строке, что и вызов main, не является обязательным, но может использоваться для предотвращения путаницы при запуске скрипта при изменении файла скрипта. Без него оболочка будет пытаться продолжить чтение команд из файла скрипта после mainвозврата. (см. Как прочитать весь сценарий оболочки перед его выполнением? )

ilkkachu
источник
@ikkachu думаю, что это должно работать .. позвольте мне проверить.
msp9011
7
С помощью сценариев Bash я часто использую [[ ${BASH_SOURCE[0]} = "$0" ]] && Main "$@"для вызова основной функции, чтобы я мог использовать ее в другом сценарии без Mainвыполнения. Затем я могу либо повторно использовать функции, либо написать тесты для их проверки.
Блэкджек
11
Наличие main "$@"; exitexitтой же строкой, что и main) также полезно в качестве защиты от изменяемого файла во время его интерпретации.
Стефан Шазелас
2
@JoL, то, что читается, не читается снова, и оболочке нужно будет прочитать и проанализировать весь текст цикла, прежде чем начинать его запускать, но затем, после того, как цикл вернется, он продолжит чтение из остальной части файла в текущая позиция (и если файл был изменен, он все испортит). Если все в функциях, оболочка должна прочитать все перед тем, как начать что-либо делать (кроме определения этих функций), если мы поместим exitстроку в ту же строку, что и mainубедимся, что оболочка больше не будет читать что-либо из файла после mainвозврата.
Стефан Шазелас
1
@MontyHarder, не имеет значения, используете ли вы main; exit, main; exit $?или main <EOF>, во всех случаях, код выхода mainиспользуется в качестве кода выхода скрипта. Это exitбыло бы просто для предотвращения путаницы, если кто-то редактирует скрипт во время его работы.
ilkkachu
13

Нет, функции должны существовать в среде оболочек во время их вызова.

В «Руководстве по стилю оболочки» от Google есть исправление:

Вызываемая функция mainтребуется для сценариев, достаточно длинных, чтобы содержать хотя бы одну другую функцию.

В самом конце скрипта, после того, как все функции, как единственный оператор не в функции, вы бы имели

main "$@"

Это вызвало бы mainфункцию с любыми параметрами, которые были заданы скриптом. mainФункция может быть расположена в верхней части сценария (руководство стиля говорит положить его на дне, но опять же , это говорит многое).

Когда оболочка получает mainвызов, все функции в скрипте были проанализированы и поэтому могут быть вызваны из mainфункции.

Кусалананда
источник
9

Нет, функции должны быть объявлены до их использования. Скрипты оболочки читаются построчно и обрабатываются построчно; поэтому функция не существует до тех пор, пока не будет выполнено ее объявление.

Стивен Китт
источник
Вы правы. проблема в том, что у меня более 30 функций в скрипте. это довольно сложно, когда мы читаем код. В Cнем комфортно.
msp9011
3
Вы можете поместить объявления своей функции в другой файл и получить его ( . yourfile).
Стивен Китт
Да, я пробовал это, но требование - иметь один скрипт.
msp9011
@SivaPrasath В чем именно проблема? Просто определите все функции, возможно даже поместите основной код в функцию, а затем последняя строка показывает, какая функция вызывается и содержит основную часть скрипта.
Блэкджек
@SivaPrasath В C у вас нет голых ifоператоров вне функции. Функция не должна быть определена , когда вы объявить о ifфункции отработанной, только когда вы звоните его.
chepner
4

Оболочка не имеет понятия declaring функции. Таким образом, вы не можете иметь предварительную декларацию.

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

Шили
источник
4
Технически, некоторые оболочки (ksh, zsh) имеют функцию автозагрузки функции, которая может рассматриваться как некая форма объявления (где autoload fобъявляется функция, но ее тело загружается только при первом вызове). Это не относится к ОП, bashхотя.
Стефан Шазелас