Как раскрасить только некоторые ключевые слова для сценария bash?

10

Я запускаю некоторый код модульного теста. Код модульного теста выводит обычный текст. Здесь много текста, поэтому я хочу выделить для пользователя важные ключевые слова.

В этом случае ключевыми словами являются «PASS» и «FAIL».

Как вы окрашиваете «PASS» в зеленый и «FAIL» в красный?

Тревор Бойд Смит
источник
Задумывались ли вы о подавлении проходящих тестов stdout / stderr и о печати только stdout / stderr для неудачных тестов? PHPUnit делает это или настраивается для этого. Я обнаружил, что этот подход работает довольно хорошо, YMMV.
Клейтон Стэнли

Ответы:

8

supercat кажется, делает то, что вы ищете.

Пакет: суперкат
Description-ru: программа, которая раскрашивает текст для терминалов и HTML
 Supercat - это программа, которая раскрашивает текст на основе соответствия обычному
 выражения / строки / символы. Supercat также поддерживает вывод html
 как стандартный текст ASCII. В отличие от некоторых программ для раскрашивания текста, которые
 существует, Supercat не требует, чтобы вы были программистом
 сделать правила окраски.
Домашняя страница: http://supercat.nosredna.net/

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

Кажется, я вспоминал, что раньше была программа под названием «hilite» или «hl», которая выделяла текст, который соответствовал шаблону (например grep --colour, но отображал также несоответствующие строки), но я не мог найти его, когда искал его.

Наконец, GNU grepможно использовать для выделения шаблонов, но можно использовать только один цвет (т. Е. У вас не может быть PASS в зеленом и FAIL в красном, оба будут выделены одним и тем же цветом).

Передайте данные через что-то вроде этого:

egrep --color "\b(PASS|FAIL)\b|$"

В этом примере используется egrep (aka grep -E), но также работают -Gбазовые регулярные выражения, -Ffixed-string и -PPCRE.

Все совпадения будут выделены. По умолчанию красный или установите GREP_COLOR env var.

Ключом к этой работе является то, что финал |$в шаблоне соответствует концу строки (т.е. все строки совпадают), поэтому все строки будут отображаться (но не раскрашиваться).

Это \bмаркеры границы слова, так что они соответствуют, например, FAIL, но не FAILURE. они не нужны, поэтому удалите их, если вы хотите сопоставить отдельные слова.

Вот пример скрипта-обёртки для supercat, который я написал вчера. Это работает, но при написании этого я обнаружил, что у supercat нет возможности поиска без учета регистра. ИМО, что делает программу значительно менее полезной. Однако это значительно упростило сценарий, поскольку мне не нужно было писать опцию '-i' :)

#! /bin/bash 

# Requires: tempfile from debian-utils, getopt from util-linux, and supercat

SCRIPTNAME=$(basename $0)
CFGFILE=$(tempfile -p spc)

usage() {
  cat <<__EOF__
Highlight regexp patterns found on stdin or files specified on command
line with specified colours.

Usage: $SCRIPTNAME [ --colour "pattern" ...] [FILE]

Options:

        -k,--black   regexp
        -r,--red     regexp
        -g,--green   regexp
        -y,--yellow  regexp
        -b,--blue    regexp
        -m,--magenta regexp
        -c,--cyan    regexp
        -w,--white   regexp

Example:

    run-script.sh | $SCRIPTNAME --green PASS --red FAIL

__EOF__
  exit 0
}


# Format definition from the spc man page:
#1234567890123456789012345678901234567890123456789012345
#HTML Color Name      Col A N T RE / String / Characters
FMT="%-20s %3s %1s %1s %1s (%s)\n"

add_color_to_config() {
  COLOR="$1"
  PATTERN="$2"

  printf "$FMT" "$COLOR" "$COLOR" - 0 r "$PATTERN" >> "$CFGFILE"
}


