在bash中,要将变量或函数传递给子进程,需要将其导出。
#!/bin/bash
f() { echo hello; }
# calling shell function `f` in child process
bash -c "f" # bash: f: command not found
# export the function
export -f f
bash -c "f" # "hello"
但是,我似乎无法使用git rebase --exec
实现相同的结果
#!/bin/bash
f() { echo hello; }
# export the function
export -f f
git rebase --exec "f" # does not work
git rebase --exec "bash -c 'f'" # does not work
我知道我可以声明函数内联:git rebase --exec 'f() { echo hello; }; f'
或将函数放在另一个脚本中并调用它:git rebase --exec './f.sh'
有办法让它工作吗?我错过了什么?
3条答案
按热度按时间6ie5vjzr1#
Bash的
export -f
是一个很好的黑客,而不是“标准”的东西。请参阅以下命令和输出(在Linux上):正如我们所看到的,bash将导出的
foo()
的定义放在一个名为BASH_FUNC_foo%%
的env var中。如果当前bash的子进程是另一个bash,那么子bash会很高兴地识别出这个奇怪的env var,并将其恢复为一个函数,并完成所有预期的工作。
但是如果子进程不是bash,那么行为是未定义的。子进程可以选择将这个奇怪的env变量传递给它的子进程,但是它也可以选择取消设置这个奇怪的env变量(因为它看起来很奇怪/无效或者可能是恶意的!)),所以它的子进程(比如另一个bash)不会看到它。
请注意,导出函数的env var命名格式曾经是changed,以处理shellshock问题。
de90aj5v2#
尝试将函数序列化为文本:
avkwfej43#
如前所述,导出的函数存储在POSIX不涉及的名称空间中的环境变量中; shell既不需要也不禁止将这些名称传递给儿童。
一个简单的解决方法是将
eval
内容放入具有明确法律的名称的环境变量中。