Color escape codes in pretty printed columns

前端 未结 4 718
攒了一身酷
攒了一身酷 2020-12-18 00:39

I have a tab-delimited text file which I send to column to \"pretty print\" a table.

Original file:

1blablablabla

        
相关标签:
4条回答
  • 2020-12-18 01:04

    I wrote a bash version of column (similar to the one from util-linux) which works with color codes:

    #!/bin/bash
    which sed >> /dev/null || exit 1
    
    version=1.0b
    editor="Norman Geist"
    last="04 Jul 2016"
    
    # NOTE: Brilliant pipeable tool to format input text into a table by 
    # NOTE: an configurable seperation string, similar to column
    # NOTE: from util-linux, but we are smart enough to ignore 
    # NOTE: ANSI escape codes in our column width computation
    # NOTE: means we handle colors properly ;-)
    
    # BUG : none
    
    addspace=1
    seperator=$(echo -e " ")
    columnW=()
    columnT=()
    
    while getopts "s:hp:v" opt; do
      case $opt in
    s ) seperator=$OPTARG;;
    p ) addspace=$OPTARG;;
    v ) echo "Version $version last edited by $editor ($last)"; exit 0;;
    h ) echo "column2 [-s seperator] [-p padding] [-v]"; exit 0;;
    * ) echo "Unknow comandline switch \"$opt\""; exit 1
      esac
    done
    shift $(($OPTIND-1))
    
    if [ ${#seperator} -lt 1 ]; then
      echo "Error) Please enter valid seperation string!"
      exit 1
    fi
    
    if [ ${#addspace} -lt 1 ]; then
      echo "Error) Please enter number of addional padding spaces!"
      exit 1
    fi
    
    #args: string
    function trimANSI()
    {
      TRIM=$1
      TRIM=$(sed 's/\x1b\[[0-9;]*m//g' <<< $TRIM); #trim color codes
      TRIM=$(sed 's/\x1b(B//g'         <<< $TRIM); #trim sgr0 directive
      echo $TRIM
    }
    
    #args: len
    function pad()
    {
      for ((i=0; i<$1; i++))
      do 
    echo -n " "
      done
    }
    
    #read and measure cols
    while read ROW
    do
      while IFS=$seperator read -ra COLS; do
    ITEMC=0
    for ITEM in "${COLS[@]}"; do
      SITEM=$(trimANSI "$ITEM"); #quotes matter O_o
      [ ${#columnW[$ITEMC]} -gt 0 ] || columnW[$ITEMC]=0
      [ ${columnW[$ITEMC]} -lt ${#SITEM} ] && columnW[$ITEMC]=${#SITEM}
      ((ITEMC++))
    done
    columnT[${#columnT[@]}]="$ROW"
      done <<< "$ROW"
    done
    
    #print formatted output
    for ROW in "${columnT[@]}"
    do
      while IFS=$seperator read -ra COLS; do
    ITEMC=0
    for ITEM in "${COLS[@]}"; do
      WIDTH=$(( ${columnW[$ITEMC]} + $addspace ))
      SITEM=$(trimANSI "$ITEM"); #quotes matter O_o
      PAD=$(($WIDTH-${#SITEM}))
    
      if [ $ITEMC -ne 0 ]; then
        pad $PAD
      fi
    
      echo -n "$ITEM"
    
      if [ $ITEMC -eq 0 ]; then
        pad $PAD
      fi
    
      ((ITEMC++))
    done
      done <<< "$ROW"
      echo ""
    done
    

    Example usage:

    bold=$(tput bold)
    normal=$(tput sgr0)
    green=$(tput setaf 2)
    
    column2 -s § << END
    ${bold}First Name§Last Name§City${normal}
    ${green}John§Wick${normal}§New York
    ${green}Max§Pattern${normal}§Denver
    END
    

    Output example:

    enter image description here

    0 讨论(0)
  • 2020-12-18 01:08

    A solution using printf to format the ouput as well :

    while IFS=$'\t' read -r c1 c2 c3; do
        tput setaf 1; printf '%-10s' "$c1"
        tput setaf 2; printf '%-30s' "$c2"
        tput setaf 3; printf '%-30s' "$c3"
        tput sgr0; echo
    done < file
    

    enter image description here

    0 讨论(0)
  • 2020-12-18 01:12

    In my case, I wanted to selectively colorise values in a column depending on its value. Let's say I want okokokok to be green and blabla to be red.

    I can do it such way (the idea is to colorise values of columns after columnisation):

    GREEN_SED='\\033[0;32m'
    RED_SED='\\033[0;31m'
    NC_SED='\\033[0m' # No Color
    
    column -s$'\t' -t <original file> | echo -e "$(sed -e "s/okokokok/${GREEN_SED}okokokok${NC_SED}/g" -e "s/blabla/${RED_SED}blabla${NC_SED}/g")"
    

    Alternatively, with a variable:

    DATA=$(column -s$'\t' -t <original file>)
    
    GREEN_SED='\\033[0;32m'
    RED_SED='\\033[0;31m'
    NC_SED='\\033[0m' # No Color
    echo -e "$(sed -e "s/okokokok/${GREEN_SED}okokokok${NC_SED}/g" -e "s/blabla/${RED_SED}blabla${NC_SED}/g" <<< "$DATA")"
    

    Take a note of that additional backslash in values of color definitions. It is made for sed to not interpret an origingal backsash.

    This is a result:

    0 讨论(0)
  • 2020-12-18 01:24

    I would use awk for the colorization (sed can be used as well):

    awk '{printf "\033[1;32m%s\t\033[00m\033[1;33m%s\t\033[00m\033[1;34m%s\033[00m\n", $1, $2, $3;}' a.txt 
    

    and pipe it to column for the alignment:

    ... | column -s$'\t' -t
    

    Output:

    output

    0 讨论(0)
提交回复
热议问题