# uses the "getopt" program from util-linux, which supports long
# options. The "getopts" built-in to bash does not.
TEMP=$(getopt \
       -o 'hk:r:g:y:b:m:c:w:' \
       -l 'help,black:,red:,green:,yellow:,blue:,magenta:,cyan:,white:' \
       -n "$0" -- "$@")

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

eval set -- "$TEMP"

while true ; do
    case "$1" in
        -k|--bla*)       add_color_to_config blk "$2" ; shift 2 ;;
        -r|--red)        add_color_to_config red "$2" ; shift 2 ;;
        -g|--gre*)       add_color_to_config grn "$2" ; shift 2 ;;
        -y|--yel*)       add_color_to_config yel "$2" ; shift 2 ;;
        -b|--blu*)       add_color_to_config blu "$2" ; shift 2 ;;
        -m|--mag*)       add_color_to_config mag "$2" ; shift 2 ;;
        -c|--cya*)       add_color_to_config cya "$2" ; shift 2 ;;
        -w|--whi*)       add_color_to_config whi "$2" ; shift 2 ;;

        -h|--hel*)       usage ; exit 0 ;;

        --)         shift ; break ;;

        *)          echo 'Unknown option!' ; exit 1 ;;
    esac
done

spc -R -c "$CFGFILE" "$@"
rm -f "$CFGFILE"
саз
источник
1
Кстати, если вы использовали, supercatвы можете изменить скрипт, который вы разместили, чтобы создать временный файл конфигурации на основе аргументов командной строки, а затем вызвать spc -c /path/to/your/temp/config. Это позволит вам легко указывать разные цвета для разных шаблонов в командной строке.
Cas
Кроме того, я написал простой скрипт-обертку, чтобы сделать это. Я должен идти на работу сейчас, но я уберу это, добавлю некоторые комментарии и т. д. и опубликую это позже сегодня.
Cas
5

Вот скрипт общего назначения для раскрашивания шаблонов регулярных выражений (вероятно, требуется некоторая ретушь):

#! /bin/bash

color_to_num () {
  case $1 in
    black)  echo 0;;
    red)    echo 1;;
    green)  echo 2;;
    yellow) echo 3;;
    blue)   echo 4;;
    purple) echo 5;;
    cyan)   echo 6;;
    white)  echo 7;;
    *)      echo 0;;
  esac
}

# default values for foreground and background colors
bg=
fg=
bold="$(tput bold)"
italics=""
boundary=""

while getopts f:b:sli option; do
  case "$option" in
    f) fg="$OPTARG";;
    b) bg="$OPTARG";;
    s) bold="";;
    l) boundary=".*";;
    i) italics="$(tput sitm)";;
  esac
done

shift $(($OPTIND - 1))

pattern="$*"

if [ -n "$fg" ]; then
  fg=$(tput setaf $(color_to_num $fg))
fi
if [ -n "$bg" ]; then
  bg=$(tput setab $(color_to_num $bg))
fi

if [ -z "$fg$bg" ]; then
  fg=$(tput smso)
fi

sed "s/${boundary}${pattern}${boundary}/${bold}${italics}${fg}${bg}&$(tput sgr0)/g"

Назовите это hilite.shи используйте это так:

$ ./BIN_PROGRAM | hilite.sh -f green PASS | hilite.sh -f red FAIL

$ # Here is an example one liner
$ echo -e "line 1: PASS\nline 2: FAIL" | hilite.sh -f green PASS | hilite.sh -f red FAIL
Trevor Boyd Smith
источник
Я сделал это, community wikiпотому что мое решение не работает.
Тревор Бойд Смит
Самый простой способ проверить это - создать другой скрипт, который отображает текст с ключевыми словами «PASS» и «FAIL». Это будет тогда вызываться этим сценарием.
Тревор Бойд Смит
Немного не по теме, но я должен отметить, что анализ вывода команды $BINvia evalна подстановку команд, вероятно, хрупок, громоздок и совершенно опасен. STDOUT - это поток и обычно предназначен для обработки потоковыми инструментами. Попытка перехватить весь поток в переменной не очень эффективна. Кроме того, evalэто опасно мощно , поэтому используйте его, только если вы действительно знаете, что делаете.
jw013
Я заменил скрипт на рабочий.
ангус
@angus, действительно очень хороший и впечатляющий сценарий IMO.
Тревор Бойд Смит
3

