функція виклику, заявлена ​​нижче


15

Чи можна викликати функцію, яка оголошена нижче в bash?

Приклад

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

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

NO_FUNCTION()
{
  .....
  .....
}

Відповіді:


37

Як уже говорили інші, ви не можете цього зробити.

Але якщо ви хочете впорядкувати код в одному файлі так, щоб основна програма знаходилася вгорі файлу, а інші функції були визначені нижче, ви можете це зробити, маючи окрему 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повернення. (див. Як прочитати весь скрипт оболонки перед його виконанням? )


@ikkachu думаю, що це має працювати .. дозвольте перевірити.
msp9011

8
За допомогою сценаріїв Bash я часто використовую [[ ${BASH_SOURCE[0]} = "$0" ]] && Main "$@"для виклику основної функції, щоб я міг джерело її в іншому сценарії без Mainвиконання. Тоді я можу або повторно використовувати функції, або написати тести, щоб перевірити їх.
BlackJack

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 У чому саме проблема? Просто визначте всі функції, можливо, навіть поклавши основний код у функцію, і тоді останній рядок показує, яка функція викликається і містить основну частину сценарію.
BlackJack

@SivaPrasath У C у вас немає голих ifзаяв поза функцією. Функцію не потрібно визначати, коли ви оголошуєтеif функцію, що містить, як тільки ви її викликаєте .
чепнер

4

Оболонка не має поняття declaringфункції. Таким чином, ви не можете мати прямої заяви.

Як наслідок, вам потрібно мати функцію реалізації функції, прочитану оболонкою, перш ніж її можна буде викликати.


4
Технічно деякі оболонки (ksh, zsh) мають функцію автозавантаження функції, яку можна розглядати як певну форму декларування (де autoload fдекларується функція, але її тіло завантажується лише при першому виклику). Це не стосується ОП bash.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.