Bash: передать функцию как параметр - программирование
Подтвердить что ты не робот

Bash: передать функцию как параметр

Мне нужно передать функцию в качестве параметра в Bash. Например, следующий код:

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  eval $1
  echo "after"
}

around x

Должен вывести:

before
Hello world
after

Я знаю, что eval неверен в этом контексте, но это просто пример:)

Любая идея?

4b9b3361

Ответ 1

Если вам не нужно что-то интересное, например, задерживать оценку имени функции или ее аргументов, вам не нужно eval:

function x()      { echo "Hello world";          }
function around() { echo before; $1; echo after; }

around x

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

function x()      { echo "x(): Passed $1 and $2";  }
function around() { echo before; "[email protected]"; echo after; }

around x 1st 2nd

печатает

before
x(): Passed 1st and 2nd
after

Ответ 2

нет необходимости использовать eval

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  var=$($1)
  echo "after $var"
}

around x

Ответ 3

Я не думаю, что кто-то вполне ответил на вопрос. Он не спросил, может ли он повторить строки в порядке. Скорее автор вопроса хочет знать, может ли он имитировать поведение указателя функции.

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

От автора:

function x() {
  echo "Hello world"
}

function around() {
  echo "before"
  ($1)                   <------ Only change
  echo "after"
}

around x

Чтобы развернуть это, мы будем иметь функцию x echo "Hello world: $1", чтобы показать, когда действительно выполняется выполнение функции. Мы передадим строку, которая является именем функции "x" :

function x() {
  echo "Hello world:$1"
}

function around() {
  echo "before"
  ($1 HERE)                   <------ Only change
  echo "after"
}

around x

Чтобы описать это, строка "x" передается функции вокруг(), которая echos "before", вызывает функцию x (через переменную $1, первый переданный параметр), передавая аргумент "ЗДЕСЬ", наконец эхо после.

В качестве другой, это методология использования переменных в качестве имен функций. Переменные на самом деле содержат строку, которая является именем функции, и (переменная $arg1 arg2...) вызывает функцию, передающую аргументы. См. Ниже:

function x(){
    echo $3 $1 $2      <== just rearrange the order of passed params
}

Z="x"        # or just Z=x

($Z  10 20 30)

дает: 30 10 20, где мы выполнили функцию с именем "x" , хранящуюся в переменной Z, и передали параметры 10 20 и 30.

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

В bash это не указатели на функции, а переменные, которые ссылаются на имена функций, которые вы позже используете.

Ответ 4

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

Здесь быстрый глупый

foldl() {
    echo $(($(</dev/stdin)$2))
} < <(tr '\n' "$1" <$3)

# Sum 20 random ints from 0-999
foldl + 0 <(while ((n=RANDOM%999,x++<20)); do echo $n; done)

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

(
    id() {
        "[email protected]"
    }

    export -f id
    exec bash -c 'echowrap() { echo "$1"; }; id echowrap hi'
)

id по-прежнему получает только строку, которая является именем функции (автоматически импортируемой из сериализации в среде) и ее аргументов.

Комментарий Pumbaa80 к другому ответу также хорош (eval $(declare -F "$1")), но он в основном полезен для массивов, а не для функций, поскольку они всегда глобальны. Если бы вы выполняли это внутри функции, все, что она сделала бы, это переопределить ее, чтобы не было никакого эффекта. Он не может использоваться для создания закрытий или частичных функций или "экземпляров функций", зависящих от того, что происходит в текущей области. В лучшем случае это можно использовать для хранения определения функции в строке, которая переопределяется в другом месте, но эти функции также могут быть только жестко запрограммированы, если конечно eval не используется

В принципе Bash не может использоваться так.

Ответ 5

У вас должно быть что-то вроде:

function around()
{
  echo 'before';
  echo `$1`;
  echo 'after';
}

Затем вы можете вызвать around x

Ответ 6

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

function myfunc()
{
    local  myresult='some value'
    echo "$myresult"
}

result=$(myfunc)   # or result=`myfunc`
echo $result

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

Ответ 7

eval, вероятно, единственный способ его выполнить. Единственный реальный недостаток - это его аспект безопасности, так как вам нужно убедиться, что ничто вредоносное не передается, и будут вызваны только функции, которые вы хотите вызвать, и убедитесь, что у него нет неприятных символов, таких как ';' в нем также).

Итак, если вы тот, кто вызывает код, тогда eval, вероятно, единственный способ сделать это. Обратите внимание, что существуют другие формы eval, которые, вероятно, будут работать также с подкомандами ($() и ``), но они не более безопасны и стоят дороже.