当我尝试在命令后链接它时,在 bash 脚本内定义 bash 函数并在同一脚本中使用它时遇到问题script
。
一个最小的工作示例是这样的。我有一个名为 的文件my_script.sh
,包含
#!/bin/bash
my_function () {
echo "My output"
}
my_function
script my_log.log -c my_function
运行时返回
My output
Script started, output log file is 'my_log.log'.
bash: line 1: my_function: command not found
Script done.
我不明白为什么my_function
单独被识别,但在链接后却不能被识别script
。
有人可以解释一下,也许提供一个解决方案吗?
答案1
这里的问题是你的函数只存在于你的脚本中,但是你运行的命令script
会调用一个新的 shell(路径存储在其中$SHELL
或/bin/sh
以其他方式存储的 shell)。该新 shell 不知道您的函数,除非您也在其中定义了它。
外壳bash
支持出口对环境的功能。然后,sh
在该环境中运行的所有其他 bash 调用(甚至是作为 运行的调用)都将导入这些定义。
要导出函数,您需要执行以下操作:
export -f my_function
help export
在 shell 中查看bash
:
$ help export
export: export [-fn] [name[=value] ...] or export -p
Set export attribute for shell variables.
Marks each NAME for automatic export to the environment of subsequently
executed commands. If VALUE is supplied, assign VALUE before exporting.
Options:
-f refer to shell functions
-n remove the export property from each NAME
-p display a list of all exported variables and functions
An argument of `--' disables further option processing.
Exit Status:
Returns success unless an invalid option is given or NAME is invalid.
然后您需要做的就是确保script
运行bash
解释之后传递的命令行-c
,您需要为其传递正确的$SHELL
变量值:
SHELL=$BASH script -c myfunction
答案2
来补充@terdon的回答,除了bash
支持typeset -f
(ksh、mksh、zsh)之外的类似 Korn 的 shell,或者bash
如果只是为了避免函数导出功能的陷阱(见下文),我建议一些替代方案。
对于由 启动的 shellscript
定义相同的函数,您可以在传递给的 shell 代码之前包含该函数的定义script -c
,您可以通过以下方式获取该函数typeset -f
:
SHELL=/same/shell/as/running/the/current/script script -c "
$(typeset -f myfunc)
myfunc"
哪里script
将启动一个新的 shell,该 shell 将通过定义函数开始,然后调用它。
或者将函数体传递到环境变量 1 中,并通过script
评估该变量的内容来启动 shell:
SHELL=/same/shell/as/running/the/current/script \
MYFUNC_DEFINITION="$(typeset -f myfunc)" script -c '
eval "$MYFUNC_DEFINITION"
myfunc'
(该方法的优点是不会在命令行参数中公开函数体,以便每个人都可以在 的输出中看到ps
)。
export -f
相比之下(除了不是特定于 bash 之外)的优点是:
- 那么该函数只会暴露给您需要它的 shell,而不暴露给可能在该环境中启动的其他 shell。
bash
如果该函数使用运算符,则导入该函数将失败,除非启用extglob
该选项extglob
前该函数已导入。通过我们的方法,我们可以选择何时导入函数定义,然后可以在shopt -s extglob
前面添加一个。但是对于使用 with 导出的函数,我们可以尽早export -f
设置选项的唯一方法是 with which 不是这里的选项 with 。 Even (这很危险,因为它会影响所有调用)不起作用。extglob
bash -O extglob
script
env BASHOPTS=extglob script -c ...
bash
1 实际上,这bash
就是export -f
.它甚至曾经以一种非常不安全的方式做到这一点,这是几年前成为新闻头条的非常令人讨厌的漏洞的根源。。