这肯定是我迄今为止尝试过的最令人沮丧的研究。所以,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 …
并使用一个相当独特的名称。