bash:从-x回显转义单个行


11

在bash中,使用该-x选项运行时,是否可以排除单个命令的回显?

我正在尝试使输出尽可能整洁,因此我正在使用的子外壳中运行脚本的某些部分set +x。但是,该行set +x本身仍然被回显,并且没有向输出添加任何有价值的信息。

我记得在糟糕的过去.bat,与一起运行时echo on,可以通过以开头来免除单独的行@。bash有任何等效功能吗?

#!/bin/bash -x

function i_know_what_this_does() {
  (
    set +x
    echo do stuff
  )
}

echo the next-next line still echoes 'set +x', is that avoidable?
i_know_what_this_does
echo and we are back and echoing is back on

运行以上命令时,输出为:

+ echo the next-next line still echoes 'set +x,' is that 'avoidable?'
the next-next line still echoes set +x, is that avoidable?
+ i_know_what_this_does
+ set +x
do stuff
+ echo and we are back and echoing is back on
and we are back and echoing is back on

Answers:


22

xtrace输出到stderr,因此您可以重定向stderr/dev/null

i_know_what_this_does() {
  echo do stuff
} 2> /dev/null

如果您仍然想查看函数内部运行的命令中的错误,可以这样做

i_know_what_this_does() (
  { set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
)

请注意使用(...)而不是{...}通过子外壳为该功能提供局部作用域。bash,因为4.4版现在支持local -在Almquist shell中提供类似功能,使选项在函数中成为本地功能(类似于set -o localoptionsin zsh),因此您可以通过执行以下操作避免使用subshel​​l:

i_know_what_this_does() {
  { local -; set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

bash4.0到4.3 的替代方法是使用$BASH_XTRACEFD变量并/dev/null为此打开专用的文件描述符:

exec 9> /dev/null
set -x
i_know_what_this_does() {
  { local BASH_XTRACEFD=9; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

由于bash缺乏用close-on-exec标志标记fd的能力,因此具有将该fd泄漏给其他命令的副作用。

另请参见此locvar.sh,其中包含一些函数,以实现POSIX脚本中变量和函数的局部作用域,还提供trace_fnuntrace_fn函数以使它们是否为xtrace d。


甜!我一直在寻找是否可以将任何修饰符应用于函数本身,但我没有想到仅重定向stderr。谢谢!
clacke

1
顺便说一句,同一页面上的stchaz.free.fr/which_interpreter非常棒且令人不安。:-)
clacke

现在,我再次回到第二种方法,即在不使有用的stderr输出保持沉默的情况下使集合+ x保持沉默。再次感谢!
clacke

2

set +x打印的原因是set -x在运行之前先打印要运行的命令(带有扩展名)。因此,外壳程序直到打印完告诉它不执行的行后才知道您不希望它不打印东西据我所知,无法阻止这种事情的发生。


0

这是您一直在寻找的解决方案:

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
echo "About to do something complicated ..."
xtrace do_something_complicated

还是要避免perl(以及多行命令的问题):+() { :;} 2> /dev/null; xtrace() { (PS4=; set -x; + "$@";{ set +x; } 2> /dev/null); "$@";}
StéphaneChazelas,2015年

不,抱歉,unix.stackexchange.com / a / 60049/17980是我正在寻找的解决方案。:-) set -x演习是否比仅仅买了我什么printf >&2 '+ %s\n' "$*"
clacke 2015年

如:xtrace() { printf >&2 '+ %s\n' "$*"; "$@"; }
clacke
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.