重击组+ x,不打印


92

有谁知道我们是否可以set +x不打印而使用bash 发言:

set -x
command
set +x

痕迹

+ command
+ set +x

但它应该只是打印

+ command

Bash是版本4.1.10(4)。现在,这困扰了我一段时间-输出杂乱无章的set +x行,使跟踪功能无法发挥应有的作用。


这不能回答您的问题,但是当您运行脚本时为什么不这样做:script.sh 2>&1 | grep -v 'set +x'
cdarke 2012年

Answers:


145

我遇到了同样的问题,并且能够找到不使用子外壳的解决方案:

set -x
command
{ set +x; } 2>/dev/null

10
好的答案,只是一个注释:在命令后没有分号,这是行不通的;并使用分号但括号之间没有空格,将引发语法错误。
sdaau 2014年

9
这将退出状态归零。
加思·基德

8
@GarthKidd每个成功命令的退出状态均归零。set +x如此成功的命令
Daniel Alder

3
在您需要退出状态的情况下command,此变体是一种解决方案:{ STATUS=$?; set +x; } 2>/dev/null。然后$STATUS在空闲时检查后续行。
格雷格价格

5
另外,这是一个打高尔夫球的版本:{ set +x; } 2>&-。它将直接关闭fd 2,而不是使其指向/ dev / null。有些程序在尝试打印到stderr时不能很好地处理该问题,这就是/ dev / null通常是好的样式的原因。但是shell的set -x跟踪处理就很好,因此在这里可以完美地工作,并且确实使这个咒语变得更短。
格雷格(Greg)价格

43

您可以使用子外壳。退出子Shell时,设置x将会丢失:

( set -x ; command )

好吧,谢谢。实际上,我知道“子外壳技巧”。我希望这会比这容易。它涉及代码的大量更改,从而使代码更复杂且可读性更差。恕我直言,这比住一组+ x线还要糟……
Andreas Spindler

我看不出( set -x \n command \n )有什么比这更糟糕的了set -x \n command \n set +x
chepner 2012年

3
@chepner:您不能设置变量。
choroba 2012年

2
...而且您不能cd:它不会更改父外壳程序中的当前目录。
Andreas Spindler

抱歉,我不确定您的实际反对意见是什么。这是一个漫长的一周...
chepner 2012年

8

当我对它感到恼火时,我最近才提出了一个解决方案:

shopt -s expand_aliases
_xtrace() {
    case $1 in
        on) set -x ;;
        off) set +x ;;
    esac
}
alias xtrace='{ _xtrace $(cat); } 2>/dev/null <<<'

这使您可以启用和禁用xtrace,如下所示,其中记录了如何将参数分配给变量:

xtrace on
ARG1=$1
ARG2=$2
xtrace off

您将获得如下所示的输出:

$ ./script.sh one two
+ ARG1=one
+ ARG2=two

聪明的把戏(尽管您不需要这个/dev/stdin部分)。需要注意的是,在脚本中打开别名扩展会产生有害的副作用。
mklement0 2014年

你是对的。我已经编辑了答案,以删除多余的/dev/stdin。我不知道任何特定的副作用,因为非交互式环境不应加载任何定义别名的文件。可能会有什么副作用?
user108471 2014年

1
很好-我忘了别名不是继承的,因此风险要比我想象的要小得多(假设,您的脚本可能会采购恰好定义别名的第三方代码,但我同意这可能不是真正的-世界关注)。+1
mklement0

1
@AndreasSpindler您能否详细说明为什么您认为此技术更有可能泄漏更敏感的信息?
user108471 2015年

1
...基本上是因为别名和函数是高级构造。set +x很难(即使不是不可能)妥协。但这仍然是一个好的直接解决方案-可能是迄今为止最好的解决方案。
Andreas Spindler

7

如何基于@ user108471的简化版本的解决方案:

shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ set +x; } 2>/dev/null'

trace_on
...stuff...
trace_off

这个怎么样?function () { set_plus_x='{ set +x; } 2>/dev/null' }
LexH

1

这是一些想法的组合,可以封装一段代码并保留退出状态。

#!/bin/bash
shopt -s expand_aliases
alias trace_on='set -x'
alias trace_off='{ PREV_STATUS=$? ; set +x; } 2>/dev/null; (exit $PREV_STATUS)'

trace_on
echo hello
trace_off
echo "status: $?"

trace_on
(exit 56)
trace_off

执行时:

$ ./test.sh 
+ echo hello
hello
status: 0
+ exit 56
status: 56

尽力而为,但我认为()周围exit没有必要。好。也许这就是偏执,但如果这个代码在一般的使用你有一个不错的攻击向量:重新定义trace_ontrace_off并注入代码读取执行的命令。如果仅使用此类“实用程序”,则具有启发性,但是如果将代码与其他人一起使用,则必须考虑这种非标准化功能的好处是否胜过缺点。我个人{ set +x; } 2>/dev/null对此很满意,因为这种结构是众所周知的,并且也不会改变退出状态。
Andreas Spindler,
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.