Reputation: 4028
How do I create a function named from the contents a variable? I want to write a template script that defines a function named after the script’s own file name. Something like this (which of course doesn't work):
#!/bin/bash
bname="$(basename $0)" # filename of the script itself
someprefix_${bname}() { # function's name created from $bname variable
echo test
}
So if the script's filename is foo.sh
, then it should define a function named someprefix_foo
that will echo "test".
Upvotes: 31
Views: 11584
Reputation: 123
To avoid uncertainty of what gets expanded when, I used to put all the stuff I want to make in an auxiliary function with a fixed name and just call that from a function with a dynamic name:
_function_main() {
date
printf '%s\n' "$@"
}
eval "function_${dynamicname}() { _function_main \"\$@\"; }"
Upvotes: 1
Reputation: 48824
I use the following syntax, which avoids /dev/stdin
but still lets you use heredocs:
eval "$(cat <<EOF
$function_name() {
commands go here
but "\$you \$have \$to \$escape $variables"
}
EOF
)"
(notice $variables
will be expanded in the function body, the other vars will not be).
Upvotes: 2
Reputation: 19555
You can disable expansion of a Here Document like that:
eval "$(cat <<EOF
$function_name() {
commands go here
and "$you $do $not $have $to $escape variables"
}
EOF
)"
See: How to cat <<EOF >> a file containing code?
Bash Manual: 3.6.6 Here Documents / Here Document
No parameter and variable expansion, command substitution, arithmetic expansion, or filename expansion is performed on word. If any part of word is quoted, the delimiter is the result of quote removal on word, and the lines in the here-document are not expanded. If word is unquoted, all lines of the here-document are subjected to parameter expansion, command substitution, and arithmetic expansion, the character sequence \newline is ignored, and
\
must be used to quote the characters\
,$
, and`
.
Upvotes: -2
Reputation: 833
The 'eval and 'source' solutions work IFF you do not have anything in the function that could be evaluated at create time that you actually want delayed until execution time.
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
Yes, it's a contrived example (just call date and don't echo a subshell call of it), but using the original answers, I tried something a more elaborate that required a run time evaluation and got similar results - evaluation at "compile" time, not run time.
The way that I solved the problem was to build a temp file with the function and then source that. By the judicious use of single and double quotes surrounding the test I print into the file, I can completely control what gets evaluated and when.
tmpsh=$(mktemp)
echo "goodfunc ()" > $tmpsh
echo '{' >> $tmpsh
echo 'echo $(date)' >> $tmpsh
echo '}' >> $tmpsh
. $tmpsh
rm -f $tmpsh
and then
$ 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
Hopefully, this will be of more use to people. Enjoy.
Upvotes: 2
Reputation: 301
Indeed, it is instructive that the aforementioned construction derails the possibility of having embedded quotation marks there within and is thus potentially bugulant. However, the following construction does proffer similar functionality whilst not having the constraints of the former answer.
For your review:
source /dev/stdin <<EOF
function someprefix_${bname}()
{
echo "test";
};
EOF
Upvotes: 20
Reputation: 149796
You can use eval
:
eval "someprefix_${bname}() { echo test; }"
Bash even allows "."
s in function names :)
Upvotes: 33