Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to syntax highlight a bash output (some help information)?

Very often I get some help information with the --help flag of a command, which gives the output at the terminal like:

$ 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

I want to syntax highlight the output like the upper half of the link (sorry that I can only post 1 link). I have tried highlight and pygmentize. However, highlight needs to specify a syntax, and pygmentize rendered the output as a wrong style (in the lower half of the link).

I'd like to know if there is a method to make the syntax highlight like this. Do I need to specify a style for pygmentize? Or do I have to turn to another solution?

Thanks!

like image 999
purplezzh Avatar asked Aug 13 '16 09:08

purplezzh


People also ask

How to output text in Linux terminal?

According to the Linux documentation, the following is the syntax for echo command. Now, we shall see the different ways in which we can output the text on the terminal. To output any string or number or text on the terminal, type the following command and press enter. Let’s declare a variable and prints its value on the terminal.

How to tell if sh is actually BASH or not?

You can set the variable g:is_bash to tell the sh syntax file that sh is actually bash, if indeed it is actually bash (does sh --version show the Bash version?). Or you can set g:is_posix if sh is POSIX compliant.

Can bash run scripts without running them?

The answer is yes, including the Bash shell itself. The Bash -n (noexec) option tells Bash to read a script and check it for syntactical errors, without running the script. Depending on what your script is intended to do, this can be a lot safer than running it and looking for problems. Here’s the script we’re going to check.

How do I write Linux shell scripts?

Writing Linux shell scripts poses its own challenges. With a compiled language like C, a program called a compiler reads your source code—the human-readable instructions you type into a text file—and transforms it into a binary executable file. The binary file contains the machine code instructions that the computer can understand and act upon.


1 Answers

ANSI escape strings

Using ANSI escape sequences to achieve what you want, you can create a format string (represented by prepended \e[ and appended m) where 38;5;{0..255} is the 256-color of the text (0..255 being the range of available color codes), and 48;5;{0..255} is the 256-color of background. E.g.,

echo -e "\e[38;5;0;48;5;255mText\e[0m"

will print black text (color code 0) with a white background (color code 255). Note with the echo command it requires the extended mode (toggled by the -e flag) to interpret the ANSI escape string.

Note the trailing \e[0m to unset the coloring, otherwise all text printed after this command with echo will retain the format. \e[0m resets it.

Note an interesting use case that causes an error also. Placing an exclamation point before the ending \e[0m causes this output:

nick@nick-lt:~$ echo -e "\e[38;5;0;48;5;255mText!\e[0m"
bash: !\e[0m: event not found

That's because ! is part of string expansion for Bash. See more on this SO question here. To make that work as expected we need to do:

echo -e "\e[38;5;0;48;5;255mText"'!'"\e[0m"

as single-quotes do not get expanded.


How to print every available color using ANSI escape sequences.

Save these in a file called 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
}

Then, in another file, call the functions after you've source'd them:

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

Here's a function that does both... But I think it's overkill because the output is far too large (256 * 256 = 2^16 combinations will be outputted):

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
}

Your use case

To color certain things certain colors, we can use egrep -i (-i flag is case-insensitive) and the GREP_COLOR variable:

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'

Or we could be real clever and functionise this:

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"
}

Then:

echo "Some string to color" | \
    color_text_match "Some" | \
    color_text_match "string" | \
    color_text_match "to" "226"
like image 175
Nick Bull Avatar answered Oct 17 '22 06:10

Nick Bull