如何在shell脚本中静默禁用xtrace?

plupiseo  于 2023-03-24  发布在  Shell
关注(0)|答案(4)|浏览(146)

我正在编写一个shell脚本,它循环遍历一些值,并为每个值运行沿着命令行。我想在整个过程中打印出这些命令,就像make在运行makefile时所做的那样。我知道我可以在运行它们之前“回显”所有命令,但这感觉不太优雅。所以我正在研究set -x和类似的机制:

#!/bin/sh

for value in a long list of values
do
    set -v
    touch $value # imagine a complicated invocation here
    set +v
done

我的问题是:在每次迭代中,不仅会打印出有趣的行,还会打印出set +x行。是否有可能防止这种情况?如果没有,您推荐什么解决方案?
PS:上面的MWE使用sh,但我也安装了bashzsh,以防有帮助。

jdg4fx2g

jdg4fx2g1#

将其沙盒到subshell中:

(set -x; do_thing_you_want_traced)

当然,在该子shell中对变量或环境所做的更改将丢失。
如果你真的关心这个,你也可以使用DEBUG陷阱(使用set -T使它被函数继承)来实现你自己的set -x等价物。
例如,如果使用bash:

trap_fn() {
  [[ $DEBUG && $BASH_COMMAND != "unset DEBUG" ]] && \
    printf "[%s:%s] %s\n" "$BASH_SOURCE" "$LINENO" "$BASH_COMMAND"
  return 0 # do not block execution in extdebug mode
}
trap trap_fn DEBUG

DEBUG=1
# ...do something you want traced...
unset DEBUG

也就是说,发出BASH_COMMAND(如DEBUG陷阱所做的)并不完全等同于set -x;例如不显示扩展后的值。

s4n0splo

s4n0splo2#

您想尝试使用单行xtrace:

function xtrace() {
  # Print the line as if xtrace was turned on, using perl to filter out
  # the extra colon character and the following "set +x" line.
  (
    set -x
    # Colon is a no-op in bash, so nothing will execute.
    : "$@"
    set +x
  ) 2>&1 | perl -ne 's/^[+] :/+/ and print' 1>&2
  # Execute the original line unmolested
  "$@"
}

原始命令在同一个shell中执行身份转换。在运行之前,您会获得参数的非递归xtrace。这允许您对您关心的命令进行xtrace,而不会向stederr发送每个“echo”命令的重复副本。

# Example
for value in $long_list; do
  computed_value=$(echo "$value" | sed 's/.../...')
  xtrace some_command -x -y -z $value $computed_value ...
done
eanckbw9

eanckbw93#

下一个命令禁用“xtrace”选项:
$ set +o xtrace

hpxqektj

hpxqektj4#

我想到了

set -x >/dev/null 2>&1; echo 1; echo 2; set +x >/dev/null 2>&1

但得到了

+ echo 1
1
+ echo 2
2
+ 1> /dev/null 2>& 1

我对这些结果感到惊讶.....但是

set -x ; echo 1; echo 2; set +x
+ echo 1
1
+ echo 2
2

看起来符合你的要求。
当我把每个语句放在它的唯一一行时,我看到了类似的结果(set +x除外)
IHTH。

相关问题