Подтвердить что ты не робот

Как определить функцию внутри другой функции в Bash?

У меня есть следующий код

func1(){
    #some function thing
    function2(){
        #second function thing
    }
}

и я хочу вызвать function2, но я получаю сообщение об ошибке function2 : not found

Есть ли решение?

4b9b3361

Ответ 1

Ограничить объем внутренней функции

Используйте функцию, определенную с помощью скобки () вместо фигурных скобок {}:

f() (
  g() {
    echo G
  }
  g
)

# Ouputs 'G'
f
# Command not found.
g

Функции округления выполняются в суб-оболочках, которые имеют одинаковую семантику () vs {}, см. Также: Определение тела функции bash с использованием скобок вместо скобок

Этого нельзя использовать, если вы хотите:

  • заданные переменные
  • exit
  • cd

поскольку они теряются в созданной суб-оболочке.

См. Также: функции bash: включение тела в скобки против круглых скобок

Ответ 2

Определения функций в bash не работают так, как определения функций работают во многих других языках. В bash определение функции - это исполняемая команда, которая определяет эффект функции (заменяя любое предыдущее определение), почти так же, как команда присваивания переменной определяет значение переменной (заменяя любое предыдущее определение). Возможно, этот пример прояснит, что я имею в виду:

$ outerfunc1() {
> innerfunc() { echo "Running inner function #1"; }
> echo "Running outer function #1"
> }
$ outerfunc2() {
> innerfunc() { echo "Running inner function #2"; }
> echo "Running outer function #2"
> }
$
$ # At this point, both outerfunc1 and outerfunc2 contain definitions of
$ # innerfunc, but since neither has been executed yet, the definitions
$ # haven't "happened".
$ innerfunc
-bash: innerfunc: command not found
$
$ outerfunc1
Running outer function #1
$ # Now that outerfunc1 has executed, it has defined innerfunc:
$ innerfunc
Running inner function #1
$
$ outerfunc2
Running outer function #2
$ # Running outerfunc2 has redefined innerfunc:
$ innerfunc
Running inner function #2

Теперь, если вы еще этого не знали, я почти уверен, что это не ваша причина для вложения определений функций. В связи с этим возникает вопрос: почему вы вообще вкладываете определения функций? Какой бы эффект вы не ожидали от вложенных определений, это не то, что они делают в bash; поэтому 1) удалите их из гнезда и 2) найдите какой-то другой способ выполнить то, что вы пытались сделать для вас.

Ответ 3

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

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

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

Запуск следующего script (inner_vs_outer.sh)

#!/bin/bash
function outer1 {
    function inner1 {
       echo '*** Into inner function of outer1'
    }
    inner1;
    unset -f inner1
}

function outer2 {
    function inner2 {
       echo '*** Into inner function of outer2'
    }
    inner2;
    unset -f inner2
}
export PS1=':inner_vs_outer\$ '
export -f outer1 outer2

exec bash -i

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

$ ./inner_vs_outer.sh
:inner_vs_outer$ outer1
*** Into inner function of outer1
:inner_vs_outer$ outer2
*** Into inner function of outer2
:inner_vs_outer$ inner1
bash: inner1: command not found
:inner_vs_outer$ inner2
bash: inner2: command not found

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

Ответ 4

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

$ cat try.bash 
function one {
  echo "One"
}

function two {
  echo "Two"
}

function three {
   one
   two
}

three
$ bash try.bash 
One
Two
$ 

Ответ 5

Если вы вложите функцию, скажите function2 внутри функции1, она не станет доступна до вызова функции1. Некоторые могут рассмотреть эту функцию, так как вы можете сделать что-то вроде "unset function2" в конце функции1, и ее область действия полностью локальна для этой функции (ее нельзя вызывать из другого места). Если вы хотите вызвать функцию в другом месте, в любом случае, возможно, нет необходимости ее встраивать.

Ответ 6

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

Как сказано в другом ответе, оператор func(){<...>} является исполняемым оператором, который определяет имя (в глобальной области), связанное с этой функцией. Также как если бы вы определили переменную.

Таким образом, вы можете использовать func2 любом месте кода после выполнения func2(){<...>} :

#func2 not defined
func1(){
    #not defined
    func2(){<...>}
    #defined
}
#not defined
func1
#defined
func3(){
    #only defined if func3 is called after 'func2(){<...>}' has run
}