我可以以及如何在 Bash 脚本中使用“script”

我可以以及如何在 Bash 脚本中使用“script”

这肯定是我迄今为止尝试过的最令人沮丧的研究。所以,script(1)。我一直试图将它添加到我拥有的 bash 脚本的开头(我正在寻找一种方法来记录每个输入和输出,而不必tee在脚本的每个步骤中使用函数或类似的东西),但每当我运行该脚本时,我得到的只是:

Script started, outlog log file is 'name'.

它似乎死了。但是当我exit按 或Ctrl+时d,它会运行 bash 脚本。我正在尝试研究它,但考虑到“bash 脚本”本身就是一个主题,到目前为止,它已经超出了我的 Google 技能。

答案?链接?想法?

答案1

总结

请参阅最后的“自定义解释器”部分。


初步说明

script通过为运行的任何程序提供 tty 来工作。在某些情况下,此 tty 可能会影响某些事情。我假设您确实想script在 shell 脚本中自动使用。


分析、问题、想法

script在您的 shell 脚本中启动一个交互式 shell。当您启动exit交互式 shell 时,shell 脚本将继续运行。在这种情况下,就像您bash -i在 shell 脚本中运行一样。

使 run 成为其他东西的唯一(?) 方法script是使用script -c。从手册(您链接到的)

-c--command command
运行command而不是交互式 shell。 […]

script -c 才不是构建一个命令,从一个参数数组中运行(与sudo使用数组的命令相比:)sudo executable arg1 arg2 …command是一个单身的参数。手册中没有明确说明,但command会将其传递给 shell。就像调用 一样"$SHELL" -c command

因此从技术上来说这个示例脚本应该可以工作:

#!/bin/sh -

exec script -c '
# shell code here
# i.e. the actual shell script you want to run
'

缺点:

  • 实际的 shell 代码必须是单个参数。在示例中,它是单引号。因此,引用里面这个论点变得有些复杂。

  • 没有简单的方法可以将参数传递给实际脚本。如果您要运行的 shell 代码使用$@$1或类似的东西,那么这是一个问题。您可能想让外壳扩展这样的标记,这将是错误的,因为嵌入{}shell 代码开始于find -exec sh -c …从技术上来说,这样的装置应该可以工作:

    #!/bin/bash -
    
    exec script -c "exec sh -c '
    # shell code here
    # i.e. the actual shell script you want to run
    ' sh ${@@Q}"
    

    在哪里Q处理${@@Q}参数的引用. bash(在 shebang 中) 是${@@Q}实现此功能所必需的,sh(之后exec) 是选择的 shell,第二个sh解释如下:中的第二个 sh 是什么sh -c 'some shell code' sh

    但是现在实际的 shell 代码在外壳脚本中是双引号的,而调用的 shell 是单引号的script -c。代码内部的正确引用变得更加复杂;很容易意外地让错误的 shell 过早地展开内容。在某些情况下,这种失误甚至可能看起来有效,但它是一堆蠕虫(即一堆潜在的错误)。

或者,此处的文档应该有效:

#!/bin/sh -

exec script -c 'exec sh' <<'EOF'
# shell code here
# i.e. the actual shell script you want to run
EOF

但:

  • 传递参数又有点复杂。你可能不想引用EOF(见这个答案) 并使外壳扩展 (一些) 参数。扩展的值将由内壳解释,因此您应该使用已经提到的Q修饰符 (为此,您需要外壳为bash)。
  • 此处的文档将通过其 stdin 到达script,最终通过 提供的 tty 到达内壳script。内壳将无法使用外部脚本的 stdin。
  • script将记录此处的文档作为输入。
  • 正式的内壳将是交互式的,它将表现得如此(例如,它将显示提示)。

自定义解释器

如果您确实希望脚本自动使用script,请考虑以下自定义解释器:

#!/bin/bash -

if [ "$#" -lt 2 ]; then
   >&2 printf 'Usage: %s interpreter file arg ...' "$0"
   exit 1
fi
set -- "${@@Q}"
IFS=$' \t\n'
exec script -c "exec $*" "${SCRIPT_OUT:-./typescript $(date --rfc-3339=seconds) $$}"

将其另存为script-c,使其可执行(chmod +x script-c)。然后使用这个自定义shebang构建你的脚本:

#!/path/to/script-c /path/to/actual/interpreter

/path/to/actual/interpreter您想要的脚本实际解释器在哪里(例如/bin/bash)。

执行脚本后,我们的自定义解释器将发挥所有神奇的作用,并script -c带有参数调用脚本的实际解释器。

由于事物的局限性你不能在脚本的 shebang 中指定多个参数script-c。我选择参数来表示实际的解释器。如果你使用这个技巧env那么您可能将能够传递更多参数(并且显然您需要进行script-c相应的修改);例如,也许您想为其自身指定一些附加选项,或者指定要写入的script文件的路径。script

我选择不让事情复杂化。script-c写入SCRIPT_OUT环境变量中指定的文件。这意味着您可以像这样调用脚本(使用我们自定义的 shebang):

SCRIPT_OUT=./mylog ./myscript arg1 arg2 …

如果变量未设置或为空,./typescript $(date --rfc-3339=seconds) $$则将被评估和使用。您date可能支持也可能不支持--rfc-3339,请使用您喜欢的任何格式。这允许您简单地运行:

./myscript arg1 arg2 …

并使用一个相当独特的名称。

相关内容