如何用语法高亮显示 bash 输出(一些帮助信息)?

pur*_*zzh 5 bash syntax-highlighting colors highlight pygmentize

我经常--help通过命令的标志获得一些帮助信息,它在终端提供如下输出:

$ vmtkimagereader --help

Creating vmtkImageReader instance.
Automatic piping vmtkimagereader
Parsing options vmtkimagereader

vmtkimagereader : read an image and stores it in a vtkImageData object
  Input arguments:
   -id Id (str,1); default=0: script id
   -handle Self (self,1): handle to self
   -disabled Disabled (bool,1); default=0: disable execution and
     piping
Run Code Online (Sandbox Code Playgroud)

我想语法突出显示输出,如链接上半部分(抱歉,我只能发布 1 个链接)。我尝试过高亮和 pygmentize。但是,highlight 需要指定语法,而 pygmentize 将输出呈现为错误的样式(在链接的下半部分)。

我想知道是否有一种方法可以像这样突出显示语法。我需要为 pygmentize 指定样式吗?还是我必须转向另一种解决方案?

谢谢!

Nic*_*ull 4

ANSI 转义字符串

使用 ANSI 转义序列来实现您想要的,您可以创建一个格式字符串(由 prepending\e[和appended表示m),其中38;5;{0..255}是文本的 256 色(0..255可用颜色代码的范围),48;5;{0..255}是背景的 256 色。例如,

echo -e "\e[38;5;0;48;5;255mText\e[0m"
Run Code Online (Sandbox Code Playgroud)

将打印黑色文本(颜色代码0)和白色背景(颜色代码255)。请注意,该echo命令需要扩展模式(由-e标志切换)来解释 ANSI 转义字符串。

请注意尾随\e[0m以取消设置颜色,否则在此命令之后打印的所有文本都echo将保留格式。\e[0m重置它。

请注意一个有趣的用例,它也会导致错误。在结尾之前放置感叹号\e[0m会导致以下输出:

nick@nick-lt:~$ echo -e "\e[38;5;0;48;5;255mText!\e[0m"
bash: !\e[0m: event not found
Run Code Online (Sandbox Code Playgroud)

这是因为!是 Bash 字符串扩展的一部分。在此处查看有关此问题的更多信息。为了使该工作按预期进行,我们需要做:

echo -e "\e[38;5;0;48;5;255mText"'!'"\e[0m"
Run Code Online (Sandbox Code Playgroud)

因为单引号不会被扩展。


如何使用 ANSI 转义序列打印每种可用颜色。

将它们保存在名为的文件中color-functions.sh

function color_list_text() {
    # First paramter can be an optional background color
    local BGCOLOR="$1"

    COLOR=
    # Loop through the number range 0 to 255
    for COLOR in {0..255}; do
        local BGCOLORFORM=""
        # If our first parameter has a value, then create a background
        # format in ANSI escape sequence, assign to $BGCOLORFORM
        [[ -z "$BGCOLOR" ]] && BGCOLORFORM="48;5;${BGCOLOR};"

        # Create the whole ANSI escape sequence, assign to $TEXTFORM
        local TEXTFORM="${BGCOLORFORM}38;5;${COLOR}m"

        echo -en "\e[${TEXTFORM} ${COLOR}\t\e[0m"

        [[ $(( (COLOR + 1) % 16 )) -eq 0 ]] && echo
    done

    return 0
}

function color_list_text_backgrounds() {
    local TEXTCOLOR="$1"

    local COLOR
    for COLOR in {0..255}; do
        local TEXTCOLORFORM=""
        [[ -z "$TEXTCOLOR" ]] && TEXTCOLORFORM="38;5;${TEXTCOLOR};"

        local TEXTFORM="${TEXTCOLORFORM}48;5;${COLOR}m"

        echo -en "\e[${TEXTFORM} ${COLOR}\t\e[0m"

        [[ $(( (COLOR + 1) % 16 )) -eq 0 ]] && echo
    done

    return 0
}
Run Code Online (Sandbox Code Playgroud)

然后,在另一个文件中,调用这些函数后source

source color-functions.sh

# Loops through and prints all ANSI escape sequence's available text colors
color_list_text
# Loops through and prints all ANSI escape sequence's available text backgrounds
color_list_backgrounds
Run Code Online (Sandbox Code Playgroud)

这是一个兼具两者功能的函数...但我认为它有点过分了,因为输出太大(将输出 256 * 256 = 2^16 组合):

function color_list_text_and_backgrounds() {
    local BG
    for BG in {0..255}; do
        local TEXT
        for TEXT in {0..255}; do
            echo -en "\e[38;5;${TEXT};48;5;${BG}m ${TEXT}\t\e[0m"

            if [[ $(( (TEXT + 1) % 8 )) -eq 0 ]]; then
                if [[ $(( ((TEXT + 1) / 8) )) -eq 16 ]]; then
                    local INVBG=$(( (BG + 128) % 256 ))
                    echo -en "\e[38;5;${INVBG};48;5;${BG}m ${BG}\t\e[0m"
                else
                    echo -en "\e[48;5;${BG}m\t\e[0m"
                fi

                echo
            fi
        done
    done

    return 0
}
Run Code Online (Sandbox Code Playgroud)

您的用例

为了给某些东西涂上某些颜色,我们可以使用egrep -i-i标志不区分大小写)和GREP_COLOR变量:

echo "Some string to color" | \
    GREP_COLOR='38;5;200' egrep -i --color=always 'some' | \
    GREP_COLOR='38;5;100' egrep -i --color=always 'string|color'
Run Code Online (Sandbox Code Playgroud)

或者我们可以非常聪明,将其功能化:

color_text_match() {
    MATCHSTRING="$1"
    COLOR="$2"

    [[ -z "$MATCHSTRING" ]] && echo "color_text_match: No color specifies." 
    [[ -z "$COLOR" ]] && COLOR="214"   # Default orange

    GREP_COLOR="38;5;$COLOR" egrep -i --color=always "$MATCHSTRING"
}
Run Code Online (Sandbox Code Playgroud)

然后:

echo "Some string to color" | \
    color_text_match "Some" | \
    color_text_match "string" | \
    color_text_match "to" "226"
Run Code Online (Sandbox Code Playgroud)