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

时间:2013-06-28 13:25:31

标签: shell

我正在编写一个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以防万一。

4 个答案:

答案 0 :(得分:9)

将沙盒放入子shell:

(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;例如,它不显示扩展后的值。

答案 1 :(得分:3)

您想尝试使用单行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关注您关心的命令,而不会使用每个" echo"的重复副本向stederr发送垃圾邮件。命令。

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

答案 2 :(得分:1)

我想到了

 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。

答案 3 :(得分:0)

下一个命令禁用'xtrace'选项:

$ set + o xtrace