在Bash中导出一个嵌套函数定义和heredoc的函数

3
我想将脚本的一部分传递给子shell,因此我将其导出为函数。 当我尝试这样做时,我注意到我不能导出包含以heredoc结尾的嵌套函数的函数。
例如:
#!/bin/bash

f() {
    g() {
        cat <<EOF
EOF
    }

    g
}

export -f f
bash -c ':'

如果我运行它,子shell会失败并打印出以下信息:
bash: f: line 8: syntax error: unexpected end of file
bash: error importing function definition for `f'

我的脚本出了什么问题?

@JohnKugelman Debian包bash_5.0-4中的Bash 5.0.3。 - Sherwood Wang
无论 g 是在 f 内部还是外部定义,它仍然存在于全局作用域中。在 bash 中没有本地函数。 - chepner
1个回答

3
为了将导出的函数传递到子shell中,Bash 将其序列化为字符串并保存在纯文本的name=value环境变量中。 子shell 会将这些环境变量识别为包含函数并解析它们。 虽然这应该是一种隐形机制,但它足够复杂,以至于有时会出现错误(比如著名的 Shellshock)。在Bash 5.0 中,bash -c env 显示该函数被序列化为一个环境变量:
BASH_FUNC_f%%=() {  function g () 
 { 
 cat <<EOF
 }
EOF

 g
}

请注意<<EOF的位置。将花括号放在heredoc内是错误的,也是语法错误的根源。
这似乎是Bash 5.0中的一个退步。在Bash 4.4和4.2中,它被序列化为这样,而且没有任何问题:
BASH_FUNC_f()=() {  function g () 
 { 
 cat
 }  <<EOF
EOF

 g
}

我在https://savannah.gnu.org/support/?group=bashhttps://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=bash;dist=unstable没有找到任何相关的错误报告。也许您可以提交一个? 其他观察:
  • 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
    }
    

我已经报告了这个问题。根据 Chet Ramey 的说法,这个 bug 已经在 devel 分支中修复了。https://lists.gnu.org/archive/html/bug-bash/2020-03/msg00015.html - Sherwood Wang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接