在 shell 脚本中定义 bash 函数并使用它链接“script”

在 shell 脚本中定义 bash 函数并使用它链接“script”

当我尝试在命令后链接它时,在 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 (这很危险,因为它会影响所有调用)不起作用。extglobbash -O extglobscriptenv BASHOPTS=extglob script -c ...bash

1 实际上,这bash就是export -f.它甚至曾经以一种非常不安全的方式做到这一点,这是几年前成为新闻头条的非常令人讨厌的漏洞的根源。

相关内容