Bash脚本:使用“script”命令从Bash脚本记录会话日志

32

我想使用script命令来记录一个bash会话。

script命令在bash脚本中被执行,但一旦它被执行,bash脚本就会终止。

我尝试过使用各种组合来调用该命令,但结果总是相同(在调用命令时终止bash脚本)。我得到的输出如下:

Script started, file is typescript
root@ubuntu: ...

我也尝试过在命令结尾加上一个&来调用该命令,但是仍然没有成功。

有人能告诉我应该如何从Bash脚本中调用该命令吗?

谢谢。


1
请展示您的Bash脚本,或者至少展示script行。 - Robin Green
从脚本提示符中执行ps命令(无参数),应该会显示发生了什么。你认为为什么它不起作用呢?如果是因为typescript是“空”的话,那么你可能遇到了缓冲问题。 - cdarke
@Robin Green:你可以在这里找到我的脚本:链接 - limp
5个回答

29
您的shell脚本没有终止,它仍在运行。你看到提示符是因为script正在生成一个新的shell。您看到的提示符是派生shell的提示符。 script的正常用例如下:
  1. 启动script。这将生成一个新的shell。
  2. 在新的shell中执行命令。
  3. 退出shell并回到先前的shell
  4. 检查由script创建的日志文件
所以基本上script的工作方式是符合预期的。您需要找到另一种实现您想要的功能的方法。
您可以像这样记录脚本的执行:
#! /bin/bash
exec > logfile 2>&1
set -x
FOO=BAR
echo $FOO

说明:

  • exec > logfile 2>&1将标准输出和标准错误输出重定向到logfile文件中
  • set -x让bash在执行每个命令前打印该命令

示例:

$ ./foo.sh
  # (no output here because everything goes to logfile)
$ cat logfile 
+ FOO=BAR
+ echo BAR
BAR

这种方法的缺点是脚本不会输出任何内容让人看到,所有的信息都会记录在日志文件中。

或者您可以这样做:

#! /bin/bash
# nothing special here
FOO=BAR
echo $FOO

然后执行以下命令:

$ script -c "bash -x foo.sh"
Script started, file is typescript
+ FOO=BAR
+ echo BAR
BAR
Script done, file is typescript

现在输出会直接显示并保存到日志文件中(日志文件的默认名称为typescript

$ cat typescript 
Script started on Mi 18 Mai 2011 01:05:29 CEST
+ FOO=BAR
+ echo BAR
BAR

Script done on Mi 18 Mai 2011 01:05:29 CEST

使用 BSD 脚本命令(MacOS X),您无需使用 -c 参数或引号来执行命令。命令应该是 script bash -x foo.sh - Simon Woodside
要将日志文件追加,请使用cmd2 >> logfile.log - ashraf minhaj

6

您的Bash脚本仍在运行,但它已经生成了一个新的交互式Shell。Bash脚本正在等待script完成,只有当交互式Shell被终止(被杀死或用户输入exit)时才会发生。

要使script后面的命令被script记录,请按照以下方式操作:

script build_log -c 'echo -e "* This line should appear inside the /"build_log/" log file..."'

然而,script 在运行该命令后将停止运行。

要在 script 中运行多个命令,请将这些命令放入另一个 bash 脚本中,并将该 bash 脚本指定为要运行的命令到 -c 选项。


谢谢!这正是我要找的。我一直在使用命令行逐个编写“make x”,“make y”等脚本。最后,我使用了一个.sh文件,并为每个make命令调用了“script results1.txt -c“make x””。非常有用! - redhotspike
使用BSD脚本命令(MacOS X),您不需要-c参数或引号来包含命令。它将是script build_log echo '* This line should appear inside the "build_log" log file...' - Simon Woodside

3

你可以按照execve的思路,使用环境变量:

#!/bin/sh
[ -z "$TYPESCRIPT" ] && TYPESCRIPT=1 exec /usr/bin/script -c "TYPESCRIPT=1 $0 $@"
# your script here...

3

juj的回答很好,但未能正确传递参数。基本问题是在双引号字符串内使用了$@。应该改用$*

#!/bin/sh
[ -z "$TYPESCRIPT" ] && TYPESCRIPT=1 exec /usr/bin/script -c "TYPESCRIPT=1  $0 $*"
# your script here...

以下是关于$@的具体情况:
foo.sh中:
#!/bin/sh
if [ -z $FOO ]
then
    FOO=1 exec $0 $@
else
    ./echo_args.sh "$0 $@"
fi

bar.sh:

#!/bin/sh
echo 0 $0
echo 1 $1
echo 2 $2
echo 3 $3

现在执行带有一些参数的./foo.sh命令会输出:

0 ./bar.sh
1 /path/to/foo.sh with
2 some
3 arguments

这将导致一些参数被传递给 script 而不是第二次执行 foo.sh

2

您可以在Shell脚本中使用技巧来控制脚本是否执行。根据特定参数,它可以选择使用特殊参数执行自身,以避免重复启动脚本。

下面的例子可能会更好地解释我所说的:

if [ "$1" != "noscript" ] ; then
        # execute self with the noscript special arg so that the second execution DOES NOT start script again.
        exec script -q -c "$0 noscript $1 $2 $3" /build/buildlog_`date '+%Y%m%d%H%M%S'`.log
        echo Problem in $0, please check.
        exit 1;
fi 
...Rest of the script should follow here.

我尝试过这个方法,效果很好。除非您对需要传递的参数类型特别在意,并且脚本打算被恶意用户使用,否则这种方法就足够了 :)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接