tput setaf tabela de cores? Como determinar os códigos de cores?

79

Estou no processo de colorir o meu terminal PS1.

Estou definindo variáveis ​​de cores usando tput; por exemplo, aqui está roxo:

PURPLE=$(tput setaf 125)

Pergunta, questão:

Como encontro os códigos de cores (por exemplo 125) de outras cores?

Existe algum guia / tabela de cores em algum lugar?

Só não tenho certeza do que 125é ... Existe alguma maneira de pegar uma cor hexadecimal e converter em um número que setafpossa ser usado?

mhulse
fonte

Respostas:

153

A contagem de cores disponíveis para o tput é dada por tput colors.

Para ver as 8 cores básicas (usadas setfno terminal urxvt e setafno terminal xterm):

$ printf '\e[%sm▒' {30..37} 0; echo           ### foreground
$ printf '\e[%sm ' {40..47} 0; echo           ### background

E geralmente chamado assim:

Color       #define       Value       RGB
black     COLOR_BLACK       0     0, 0, 0
red       COLOR_RED         1     max,0,0
green     COLOR_GREEN       2     0,max,0
yellow    COLOR_YELLOW      3     max,max,0
blue      COLOR_BLUE        4     0,0,max
magenta   COLOR_MAGENTA     5     max,0,max
cyan      COLOR_CYAN        6     0,max,max
white     COLOR_WHITE       7     max,max,max

Para ver as 256 cores estendidas (conforme usadas setafno urxvt):

$ printf '\e[48;5;%dm ' {0..255}; printf '\e[0m \n'

Se você deseja números e uma saída ordenada:

#!/bin/bash
color(){
    for c; do
        printf '\e[48;5;%dm%03d' $c $c
    done
    printf '\e[0m \n'
}

IFS=$' \t\n'
color {0..15}
for ((i=0;i<6;i++)); do
    color $(seq $((i*36+16)) $((i*36+51)))
done
color {232..255}

256 cartela de cores em sequência, rotuladas com seu índice


As 16 milhões de cores precisam de bastante código (alguns consoles não podem mostrar isso).
O básico é:

fb=3;r=255;g=1;b=1;printf '\e[0;%s8;2;%s;%s;%sm▒▒▒ ' "$fb" "$r" "$g" "$b"

fbé front/backou 3/4.

Um teste simples da capacidade do console de apresentar tantas cores é:

for r in {200..255..5}; do fb=4;g=1;b=1;printf '\e[0;%s8;2;%s;%s;%sm   ' "$fb" "$r" "$g" "$b"; done; echo

linha vermelha, desbotando de mais escuro para mais claro (da esquerda para a direita) Apresentará uma linha vermelha com uma mudança muito pequena no tom da esquerda para a direita. Se essa pequena alteração estiver visível, seu console poderá ter 16 milhões de cores.

Cada r, ge bé um valor de 0 a 255 para RGB (Red, Green, Blue).

Se o seu tipo de console suportar isso, este código criará uma tabela de cores:

mode2header(){
    #### For 16 Million colors use \e[0;38;2;R;G;Bm each RGB is {0..255}
    printf '\e[mR\n' # reset the colors.
    printf '\n\e[m%59s\n' "Some samples of colors for r;g;b. Each one may be 000..255"
    printf '\e[m%59s\n'   "for the ansi option: \e[0;38;2;r;g;bm or \e[0;48;2;r;g;bm :"
}
mode2colors(){
    # foreground or background (only 3 or 4 are accepted)
    local fb="$1"
    [[ $fb != 3 ]] && fb=4
    local samples=(0 63 127 191 255)
    for         r in "${samples[@]}"; do
        for     g in "${samples[@]}"; do
            for b in "${samples[@]}"; do
                printf '\e[0;%s8;2;%s;%s;%sm%03d;%03d;%03d ' "$fb" "$r" "$g" "$b" "$r" "$g" "$b"
            done; printf '\e[m\n'
        done; printf '\e[m'
    done; printf '\e[mReset\n'
}
mode2header
mode2colors 3
mode2colors 4

