我试图找到这个问题的答案,但到目前为止没有运气:
我有一个运行其他一些脚本的脚本,其中许多其他脚本都包含“set -x”,这使得它们打印执行的每个命令。如果任何脚本将错误消息发送到 stderr,我想摆脱它但保留信息。
所以我不能简单地写 ./script 2>/dev/null
此外,我没有编辑其他脚本的权限,因此我无法手动更改设置选项。
我正在考虑将所有内容从 stderr 记录到单独的文件并过滤掉跟踪命令,但也许有更简单的方法?
Sté*_*las 25
使用bash
4.1 及更高版本,您可以执行
BASH_XTRACEFD=7 ./script.bash 7> /dev/null
Run Code Online (Sandbox Code Playgroud)
(也适用于bash
作为 调用时sh
)。
基本上,我们告诉在文件描述符 7 上bash
输出xtrace
输出而不是默认值 2,并将该文件描述符重定向到/dev/null
. fd 编号是任意的。使用 2 以上的 fd,该 fd 未在您的脚本中以其他方式使用。如果您在其中输入此命令的 shell 是bash
或yash
,您甚至可以使用大于 9 的数字(尽管如果 shell 内部使用文件描述符,您可能会遇到问题)。
如果您bash
从中调用该脚本的 shell是zsh
,您还可以执行以下操作:
(export BASH_XTRACEFD; ./script.bash {BASH_XTRACEFD}> /dev/null)
Run Code Online (Sandbox Code Playgroud)
为变量自动分配第一个大于 9 的空闲 fd。
对于旧版本的bash
,另一种选择,如果xtrace
打开 with set -x
(与#! /bin/bash -x
or相对set -o xtrace
)将重新定义set
为在传递时不执行任何操作的导出函数-x
(尽管如果它(或bash
它调用的任何其他脚本)会破坏脚本)用于set
设置位置参数)。
喜欢:
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
Run Code Online (Sandbox Code Playgroud)
另一种选择是在每个命令之前执行的$BASH_ENV
文件中添加调试陷阱set +x
。
echo 'trap "{ set +x; } 2>/dev/null" DEBUG' > ~/.no-xtrace
BASH_ENV=~/.no-xtrace ./script.bash
Run Code Online (Sandbox Code Playgroud)
但是,当set -x
在子外壳中完成时,这将不起作用。
正如@ilkkachu 所说,如果您对文件系统上的任何文件夹具有写权限,您至少应该能够制作脚本的副本并对其进行编辑。
如果您无处可写脚本的副本,或者每次对原始脚本进行更新时都不方便制作和编辑新副本,您仍然可以执行以下操作:
bash <(sed 's/set -x/set +x/g' ./script.bash)
Run Code Online (Sandbox Code Playgroud)
如果脚本使用$0
特殊变量或特殊变量$BASH_SOURCE
(例如查找与脚本本身的位置相关的文件),则该(以及复制方法)可能无法正常工作,因此您可能需要进行更多编辑,例如替换$0
为脚本的路径...
由于它们是脚本,您可以制作它们的副本并进行编辑。
除此之外,过滤输出看起来很简单,您可以明确设置PS4
比单个加号更不寻常的东西,以使过滤更容易:
PS4="%%%%" bash script.sh 2>&1 | grep -ve '^%%%%'
Run Code Online (Sandbox Code Playgroud)
(当然,这会导致 stdout 和 stdin 崩溃,但是在 Bash 中只使用 stderr 管道会有点麻烦,所以我会忽略它)