bash: как мне создать функцию из переменной? - PullRequest
18 голосов
/ 22 августа 2011

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

#!/bin/bash
bname="$(basename $0)" # filename of the script itself

someprefix_${bname}() { # function's name created from $bname variable
    echo test
}

Так что, если имя скрипта равно foo.sh, тогда он должен определить функцию с именем someprefix_foo, которая будет выводить «test».

Ответы [ 5 ]

19 голосов
/ 22 августа 2011

Вы можете использовать eval:

eval "someprefix_${bname}() { echo test; }"

Bash даже позволяет "." s в именах функций:)

9 голосов
/ 12 августа 2015

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

Для вашего обзора:

source /dev/stdin <<EOF
function someprefix_${bname}()
{
     echo "test";
};
EOF
2 голосов
/ 01 декабря 2015

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

source /dev/stdin << EOF
badfunc () 
{
    echo $(date)
}
EOF

$ date;badfunc;sleep 10;date;badfunc
Tue Dec  1 12:34:26 EST 2015 ## badfunc output not current
Tue Dec  1 12:23:51 EST 2015
Tue Dec  1 12:34:36 EST 2015 ## and not changing
Tue Dec  1 12:23:51 EST 2015

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

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

tmpsh=$(mktemp)
echo "goodfunc ()" > $tmpsh
echo '{' >> $tmpsh
echo 'echo $(date)' >> $tmpsh
echo '}' >> $tmpsh
. $tmpsh
rm -f $tmpsh

, а затем

$ date;goodfunc;sleep 10;date;goodfunc
Tue Dec 1 12:36:42 EST 2015 ## current
Tue Dec 1 12:36:42 EST 2015
Tue Dec 1 12:36:52 EST 2015 ## and advancing
Tue Dec 1 12:36:52 EST 2015

Надеюсь, это будет более полезным для людей. Наслаждайтесь.

1 голос
/ 22 февраля 2016

Я использую следующий синтаксис, который избегает /dev/stdin, но все же позволяет использовать heredocs:

eval "$(cat <<EOF
  $function_name() {
    commands go here
    but "\$you \$have \$to \$escape $variables"
  }
EOF
)"
0 голосов
/ 31 августа 2018

Вы можете отключить расширение Здесь Документ , например:

eval "$(cat <<EOF
  $function_name() {
    commands go here
    and "$you $do $not $have $to $escape variables"
  }
EOF
)"

См .: Как отследить << EOF >> файл, содержащий код?

Руководство по Bash: 3.6.6 Здесь Документы / Здесь Документ

Без расширения параметров и переменных, подстановка команд, арифметика расширение, или расширение имени файла выполняется над словом. Если какая-либо часть слово заключено в кавычки, разделитель является результатом удаления кавычки на слове, и строки в здесь-документе не расширены. Если слово без кавычек, все строки здесь-документа подвергаются параметру расширение, подстановка команд и арифметическое расширение, последовательность символов \ newline игнорируется, и \ должен использоваться для кавычек символы \, $ и `.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...