Выделите значения, разделенные табуляцией, на основе нескольких правил

У меня есть какой-то разделенный табуляцией файл, для которого я хочу условно выделить определенные столбцы или определенные значения.

Пример исходного файла:

wn       name          Building Name       8       Desc       char       -> bl
wo       bl_id!*       Building Code       8                  char

Я бы хотел:

  • выделите желтым цветом содержимое 2-го столбца, когда к имени добавляется суффикс "!"
  • поместите в голубой содержимое 2-го столбца, а в зеленый - содержимое 7-го столбца, когда есть такой 7-й столбец
  • поместите маленький знак "*" в красный столбец во 2-й колонке

и пара других таких правил.

В настоящее время я делаю это следующим образом:

cat file.tsv
    | sed -r 's/^([^\t]*)\t([^\t]*)!/\1\t\x1b[33m\2!\x1b[0m/' \
    | sed -r 's/^^([^\t]*)\t([^\t]*)\t(.*)\t-> ([^\t]+)/\1\t\x1b[36m\2\x1b[0m\t\3\t-> \x1b[32m\4\x1b[0m/' \
    | sed -r 's/\*/\x1b[31;1m&\x1b[0m/'

Но это довольно сложно читать и обновлять.

Есть ли способ лучше? Я совершенно уверен, но какой?

Есть вещи вроде GRC или Supercat? Тем не менее, я должен признать, что у меня есть довольно важное ограничение: я хотел бы, чтобы решение работало "из коробки" в Cygwin. Я не хочу собирать свои инструменты там - по причинам переносимости моего кода.

Можете ли вы дать подсказки о том, как улучшить код, чтобы получить такую ​​"изюминку" функциональности?

2 ответа

Решение

Вы можете сделать это с помощью GNU awk, вот так (col.awk):

function colText ( text, col) { 
    return sprintf("\033[%sm%s\033[39;0m", col, text); 
}

function yellow( text ){ return colText( text, "33;1" ); }
function cyan  ( text ){ return colText( text, "36;1" ); }
function green ( text ){ return colText( text, "32;1" ); }
function red   ( text ){ return colText( text, "31;1" ); } 

BEGIN {FS=OFS="\t";}

# red * in $2
$2 ~ /\*/ {gsub(/\*/, red("*"), $2); }

# cyan if col 7 present
NF == 7 {print $1, cyan($2), $3, $4, $5, $6, green( $7 ) ;
         next;}

# yellow col2 if there is a !  
$2 ~ /!/ {print $1, yellow($2), $3, $4, $5, $6, $7 }

Используйте это так gawk -f col.awk file.tsv

Вы можете сделать скрипт более читабельным, используя переменные оболочки (и tput для переносимости между типами терминалов):

BOLD_RED=$(tput setaf 1; tput bold)
GREEN=$(tput setaf 2)
YELLOW=$(tput setaf 3)
CYAN=$(tput setaf 6)
COLOR_OFF=$(tput sgr0)

cat file.tsv
    | sed -r 's/^([^\t]*)\t([^\t]*)!/\1\t'"$YELLOW"'\2!'"$COLOR_OFF"'/' \
    | sed -r 's/^([^\t]*)\t([^\t]*)\t(.*)\t-> ([^\t]+)/\1\t'"$CYAN"'\2'"$COLOR_OFF"'\t\3\t-> '"$GREEN"'\4'"$COLOR_OFF"'/' \
    | sed -r 's/\*/'"$BOLD_RED"'&'"$COLOR_OFF"'/'

Аналогично, вы могли бы создать переменную для порции регулярного выражения, которая является чем угодно, кроме вкладок, например,

NO_TABS='([^\t]*)'

Кстати, один из sed выражения повторяются ^ (опечатка).

Другие вопросы по тегам