重击:执行前高亮显示命令(设置-x)

时间:2018-06-22 13:50:48

标签: linux bash shell sh

我有一个执行约20条命令的bash脚本,出于调试目的,我发现自己在输出中滚动了很多。 不幸的是,bash不能告诉我输出的哪一部分是什么命令的一部分。 当我在脚本中使用“ set -x”时,它至少会打印一些有关其刚刚执行的内容的信息,但我真的不喜欢它生成的输出。

例如,如果我有此脚本:

#!/bin/bash

set -x
echo "foo"
if [ "$ASD" == "QWE" ] ; then
    echo "bar"
fi

我希望输出是这样的:

  

回显“ foo”
  foo
  回显“栏”
  酒吧

或者也许:

  

回显“ foo”
  foo
   if [“” value_of_ASD“ ==” QWE“];然后
  回显“栏”
  酒吧
   fi

与其以粗体显示命令,还可以用颜色突出显示。但是我不仅想在命令前加上“ +”字符,而且我也不希望if语句显示为'[' value_of_ASD == QWE ']'

我如何用bash做到这一点?

此刻输出如下所示:

+ echo foo
foo
+ '[' value_of_ASD == QWE ']'
+ echo bar
bar

编辑:

我的一个想法是编写一个脚本,该脚本将在主脚本的开始处提供,然后让源脚本解析主脚本。像这样:

source_me.sh

#!/bin/bash
SCRIPT_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/$(basename $0)"
FORMAT_SET_BOLD='\033[0;1m'
FORMAT_RESET='\033[0m'

cat $SCRIPT_PATH | tail -n "+$START_LINE" | while read line; do
    printf "${FORMAT_SET_BOLD}${line}${FORMAT_RESET}\n"
    eval "${line}"
done

exit 0;

main.sh

#!/bin/bash
START_LINE=$((LINENO+1)) source ./source_me.sh

echo "Foo"
echo "Bar"
echo "+Hello"

在这种情况下的输出是:

  

回显“ Foo”
  富
  回显“酒吧”
  酒吧
  回声“ +你好”
  +你好

但是,如果我使用遍及多行的更复杂的代码(例如语句,循环等),则此方法将失败:

#!/bin/bash
START_LINE=$((LINENO+1)) source ./source_me.sh

echo "Foo"

if [ "$FOOBAR" == "" ] ; then
    echo "Bar"
fi

echo "+Hello"

在这种情况下,我得到:

  

回显“ Foo”
  富

     

if [“ $ FOOBAR” ==“”];然后
  ./source_me.sh:eval:第9行:语法错误:文件意外结束
  回显“酒吧”
  酒吧
   fi
  ./source_me.sh:eval:第8行:意外标记'fi'附近的语法错误
  ./source_me.sh:评估:第8行:“ fi”

     

回显“ +你好”
  +你好

4 个答案:

答案 0 :(得分:2)

您可以通过设置+PS4更改为所需的字符串,例如:

PS4="# "; set -x

答案 1 :(得分:1)

请注意,set -x不了解您的终端,这是发送正确的字符以创建粗体或彩色文本所必需的。

如果可以通过单个文件句柄捕获所有输出,则可以使用管道来实现:

$ /path/to/your/script 2>&1 | sed "/^+ /s/.*/$(tput bold)&$(tput sgr0)/"

您可能想man tput来获取有关我们用于获取粗体字的工具的更多信息。

此方法的可行性取决于我对您的环境不了解的许多因素。 YMMV,可能包含坚果。


注意:

您可能会认为最好用这样的一行单独捕获stderr:

$ /path/to/your/script 2> >(sed "/^+ /s/.*/$(tput bold)&$(tput sgr0)/")

A,这并不一致,因为通过脚本传递的stderr可能不会在随后的 stdout之前提交给终端。还要注意,该解决方案由于使用了进程替换,因此是一种bashism,不能移植到POSIX。

答案 2 :(得分:1)

我想用一些我认为值得单独回答的例子来扩展rubo77's answer

纯文本前缀

因此,基本示例是将PS4设置为某些纯文本,例如:

PS4="# "; set -x

这将导致:



颜色和额外的行文本前缀

但是由于可以使用特殊字符和ANSI转义码,因此可以在每个新命令之前添加新行,并以彩色打印前缀,例如:

PS4="\n\033[1;33m>>>\033[0m "; set -x

结果:



动态颜色前缀

最后,您可以使命令前缀每次使用时都调用其他程序 ,您可以使用它们添加时间戳,例如:

# yes, there have to be single quotes below, not double!
PS4='\033[1;34m$(date +%H:%M:%S)\033[0m '; set -x

结果:

答案 3 :(得分:0)

您要寻找的是set -v

-v打印出解释器刚刚读取的行。

-x打印出解释器刚刚读取的行的后解析结果。

文件x

set -vx
foo=1
echo $foo
set +vx

执行中:

$: . x
foo=1
++ foo=1
echo $foo
++ echo 1
1
set +vx
++ set +vx