从脚本外部抑制 bash 执行跟踪 (set -x)

从脚本外部抑制 bash 执行跟踪 (set -x)

我尝试寻找这个问题的答案,但到目前为止没有运气:

我有一个运行其他一些脚本的脚本,其中许多其他脚本都有“set -x”,这使它们打印它们执行的每个命令。我想摆脱它,但如果任何脚本将错误消息发送到 stderr,则保留信息。

所以我不能简单地写 ./script 2>/dev/null

另外,我没有编辑其他脚本的权限,因此我无法手动更改设置选项。

我正在考虑将所有内容从 stderr 记录到单独的文件并过滤掉跟踪命令,但也许有更简单的方法?

答案1

使用bash4.1 及更高版本,您可以执行以下操作

BASH_XTRACEFD=7 ./script.bash 7> /dev/null

bash(当作为 调用时也有效sh)。

基本上,我们告诉在文件描述符 7 而不是默认的 2 上bash输出输出xtrace,并将该文件描述符重定向到/dev/null. fd 号是任意的。使用脚本中未使用的高于 2 的 fd。如果您在其中输入此命令的 shell 是bashyash,您甚至可以使用大于 9 的数字(尽管如果文件描述符由 shell 内部使用,您可能会遇到问题)。

如果您调用该脚本的 shellbashzsh,您还可以执行以下操作:

(export BASH_XTRACEFD; ./script.bash {BASH_XTRACEFD}> /dev/null)

为变量自动分配 9 以上的第一个空闲 fd。

对于旧版本的bash,另一种选择是,如果使用(与或相对)xtrace打开,则将重新定义为导出函数,该函数在传递时不执行任何操作(尽管这会破坏脚本,如果它(或它调用的任何其他脚本)用于设置位置参数)。set -x#! /bin/bash -xset -o xtraceset-xbashset

喜欢:

set()
  case $1 in
    (-x) return 0;;
    (-[!-]|"") builtin set "$@";;
    (*) echo >&2 That was a bad idea, try something else; builtin set "$@";;
  esac

export -f set
./script.bash

另一种选择是在文件中添加一个 DEBUG 陷阱,该陷阱在每个命令之前$BASH_ENV执行。set +x

echo 'trap "{ set +x; } 2>/dev/null" DEBUG' > ~/.no-xtrace
BASH_ENV=~/.no-xtrace ./script.bash

set -x但是,当在子 shell 中完成时,这将不起作用。

正如 @ilkkachu 所说,只要您对文件系统上的任何文件夹具有写入权限,您至少应该能够复制脚本并对其进行编辑。

如果没有地方可以编写脚本的副本,或者每次更新原始脚本时不方便制作和编辑新副本,您仍然可以执行以下操作:

 bash <(sed 's/set -x/set +x/g' ./script.bash)

$0如果脚本执行任何奇特的操作或特殊变量$BASH_SOURCE(例如查找与脚本本身位置相关的文件),则该方法(以及复制方法)可能无法正常工作,因此您可能需要进行更多编辑,例如替换$0为脚本的路径...

答案2

因为它们是脚本,所以你可以复制它们并进行编辑。

除此之外,过滤输出看起来很简单,您可以显式设置PS4为比单个加号更不寻常的内容,以使过滤更容易:

PS4="%%%%" bash script.sh 2>&1 | grep -ve '^%%%%'

(当然,这会崩溃 stdout 和 stdin,但是在 Bash 中仅通过管道传输 stderr 会有点麻烦,所以我会忽略它)

相关内容