Встраивание произвольных строк (например, tputвыходных данных) в sedвыражения замены проблематично, потому что вы должны убедиться (путем экранирования), что строка является допустимым sedсинтаксисом, а это более сложная задача, которую лучше избегать. Я бы использовал awkвместо этого. Просто в качестве примера:

{ echo line 1: PASS; echo line 2: FAIL; } | 
    awk -v "red=$(tput setaf 1)" -v "green=$(tput setaf 2)" \
        -v "reset=$(tput sgr0)" '
    { for (i = 1; i <= NF; i++) {
           if ($i == "FAIL") printf "%s", red "FAIL" reset;
           else if ($i == "PASS") printf "%s", green "PASS" reset;
           else printf "%s", $i

           if (i == NF) printf "%s", ORS
           else printf "%s", OFS 
      }}'

Ключ заключается в том, чтобы назначить tputпоследовательности awkпеременным, что делается здесь с помощью -vпараметров.

jw013
источник
Я запустил вашу программу, и она делает то, что нужно. Ура! Но, к сожалению, я не гуру ака, поэтому мне трудно понять, что происходит. Поправь меня, где я не прав. Для каждой новой строки awk запускается? Цикл for в исходном коде awk делает: «для всех токенов в строке»? тогда он обрабатывает каждый токен?
Тревор Бойд Смит
Awk мыслит в терминах полей и записей. По умолчанию записи представляют собой строки текста, а поля не являются пробелами. awkСценарий состоит из набора блоков (материал между {}на уровне верхнего). Каждый блок связан с условием - в моем посте выше его нет, потому что я хочу безоговорочно действовать на каждую строку ввода. Awk работает путем чтения записей из файлов или стандартного ввода (в данном случае это STDIN, поскольку имена файлов не были предоставлены), и сопоставляет их с каждым блоком по порядку, выполняя блок в записи, если условие соответствует.
jw013
2

используйте printf:

printf "\e[%sm%s\e[00m\n" <some_number> <text_in_colour>

например.

printf "\e[%sm%s\e[00m\n" 32 yodle

последний \nдобавляет символ новой строки.

чтобы увидеть возможные значения попробуйте что-то вроде:

for i in {0..9} {30..38} {90..98} {100..108};
do
    printf "%d:\e[%sm%s\e[00m\n" $i "$i" yodle;
done

Помимо цвета вы можете добавить модификаторы, такие как жирный или подчеркнутый или цветной текст с цветным фоном, комбинируя числа. Чтобы создать синий текст с серым фоном, который подчеркнут и вычеркнут с помощью:

printf "\e[%sm%s\e[00m\n" "4;9;34;107" yodle

Ура,

/ B2S

Born2Smile
источник
2

Если вы готовы установить скрипт BASH и ack, hhlighterпакет имеет полезные цвета по умолчанию и простой интерфейс https://github.com/paoloantinori/hhighlighter :

пример

Вы можете использовать его так, чтобы выделить строки, начинающиеся с FAIL:

h -i 'FAIL.*'

или которые содержат FAIL:

h -i '.*FAIL.*'

или для различных общих записей журнала:

h -i '.*FAIL.*' '.*PASS.*' '.*WARN.*'

И конечно, для одного цвета (красного) с простым grep:

$ printf 'Pass: good job\nFail: bad job\n' | grep -Ei --colour=auto '^|fail.*'

Соответствует ^каждой строке, но является специальным сопоставителем и печатает всю строку. Выражение, которое нужно выделить, определяется после a |. Дальнейшие выражения могут быть добавлены, если они разделены |.

Энди
источник