【问题标题】:Bash script: Using "script" command from a bash script for logging a sessionBash 脚本:使用 bash 脚本中的“脚本”命令来记录会话
【发布时间】:2011-05-12 22:08:23
【问题描述】:

我正在尝试使用script 命令来记录 bash 会话。

script 命令是通过 bash 脚本执行的,但一旦执行,bash 脚本就会终止。

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

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

我也曾尝试使用& 调用命令,但还是没有成功。

谁能告诉我应该如何从 bash 脚本调用命令?

谢谢

【问题讨论】:

  • 请向我们展示您的 bash 脚本,或者至少是 script 行。
  • 从脚本提示符执行 ps(无参数),应该显示正在发生的事情。为什么你认为它不起作用?如果是因为打字稿是“空的”,那么你正在遭受缓冲。
  • @Robin Green:你可以在这里找到我的脚本:link

标签: linux bash


【解决方案1】:

您的 shell 脚本没有终止。它仍在运行。您收到提示是因为script 正在生成一个新外壳。您看到的提示是来自生成的 shell 的提示。

script 的正常用例是这样的:

  1. 开始script。这会产生一个新的外壳。
  2. 在新的 shell 中执行命令。
  3. 退出 shell 并返回到上一个 shell
  4. 检查script创建的日志文件

所以基本上script 正在按预期工作。你必须找到另一种方法来实现你想要的。

您可以像这样记录脚本的执行:

#! /bin/bash
exec > logfile 2>&1
set -x
FOO=BAR
echo $FOO

解释:

  • exec > logfile 2>&1 将 stdout 和 stderr 重定向到日志文件
  • 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
【解决方案2】:

您的 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"。非常有用!
  • 使用 BSD 脚本命令 (MacOS X),您不需要 -c 参数或命令周围的引号。它将是script build_log echo '* This line should appear inside the "build_log" log file...'
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

    您可以在 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.
    

    我试过了,效果很好。除非您特别关注需要传递的参数类型以及脚本计划被敌对用户使用,否则这应该足够了:)。

    【讨论】:

      【解决方案5】:

      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 with some arguments 输出

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

      这会导致某些参数被传递给script,而不是第二次执行foo.sh。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-04-27
        • 2018-03-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多