10

我正在编写一个循环遍历一些值并为每个值运行一个长命令行的 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

4 回答 4

12

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

于 2013-06-28T14:06:32.870 回答
6

您想尝试使用单行 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
于 2015-08-27T19:37:13.433 回答
2

下一个命令禁用“xtrace”选项:

$ 设置 +o xtrace

于 2019-04-05T03:01:55.297 回答
0

我想到了

 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。

于 2013-06-28T13:53:06.623 回答