gráfico de cores de primeiro plano de amostra com seu índice como rótulos

gráfico de cores de plano de fundo de amostra com seu índice como rótulos

Para converter um valor de cor hexadecimal em um índice de cores 0-255 (mais próximo):

fromhex(){
    hex=${1#"#"}
    r=$(printf '0x%0.2s' "$hex")
    g=$(printf '0x%0.2s' ${hex#??})
    b=$(printf '0x%0.2s' ${hex#????})
    printf '%03d' "$(( (r<75?0:(r-35)/40)*6*6 + 
                       (g<75?0:(g-35)/40)*6   +
                       (b<75?0:(b-35)/40)     + 16 ))"
}

Use-o como:

$ fromhex 00fc7b
048
$ fromhex #00fc7b
048

Para encontrar o número da cor conforme usado no formato de cores HTML :

#!/bin/dash
tohex(){
    dec=$(($1%256))   ### input must be a number in range 0-255.
    if [ "$dec" -lt "16" ]; then
        bas=$(( dec%16 ))
        mul=128
        [ "$bas" -eq "7" ] && mul=192
        [ "$bas" -eq "8" ] && bas=7
        [ "$bas" -gt "8" ] && mul=255
        a="$((  (bas&1)    *mul ))"
        b="$(( ((bas&2)>>1)*mul ))" 
        c="$(( ((bas&4)>>2)*mul ))"
        printf 'dec= %3s basic= #%02x%02x%02x\n' "$dec" "$a" "$b" "$c"
    elif [ "$dec" -gt 15 ] && [ "$dec" -lt 232 ]; then
        b=$(( (dec-16)%6  )); b=$(( b==0?0: b*40 + 55 ))
        g=$(( (dec-16)/6%6)); g=$(( g==0?0: g*40 + 55 ))
        r=$(( (dec-16)/36 )); r=$(( r==0?0: r*40 + 55 ))
        printf 'dec= %3s color= #%02x%02x%02x\n' "$dec" "$r" "$g" "$b"
    else
        gray=$(( (dec-232)*10+8 ))
        printf 'dec= %3s  gray= #%02x%02x%02x\n' "$dec" "$gray" "$gray" "$gray"
    fi
}

for i in $(seq 0 255); do
    tohex ${i}
done

Use-o como ("básico" são as primeiras 16 cores, "cor" é o grupo principal, "cinza" é as últimas cores cinza):

$ tohex 125                  ### A number in range 0-255
dec= 125 color= #af005f
$ tohex 6
dec=   6 basic= #008080
$ tohex 235
dec= 235  gray= #262626
Jeff Schaller
fonte
Sua função fromhex é ótima! Muito obrigado!
Mhulse
Amando fromhex. Obrigado novamente! Além disso, adicionei uma verificação para o# . Comentários?
Mhulse
1
Sim, remover um '#' inicial é uma proteção razoável. Acho muito mais simples de usar hex=${1#"#"}. Ele não removerá nada se $1não tiver um #e removerá se existir. Veja meu código atualizado.
Agradável! Muito mais compacto. Atualizando meu código agora. Obrigado!!!!
Mhulse 12/03/16
Observe que, pelo menos na minha versão do xterm \e[0;%s8;2;%s;%s;%sm, não me dá 16 milhões de cores, apenas a cor da paleta de 240 cores mais próxima do rgb solicitado.
Stéphane Chazelas
14

A resposta curta é que você pode encontrar na web tabelas de cores e combiná-las com o número da cor.

A resposta longa é que o mapeamento correto depende do terminal -

O 125é um parâmetro para uma sequência de escape referida setafna descrição do terminal. tputnão atribui nenhum significado particular ao número. Isso realmente depende do emulador de terminal específico.

Há um tempo, o ANSI definia códigos para 8 cores e havia dois esquemas para numerá-los. Os dois são vistos em algumas descrições de terminais como pares setf/setbou setaf/setab. Como o último tem a conotação de "cores ANSI", você verá que é usado com mais frequência. O antigo (setf / setb) alterou a ordem de vermelho / azul, conforme observado nas Perguntas frequentes das ncurses Por que o vermelho / azul é trocado? , mas em ambos os casos, o esquema foi estabelecido apenas para numerar as cores. Não há relacionamento predefinido entre esses números e o conteúdo RGB.

Para emuladores de terminal específicos, existem paletas de cores predefinidas que podem ser enumeradas com bastante facilidade - e podem ser programadas usando essas seqüências de escape. Não padrões relevantes e você verá diferenças entre os emuladores de terminal, conforme observado nas Perguntas frequentes do xterm . Não gosto desse tom de azul .

No entanto, a convenção costuma ser confundida com os padrões. No desenvolvimento do xterm nos últimos 20 anos, incorporou cores ANSI (8), adaptou as cores do aixtermrecurso (16), adicionou extensões para 88 e 256 cores. Muito disso foi adotado por outros desenvolvedores para diferentes emuladores de terminal. Isso está resumido nas Perguntas frequentes do xterm Por que não fazer "xterm" igual a "xterm-256color"? .

O código-fonte xterm inclui scripts para demonstrar as cores, por exemplo, usando as mesmas seqüências de escape que tputseriam usadas.

Você também pode achar útil esta pergunta / resposta: Valores RGB das cores no índice de cores estendidas da Ansi (17-255)

Thomas Dickey
fonte
Muito obrigado pela sua ajuda Thomas, eu realmente aprecio isso! Estou em um Mac / OS X executando o iTerm. Sua explicação realmente me ajuda a entender mais sobre minha configuração (fiz várias cópias / colagens de cores de várias pessoas na web). Eu realmente aprecio que você reserve um tempo para me escrever uma resposta detalhada e informativa. :)
mhulse
9

O tpututilitário está usando uma tabela de pesquisa de 256 cores para imprimir seqüências de escape ANSI de 8 bits (iniciando com Esce [) que utiliza os recursos do terminal , para que essas seqüências de controle possam ser interpretadas como cores. Estes são um conjunto predefinido de 256 cores, comumente usadas em placas gráficas.

Para imprimir todas as 256 cores no terminal, tente a seguinte linha:

for c in {0..255}; do tput setaf $c; tput setaf $c | cat -v; echo =$c; done

Dica: Anexe | columnà lista de colunas.

Esta tabela de pesquisa de 256 cores também pode ser encontrada na página da Wikipedia da seguinte forma:

Gráfico;  Código de escape ANSI;  Tabela de pesquisa de 256 cores de 8 bits na Wikipedia;  Modo de 256 cores - primeiro plano: ESC [38; 5; #m plano de fundo: ESC [48; 5; #m

kenorb
fonte
3

Com zsh e num xtermterminal de -como ( xterme vteterminais baseados como gnome-terminal, xfce4-terminal... pelo menos) que você pode fazer:

$ read -s -t1 -d $'\a' $'c?\e]4;125;?\a' && echo "${c##*;}"
rgb:afaf/0000/5f5f

O equivalente do bash:

read -s -t1 -d $'\a' -p $'\e]4;125;?\a' c && echo "${c##*;}"

(você deseja que a sequência de escape consulte a cor a ser enviada após a disciplina do terminal echoser desativada (com -s); caso contrário, a resposta será exibida pela disciplina de linha na metade do tempo, portanto, o envio dela como parte do readprompt ( var?promptem zsh como no ksh, -p promptno bash)).

para obter a definição da cor 125 (aqui como uma especificação RGB, cada número sendo a intensidade dos componentes Vermelho, Verde e Azul como um número hexadecimal entre 0 e FFFF).

Você pode fazer o mesmo nas 16 primeiras cores com o xtermcontrolcomando:

$ xtermcontrol --get-color1
rgb:cdcd/0000/0000
Stéphane Chazelas
fonte
Incrível, muito obrigado pela ajuda! 1
mhulse
@Gilles, você deseja que a consulta seja enviada via prompt após o eco da disciplina do terminal ser desativado. Veja editar.
Stéphane Chazelas
@ StéphaneChazelas Usando outro programa de terminal (gnome-terminal) (que é um terminal xterm), obtive seu código para funcionar corretamente (tanto no bash quanto no zsh) Estranhamente: tput colorsinforma apenas 8se o terminal é capaz de apresentar 256 cores. Além disso, o xterm-color (Konsole) tput colorssomente reporta 8mesmo que esse terminal seja totalmente capaz de apresentar 16 milhões de cores (e todas as 256 cores, é claro). E não, nenhum tmux ou tela que possa "colorir" :-) (altere isso) os resultados (eu estava ciente desse detalhe). Em resumo: seu código pode falhar em alguns terminais / consoles.
Ah, o tohex adicionou à minha resposta, um pouco mais do que eu esperava, mas as 256 cores têm algumas curvas peculiares.
0

Cores ANSI no termo do console

Dependendo de qual protocolo de termo o console usa, a sequência pode ser: \e[38;5;XXXmou \e[3XXXmonde XXXcorresponde ao número da ansi.

Para garantir que você use a sequência ANSI correta, você deve usar tput.

Em relação ao código de escape ANSI da Wikipedia , escrevi o seguinte:

#!/bin/bash


for ((i=0; i<256; i++)) ;do
    echo -n '  '
    tput setab $i
    tput setaf $(( ( (i>231&&i<244 ) || ( (i<17)&& (i%8<2)) ||
        (i>16&&i<232)&& ((i-16)%6 <(i<100?3:2) ) && ((i-16)%36<15) )?7:16))
    printf " C %03d " $i
    tput op
    (( ((i<16||i>231) && ((i+1)%8==0)) || ((i>16&&i<232)&& ((i-15)%6==0)) )) &&
        printf "\n" ''
done

Pode render algo como:

insira a descrição da imagem aqui

... Então, porque eu odeio rodar mais de 200 garfos em um pequeno script, escrevi isso:

#!/bin/bash

# Connector fifos directory
read TMPDIR < <(mktemp -d /dev/shm/bc_shell_XXXXXXX)

fd=3
# find next free fd
nextFd() { while [ -e /dev/fd/$fd ];do ((fd++)) ;done;printf -v $1 %d $fd;}

tputConnector() {
    mkfifo $TMPDIR/tput
    nextFd TPUTIN
    eval "exec $TPUTIN> >(LANG=C exec stdbuf -o0 tput -S - >$TMPDIR/tput 2>&1)"
    nextFd TPUTOUT
    eval "exec $TPUTOUT<$TMPDIR/tput"
}
myTput() { echo -e "$1\ncr" 1>&$TPUTIN && IFS= read -r -d $'\r' -u $TPUTOUT $2
}
tputConnector

myTput op op
myTput "setaf 7" grey
myTput "setaf 16" black
fore=("$black" "$grey")
for ((i=0; i<256; i++)) ;do
    myTput "setab $i" bgr
    printf "  %s%s  %3d  %s" "$bgr" "${fore[ i>231 && i<244||(i<17)&& (i%8<2)||
        (i>16&&i<232)&&((i-16)%6*11+(i-16)/6%6*14+(i-16)/36*10)<58
        ? 1 : 0 ]}" $i "$op"
    (( ((i<16||i>231) && ((i+1)%8==0)) || ((i>16&&i<232)&& ((i-15)%6==0)) )) &&
        printf "\n" ''
done

Com apenas 1 garfo! Mesmo resultado, mas muito mais rápido!

F. Hauri
fonte