简体   繁体   English

Bash:执行前突出显示命令(set -x)

[英]Bash: highlight command before execution (set -x)

I have a bash script which executes about 20 commands and for debugging purposes I find myself scrolling through the output a lot.我有一个 bash 脚本,它执行大约 20 个命令,出于调试目的,我发现自己经常滚动输出。 Unfortunately bash doesn't tell me which part of the output is part of what command.不幸的是,bash 没有告诉我输出的哪一部分是什么命令的一部分。 When I use "set -x" in the script it at least prints some information on what it just executed, but I don't really like the output it generates.当我在脚本中使用“set -x”时,它至少会打印一些关于它刚刚执行的内容的信息,但我并不喜欢它生成的输出。

For instance, if I have this script:例如,如果我有这个脚本:

#!/bin/bash

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

I would like the output to be something like this:我希望输出是这样的:

echo "foo"回声“富”
foo
echo "bar"回声“酒吧”
bar酒吧

Or maybe:或者可能:

echo "foo"回声“富”
foo
if [ "value_of_ASD" == "QWE" ] ; if [ "value_of_ASD" == "QWE" ] ; then然后
echo "bar"回声“酒吧”
bar酒吧
fi

Instead of printing the commands in bold, highlighting with a color would also be okay.除了以粗体打印命令之外,用颜色突出显示也可以。 But I don't just want to have "+" characters in front of the commands and I also don't like the if statements showing up like '[' value_of_ASD == QWE ']' .但我不只是想在命令前面有“+”字符,我也不喜欢 if 语句显示为'[' value_of_ASD == QWE ']'

How can I accomplish that with bash?我怎样才能用 bash 做到这一点?

At the moment the output looks like this btw:目前输出看起来像这样顺便说一句:

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

Edit:编辑:

One idea I had was to write a script that I would source in the very beginning of the main script and then let the sourced script parse the main one.我的一个想法是编写一个脚本,我将在主脚本的最开始使用该脚本,然后让源脚本解析主要脚本。 Something like this:像这样的东西:

source_me.sh 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"

The output in that case is:这种情况下的输出是:

echo "Foo"回声“福”
Foo
echo "Bar"回声“酒吧”
Bar酒吧
echo "+Hello"回声“+你好”
+Hello +你好

But this method will fail if I use more complex code that goes over multiple lines (if statements, loops etc):但是,如果我使用跨越多行的更复杂的代码(if 语句、循环等),则此方法将失败:

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

echo "Foo"

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

echo "+Hello"

In this case I get:在这种情况下,我得到:

echo "Foo"回声“福”
Foo

if [ "$FOOBAR" == "" ] ;如果 [ "$FOOBAR" == "" ] ; then然后
./source_me.sh: eval: line 9: syntax error: unexpected end of file ./source_me.sh: eval: 第 9 行:语法错误:文件意外结束
echo "Bar"回声“酒吧”
Bar酒吧
fi
./source_me.sh: eval: line 8: syntax error near unexpected token ´fi' ./source_me.sh: eval: 第 8 行:意外标记“fi”附近的语法错误
./source_me.sh: eval: line 8: ´fi' ./source_me.sh: 评估: 第 8 行: 'fi'

echo "+Hello"回声“+你好”
+Hello +你好

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

PS4="# "; set -x

Note that set -x has no innate knowledge of your terminal, which would be required to send the correct characters to create bold or coloured text.请注意, set -x对您的终端没有先天的了解,这需要发送正确的字符来创建粗体或彩色文本。

If you can capture all output through a single file handle, you can probably do this with a pipe:如果您可以通过单个文件句柄捕获所有输出,则可以使用管道执行此操作:

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

You might want to man tput for more information about the tool we're using to get bold type.您可能想要man tput以获取有关我们用来获取粗体的工具的更多信息。

The viability of this depends on many factors I don't know about your environment.这的可行性取决于我不知道您的环境的许多因素。 YMMV, may contain nuts. YMMV,可能含有坚果。


Note:笔记:

You might think it was better to capture stderr separately with a line like this:您可能认为最好用这样的一行单独捕获 stderr:

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

Alas, this doesn't behave consistently, because stderr passing through the pipe may not be submitted to the terminal before subsequent stdout from the script itself.唉,这并不一致,因为在脚本本身的后续stdout 之前,通过管道的 stderr 可能不会提交到终端。 Note also that this solution, because it uses process substitution , is a bashism and is not portable to POSIX.还要注意,这个解决方案,因为它使用进程替换,是一种bashism,不能移植到POSIX。

I would like to extend rubo77's answer with a few examples that I think deserve a separate answer:我想用几个我认为应该单独回答的例子来扩展rubo77 的回答:

Plain text prefix纯文本前缀

So the basic example is to set PS4 to some plain text, eg:所以基本的例子是将PS4设置为一些纯文本,例如:

PS4="# "; set -x

Which will result in:这将导致:



Color & extra line text prefix颜色和额外的行文本前缀

But because you can use special characters and ANSI escape codes you can for example add a new line before each new command and print the prefix in a color, eg:但是因为您可以使用特殊字符和 ANSI 转义码,您可以例如在每个新命令之前添加一个新行并以颜色打印前缀,例如:

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

Result:结果:



Dynamic color prefix动态颜色前缀

Finally you can make the command prefix call other programs with each use , which you can use to add a timestamp, eg:最后,您可以使命令前缀在每次使用时调用其他程序,您可以使用它来添加时间戳,例如:

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

Result:结果:

What you are looking for is set -v .您正在寻找的是set -v

-v prints out the line the interpreter just read. -v 打印出解释器刚刚读取的行。

-x prints out the post-parsing results of the line that the interpreter just read. -x 打印出解释器刚刚读取的行的解析后结果。

file x :文件x

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

Executing:执行:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM