如何在不显示stdout的情况下使用set -x?

时间:2018-07-19 09:08:26

标签: linux bash logging sh

在CI中,我正在运行一个bash脚本,该脚本调用了许多bash脚本。

./internals/declination/create "${RELEASE_VERSION}" "${CI_COMMIT_REF_NAME}" > /dev/null

请勿禁用脚本返回的stdout

Gitlabi-CI运行程序在记录100MB日志后停止记录,显示为Job's log exceeded limit of 10240000 bytes

我知道日志脚本只能长大。

如何优化输出日志大小?

我不需要所有的stdout,我可以拥有stderr,但这将是一个长时间运行的脚本,没有任何信息。

是否可以显示正在执行set -x的命令?

修改

阅读答案,我无法解决我的问题。我需要添加我正在使用nodejs 来运行运行长bash脚本的bash脚本。

这就是我在.gitlab-ci.yml中调用节点脚本的方式:

scripts:
   - node my_script.js

my_script.js内,我有:

exports.handler = () => {
  const ls = spawn('bash', [path.join(__dirname, 'release.sh')], { stdio: 'inherit' });
  ls.on('close', (code) => {
    if (code !== 0) {
      console.log(`ps process exited with code ${code}`);
      process.exitCode = code;
    }
  });
};

my_script.sh内,我有:

./internals/declination/create "${RELEASE_VERSION}" "${CI_COMMIT_REF_NAME}" > /dev/null

2 个答案:

答案 0 :(得分:2)

您可以使用exec选择性地重定向文件句柄。

exec >stdout 2>stderr

但是这会失去与终端的连接,因此没有简单的方法可以在此之后向终端输出任何内容。

您可以改为使用m>&n复制文件句柄,其中m是要复制的文件描述符的编号,而n是新的文件描述符的编号(选择一个大的数字,例如99,以免偶然破坏现有的句柄。

exec 98<&1  # stdout
exec 99<&2  # stderr
exec >/dev/null 2>&1
:

要重新启用输出,

exec 1<&98 2<&99

如果您重定向到临时文件而不是/dev/null,则现在显然可以将这些文件的tail显示给调用方。

tail -n 100 "$TMPDIR"/stdout "$TMPDIR"/stderr

(在共享服务器上,可能会使用mktemp在脚本的开头创建一个唯一的临时目录;静态的硬编码文件名使它无法同时运行两个构建。)

由于您通常无法预测下一个错误将在何处发生,因此可能将所有这些信息放入执行重定向,运行构建并最终显示临时日志文件末尾的包装脚本中。某些构建服务器可能希望每隔几分钟就在日志文件中看到一些生命迹象,因此有时也可能每隔一段时间tail几行。

另一方面,如果只有一个构建命令,则整个构建作业的stdout和stderr可以简单地重定向到日志文件,而您不需要来回exec。如果需要为脚本的某些部分选择性地启用输出 ,请使用上述的exec;但是对于批量重定向,只需重定向一个命令即可。

总而言之,也许您的构建脚本应如下所示。

#!/bin/sh

t=$(mktemp -t -d cibuild.XXXXXXXX) || exit

trap 'kill $buildpid; wait $buildpid; tail -n 500 "$t"/*; rm -rf "$t"' 0 1 2 3 5 15

# Your original commands here
${initial_process_wd}/internals/declination/create "${RELEASE_VERSION}" "${CI_COMMIT_REF_NAME}">"$t"/stdout 2>"$t"/stderr &

buildpid=$!
while kill -0 $buildpid; do
    sleep 180
    date
    tail -n 1 "$t"/*
done
wait

此方法的缺点是您会丢失计时信息。适当的解决方案可以让您看到每行的生产时间,并按照消息打印的顺序显示标准输出和标准错误,可能带有可见的时间戳,甚至带有彩色提示(stderr的红色时间戳?)

答案 1 :(得分:0)

选项1

如果您的脚本会将错误消息输出到stderr,则可以使用command > /dev/null忽略所有输出到stdout,其中/dev/null是一个黑洞,它将剥夺对其的任何输出。

选项2

如果错误消息上有任何模式,则可以使用grep过滤掉这些错误消息。


编辑1:

要显示正在运行的命令,您可以向bash提供-x命令;因此,您的命令将是

bash -x ${initial_process_wd}/internals/declination/create "${RELEASE_VERSION}" "${CI_COMMIT_REF_NAME}" > /dev/null

bash将打印执行到stderr的命令


编辑2:

如果要减小输出文件的大小,可以使用gzip将其传递到${initial_process_wd}/internals/declination/create "${RELEASE_VERSION}" "${CI_COMMIT_REF_NAME}" | gzip > logfile

要读取日志文件的内容,可以使用zcat logfile