我正在编写一个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
,但我也安装了bash
和zsh
以防万一。
答案 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