漂亮的打印列中的颜色转义码

时间:2013-11-22 18:07:12

标签: bash unix escaping multiple-columns

我有一个制表符分隔的文本文件,我将其发送到column以“打印”表格。

原始档案:

1<TAB>blablablabla<TAB>aaaa bbb ccc
2<TAB>blabla<TAB>xxxxxx
34<TAB>okokokok<TAB>zzz yyy

使用column -s$'\t' -t <original file>,我得

1  blablablabla aaaa bbb xxx
2  blabla       xxxxxx
34 okokokok     zzz yyy

根据需要。现在我想为列添加颜色。我试图在原始文件中的每个制表符分隔字段周围添加转义码。 column成功打印颜色,但列不再对齐。相反,它只是逐字打印TAB分隔符。

问题是:如何使列对齐,还能使用独特的颜色?

我想过两种方法来实现这个目标:

  1. 调整column参数以使对齐与颜色代码一起使用
  2. 将列的输出重定向到另一个文件,并在前两个以空格分隔的字段上执行搜索+替换(前两列保证包含空格;第三列最有可能将包含空格,但没有TAB字符)
  3. 问题是,我不确定如何做到这两个......

    供参考,以下是我传递给column的内容:

    Original file with color codes

    请注意,这些字段确实由TAB字符分隔。我已使用od确认了这一点。

    修改

    着色似乎没有问题。我已经有上面显示的文件,颜色代码正常工作。一旦我使用转义码发送输入,问题是column将不会对齐。我正在考虑将没有颜色代码的字段传递给column,然后在每个字段之间复制确切的空格数column,并在漂亮的打印方案中使用它。

4 个答案:

答案 0 :(得分:4)

我写了一个bash版本的列(类似于util-linux中的一个),它使用颜色代码:

#!/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

使用示例:

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

输出示例:

enter image description here

答案 1 :(得分:3)

我会使用awk进行着色(sed也可以使用):

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 

并将其传输到column以进行对齐:

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

输出:

output

答案 2 :(得分:3)

使用printf格式化输出的解决方案:

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

答案 3 :(得分:0)

就我而言,我想根据列的值选择性地为列中的值着色。假设我希望okokokok为绿色,blabla为红色。

我可以这样做(想法是在列化后将列的值着色):

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

或者,使用变量:

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

请注意颜色定义值中的其他反斜杠。 sed的目的是不解释原始的后窗。

这是结果:

enter image description here