Reputation: 715
I want to pass a segment of a script to a subshell, so I export it as a function. When I was trying this, I happened to notice I cannot export a function containing a nested function that ends with heredoc.
For example:
#!/bin/bash
f() {
g() {
cat <<EOF
EOF
}
g
}
export -f f
bash -c ':'
If I run it, the subshell fails and prints:
bash: f: line 8: syntax error: unexpected end of file
bash: error importing function definition for `f'
What's wrong with my script?
Upvotes: 3
Views: 348
Reputation: 361625
To get exported functions into subshells Bash serializes them as strings and saves them in plain name=value
environment variables. The subshell recognizes the environment variables as containing functions and parses them as such. This is supposed to be an invisible mechanism but it's complicated enough that there are sometimes bugs (famously, Shellshock).
In Bash 5.0, bash -c env
shows that the function is serialized into an environment variable as:
BASH_FUNC_f%%=() { function g ()
{
cat <<EOF
}
EOF
g
}
Notice the placement of <<EOF
. Having the curly brace inside the heredoc is wrong and the source of the syntax error.
It appears to be a regression in Bash 5.0. In Bash 4.4 and 4.2 it's serialized as this, which works without issue:
BASH_FUNC_f()=() { function g ()
{
cat
} <<EOF
EOF
g
}
I don't see any relevant bug reports at https://savannah.gnu.org/support/?group=bash, nor https://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=bash;dist=unstable. Perhaps you could submit one?
Other observations:
declare -fp
has the same syntax error. The bug probably originates there, not in the environment variable export code.
$ declare -pf f
f ()
{
function g ()
{
cat <<EOF
}
EOF
g
}
I don't see any way to simplify your test case. Well done!
Removing the call to g
fixes the error:
f ()
{
function g ()
{
cat <<EOF
EOF
}
}
So does changing the nested declaration to a simple curly brace block:
f ()
{
{
cat <<EOF
EOF
}
g
}
Upvotes: 3