Como você colorir apenas algumas palavras-chave para um script bash?


10

Estou executando algum código de teste de unidade. O código do teste de unidade gera texto normal. Há muito texto, por isso quero destacar para as palavras-chave importantes do usuário.

Nesse caso, as palavras-chave são "PASS" e "FAIL".

Como você define "PASS" como verde e "FAIL" como vermelho?


Você já pensou em suprimir stdout / stderr de testes aprovados e imprimir apenas stdout / stderr para testes com falha? O PHPUnit faz isso ou é configurável para fazer isso. Eu descobri que essa abordagem funciona muito bem, YMMV.
— Clayton Stanley

Respostas:


8

supercat parece fazer o que você está procurando.

Pacote: supercat
Description-pt: programa que coloriza o texto para terminais e HTML
 O Supercat é um programa que coloriza o texto com base na correspondência regular
 expressões / strings / caracteres. Supercat também suporta saída html
 como texto ASCII padrão. Ao contrário de alguns programas de coloração de texto que
 existir, o Supercat não exige que você seja um programador para
 faça regras de coloração.
Página inicial: http://supercat.nosredna.net/

Não parece haver nenhuma maneira de dizer o que colorir na linha de comando, você precisa especificar um arquivo de configuração.

Lembro-me de que costumava haver um programa chamado 'hilite' ou 'hl' que realçava o texto que correspondia a um padrão (como grep --colour, mas também exibe linhas não correspondentes), mas não o encontrei quando o procurei.

Finalmente, o GNU greppode ser usado para destacar padrões - mas apenas uma cor pode ser usada (ou seja, você não pode ter PASS em verde e FAIL em vermelho, ambos seriam destacados com a mesma cor).

Canalize seus dados através de algo como isto:

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

Este exemplo usa egrep (aka grep -E), mas -Gregexp básico, -Fstring fixa e -PPCRE também funcionam.

Todas as partidas serão destacadas. O padrão é vermelho ou configure a var. Env GREP_COLOR.

A chave para este trabalho é que a final |$no padrão corresponde ao final da linha (ou seja, todas as linhas correspondem), para que todas as linhas sejam exibidas (mas não coloridas).

O \bsão marcadores de limite de palavras para que ele corresponda por exemplo falhar, mas não FALHA. eles não são necessários; portanto, remova-os se desejar corresponder a palavras parciais.

Aqui está o exemplo de script wrapper para supercat que escrevi ontem. Funciona, mas, ao escrevê-lo, descobri que o supercat não tem nenhuma opção para pesquisas que não diferenciam maiúsculas de minúsculas. IMO, isso torna o programa significativamente menos útil. No entanto, simplificou bastante o script, porque não precisei escrever uma opção '-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
BTW, se você usou, supercatpode modificar o script publicado para gerar um arquivo de configuração temporário com base nos argumentos da linha de comando e, em seguida, chamar spc -c /path/to/your/temp/config. Isso permitiria especificar facilmente cores diferentes para diferentes padrões na linha de comando.
— cas

btw também, eu escrevi um script wrapper simples para fazer isso. Eu tenho que ir trabalhar agora, mas vou limpá-lo, adicionar alguns comentários, etc e publicá-lo hoje mais tarde.
— cas

5

Aqui está um script de uso geral para colorir padrões de regex (provavelmente precisa de retoques):

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

Nomeie-o hilite.she use-o desta maneira:

$ ./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

Fiz isso community wikiporque minha solução não funciona.
— Trevor Boyd Smith

Uma maneira fácil de testar é criar outro script que reproduza o texto com as palavras-chave "PASS" e "FAIL". Isso seria chamado por esse script.
— Trevor Boyd Smith

Um pouco fora do tópico, mas devo salientar que analisar a saída da $BINvia evalna substituição de comandos é provavelmente frágil, complicado e absolutamente perigoso. STDOUT é um fluxo e geralmente deve ser processado por ferramentas como fluxo. Tentar capturar um fluxo inteiro em uma variável não é muito eficiente. Além disso, evalé perigosamente poderoso , portanto, use-o apenas se você realmente souber o que está fazendo.
— Jw013

Substituí o script por um que funcione.
— Angus

@angus, script realmente muito bom e impressionante IMO.
— Trevor Boyd Smith

3

A incorporação de cadeias arbitrárias (como tputsaída) em sedexpressões de substituição é problemática, pois é necessário garantir (escapando) que a cadeia seja de sedsintaxe válida , o que evita mais complexidade. Eu usaria em seu awklugar. Apenas como exemplo:

{ 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 
      }}'

A chave é atribuir as tputseqüências às awkvariáveis, feitas aqui usando as -vopções.


Eu executei seu programa e ele faz o que é necessário. Huzzah! Mas, infelizmente, não sou um guru inábil, por isso acho difícil entender o que está acontecendo. Corrija-me onde estou errado. Para cada nova linha, o awk é executado? O loop for no código-fonte do awk está executando: "para todos os tokens da linha"? então processa cada token?
— Trevor Boyd Smith

Awk pensa em termos de campos e registros. Por padrão, os registros são linhas de texto e os campos não são espaços em branco. Um awkscript consiste em um conjunto de blocos (as coisas entre o {}nível superior). Cada bloco está associado a uma condição - no meu post acima, não há nenhum porque quero agir incondicionalmente em todas as linhas de entrada. O Awk opera lendo registros de arquivos ou de entrada padrão (neste caso, é STDIN b / c, nenhum nome de arquivo foi fornecido) e os associa a cada bloco na ordem, executando o bloco no registro, se a condição corresponder.
— jw013

2

use printf:

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

por exemplo.

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

o último \nadiciona o caractere de nova linha.

para ver os possíveis valores de tentar algo como:

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

além da cor, você pode adicionar modificadores como negrito, sublinhado ou texto colorido com fundo colorido combinando os números. Para criar texto azul com fundo cinza sublinhado e marcado através do uso:

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

Felicidades,

/ B2S


2

Se você estiver feliz em instalar um script BASH e ack, o hhlighterpacote tiver cores padrão úteis e uma interface fácil https://github.com/paoloantinori/hhighlighter :

exemplo de destaque

Você pode usá-lo assim para destacar as linhas que começam com FAIL:

h -i 'FAIL.*'

ou que contenham FAIL:

h -i '.*FAIL.*'

ou para várias entradas de log comuns:

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

E, claro, para uma única cor (vermelho) com grep simples:

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

A ^corresponde a cada linha, mas é uma correspondência especial e imprime a linha inteira. A expressão a ser destacada é definida após a |. Expressões adicionais podem ser adicionadas desde que separadas |.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.