彩色 xtrace 输出

2024-04-04

我有一个 .sh 脚本,它使用set -o xtrace打印以下所有命令。 我想为这些命令着色。我尝试像这样使用 PS4 变量:

export PS4='\[\e[36m\]\+ \[\e[m\]'

但这只是颜色+- 角色,如果我省略\[\e[m\]我的完整输出和执行程序的输出是彩色的。 是否有另一个变量附加在打印命令之后,我可以在其中重置颜色,或者是否有其他方法。 谢谢。


The Gist

由于终端着色的工作方式,再加上 bash 跟踪的工作方式,实现起来相当难看,但实现方法如下:

首先,您需要找到一些既不会出现在跟踪中、也不会出现在 stdout 中、也不会出现在 stderr 中的唯一字符串。在我的例子中,它是@@@.

然后,如果您的脚本被调用example.sh, 你跑

$ ./color_trace.sh example.sh 

Where ./color_trace.sh是这个脚本:

#!/bin/bash

RED=1
UNIQUE_STR='@@@'

COLOR=$RED

normal()
{
    tput sgr0 # tell the terminal to not style the output
}

colored()
{
    tput setaf $COLOR # tell the terminal to set forward color to $COLOR
}

export PS4="+${UNIQUE_STR}" # artificially insert $UNIQUE_STR to the trace
exec &> >(sed "s/\(\+\)*\+\(${UNIQUE_STR}\)\(.*\)$/$(colored)\1+\3$(normal)/") # see below
set -x # set trace
source "$@" # run the commands in the current shell so that all settings apply

这将为跟踪命令着色red https://linux.101hacks.com/ps1-examples/prompt-color-using-tput/.

解释

它的实现方式如下:

  • Insert $UNIQUE_STR到输出
  • 通过命令路由所有输出 - stdout 和 stderr (exec &> >(...))
  • 命令 (sed) 假设轨迹的形式为+++${UNIQUE_STR} <some interesting trace>
  • 查找带有以下内容的行$UNIQUE_STR (s/...\(${UNIQUE_STR}\).../)并将其删除(/...\1+\3.../, where \1 is ++ and \3 is <some interesting trace>)
  • 如果该行确实包含$UNIQUE_STR,告诉终端在该行之前将颜色设置为红色,并在该行之后取消设置颜色(/$(colored)...$(normal)/).

什么不起作用

一、功能colored() and normal()不接受一段文字要着色。相反,它们指示终端将颜色设置为接下来要写入的内容,并在写入后指示它取消设置颜色。这就是着色或任何类型的样式在 Unix 终端中的工作方式。

其次,跟踪转到 stderr,因此它将与 stderr 的其他输出混合。这可以改变使用BASH_XTRACEFD https://askubuntu.com/questions/811439/bash-set-x-logs-to-file,但在这里效果不佳。

由于您需要着色,因此假定您希望将跟踪与其他输出区分开来,因此假定所有输出(包括 stdout、stderr 和跟踪)都将发送到终端。

如果所有内容都发送到终端,那么为了使跟踪与实际输出正确交错,所有输出(stdout、stderr 和跟踪)都需要在同一文件描述符上执行。这就是为什么我们必须通过以下方式重定向一切sed,不仅仅是痕迹。如果我们只重定向跟踪,那么您将获得来自各种命令的一堆输出,只有在之后您才会看到这些命令的所有跟踪,例如

... actual output from /etc/passwd...
... actual output from /etc/group...
+source ./script.sh
++cat_file /etc/passwd
++cat /etc/passwd
++cat_file /etc/group
++cat /etc/group

如果不是因为文件描述符问题,我们就不需要UNIQUE_STR,我们可以使用类似的东西:

exec 19> >(sed "s/^.*$/$(colored)&$(normal)/")
BASH_XTRACEFD=19
set -x
source "$@"

值得注意的是,即使在这个版本中,我们也必须打开和关闭每行的颜色,因为“实际输出”的行需要不着色。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

彩色 xtrace 输出 的相关文章

  • 何时用引号将 shell 变量括起来?

    我应该或不应该在 shell 脚本中用引号括住变量吗 例如 下列说法正确的是 xdg open URL eq 2 or xdg open URL eq 2 如果是这样 为什么 一般规则 如果它可以为空或包含空格 或实际上任何空格 或特殊字符
  • 如何通过 makefile 在 Linux 上安装程序? [复制]

    这个问题在这里已经有答案了 可能的重复 Linux Unix make install 应该包含什么 https stackoverflow com questions 528399 what should linux unix make
  • 如何通过ssh获取远程命令的退出代码

    我正在通过 ssh 从远程计算机运行脚本 ssh some cmd my script 现在 我想在本地计算机上存储 shell 脚本的退出状态 我该怎么做 假设没有任何问题ssh其本身 其退出状态是在远程主机上执行的最后一个命令的退出状态
  • 如何将一个文本文件拆分为多个 *.txt 文件?

    我有一个文本文件file txt 12 MB 包含 something1 something2 something3 something4 有没有办法分开file txt分成 12 个 txt 文件 比方说file2 txt file3 t
  • 任何退出 bash 脚本但不退出终端的方法

    当我使用exitshell 脚本中的命令 该脚本将终止终端 提示符 有什么方法可以终止脚本然后停留在终端中吗 我的剧本run sh预计通过直接获取或从另一个脚本获取来执行 编辑 更具体地说 有两个脚本run2 sh as run sh ec
  • 向后台进程发送命令

    我有一个先前运行的进程 process1 sh 它正在后台运行 PID 为 1111 或其他任意数字 我怎样才能发送类似的东西command option1 option2PID 为 1111 的进程 I don t想要启动一个新的proc
  • bash 将输出重定向到文件,但结果不完整

    重定向命令输出的问题已经被问过很多次了 但是我有一个奇怪的行为 我使用的是 bash shell debian 版本 4 3 30 1 release 并尝试将输出重定向到文件 但并非所有内容都记录在文件中 我尝试运行的 bin 文件是 l
  • bash while 循环的布尔表达式中的 -lt 意味着什么?

    我猜测它代表小于基于输出 但是我在哪里可以找到有关此语法的文档 bin bash COUNTER 0 while COUNTER lt 10 do echo The counter is COUNTER let COUNTER COUNTE
  • Linux shell 从用户输入中获取设备 ID

    我正在为一个程序编写安装脚本 该程序需要在其配置中使用 lsusb 的设备 ID 因此我正在考虑执行以下操作 usblist lsusb put the list into a array for each line use the arr
  • 如何使用 Bash 编写二进制文件?

    我的问题是我需要创建一个包含以下确切字节的文件 48 00 49 00 我不能使用C perl 其他脚本语言 目标是嵌入式设备 我使用 awk 尝试过 在桌面上它确实有效 awk BEGIN printf c c c c 48 00 49
  • 退出代码大于 255 — 可能吗?

    如果是 在哪个操作系统 shell 或其他操作系统上 考虑以下 Java 程序 我使用 Java 只是作为示例 任何语言都适合这个问题 这更多地与操作系统有关 public class ExitCode public static void
  • Bash 中所有匹配的^单词^替换^?

    为了澄清 我正在寻找一种方法来执行global搜索并替换先前使用的命令 word replacement 似乎只替换了第一场比赛 有没有一些set我无法选择的选项 尝试这个 echo oneone oneone gs one two Rep
  • 为什么 fork 炸弹没有使 android 崩溃?

    这是最简单的叉子炸弹 我在许多 Linux 发行版上执行了它 但它们都崩溃了 但是当我在 android 终端中执行此操作时 即使授予后也没有效果超级用户权限 有什么解释为什么它没有使 Android 系统崩溃吗 一句话 ulimit Li
  • 在 Bash Linux 中,如果给定进程运行时间超过指定时间,如何获取通知?

    我一切顺利 我的程序在大约 N 秒内完成 maybe deadlock 但有时会随机发生死锁 导致程序永远挂起 为了调试这个 我想按照以下方式运行该程序 如何调试罕见的死锁 https stackoverflow com questions
  • 关键字“if”如何测试一个值是真还是假?

    在 bash 脚本中 if 1 then echo Yes else echo No fi Output Yes 它表示 1 被视为真值 但在代码中 word Linux letter nuxi if echo word grep q le
  • Slurm:提交到多个节点时出错(“slurmstepd:错误:execve():python:没有这样的文件或目录”)

    我有一个 bash 脚本submit sh用于向 Slurm 服务器提交训练作业 其工作原理如下 正在做 bash submit sh p1 8 config file 将提交一些对应的任务config file至 8 个 GPU 分区p1
  • 获取最新远程提交的 SHA1 [重复]

    这个问题在这里已经有答案了 可能的重复 git bash 如何检查是否有新的提交可用 https stackoverflow com questions 6006759 git bash how to check if theres a n
  • shell中如何分割字符串

    我有一个变量作为 string ABC400p2q4 我怎样才能分开ABC400 and p2q4 我需要将它分成两个变量 结果我得到 echo var1 ABC400 echo var2 p2q4 可以用任何字母字符代替 ABC 可以用任
  • 是否有 ADB 命令来检查媒体是否正在播放

    我想使用 ADB 命令检查根植于终端的外部设备中是否正在播放音频 视频 我无法找到任何 ADB 命令 如果有 我尝试过 adb shell dumpsys media player 我想要一个命令来指定视频是否正在运行 您可以使用以下命令查
  • 检查帐号是否为数字时出现语法错误

    if account nr 0 9 from account nr 0 9 这是为了检查帐号是否为数字 我收到语法错误 这个问题的早期版本缺少之间的空格if and 实际代码具有所需的空间 它显示以下错误消息 syntax error ac

随机推荐