Contexto e pergunta
Existem várias maneiras de colorir o ambiente do terminal e do shell. A saída de comandos individuais, como ls
e grep
, também pode ser colorida. Não está diretamente relacionada, mas interessante, no entanto, é a noção de reproduzir mídia no console, mas isso parece depender de alguma estrutura (bibliotecas) no topo do sistema de janelas. A pergunta a seguir é voltada apenas para o bash
shell e sua implementação na estrutura de terminal do Linux e seus fundamentos.
Por favor, considere a seguinte montagem de "renderizações" ASCII de uma cena em um jogo 2D :
Essas não são cenas geradas aleatoriamente. Os segmentos que eu selecionei, na verdade, retratam algum tipo de terreno "gramado" (árvores, arbustos, flores, grama etc.) de um jogo que usa caracteres ASCII para representar esses objetos. As últimas 4 cenas mostram conjuntos de peças feitas pelo usuário, que são basicamente um remapeamento de caracteres ASCII com especificações de cores (esses detalhes são triviais - basta dizer que essa é a inspiração visual para o que estou tentando realizar aqui em termos visuais e " padronizar").
Os recursos comuns que essas cenas no compartilhamento de montagem são:
- 5-6 caracteres ASCII diferentes, no máximo (vírgulas, aspas e alguns outros)
- 2-4 cores usadas
- para os personagens
- para os fundos dos personagens em alguns casos - o último exemplo existe para mostrar o uso de tons de cores com pouco ou nenhum caractere para criar um padrão, como mosaico de cores
O que eu tenho em uma VM no momento é o Arch Linux e, embora a questão não seja específica da distribuição, examinei a documentação deles para personalizar o /etc/bash.bashrc
arquivo. Percebo que muitas explicações são necessárias para configurar a aparência do prompt e, geralmente, todos os elementos em primeiro plano. Há pouca informação sobre qualquer configuração do plano de fundo, exceto geralmente para uma cor sólida, como essas configurações e dicas :
# Background
On_Black='\e[40m' # Black
On_Red='\e[41m' # Red
On_Green='\e[42m' # Green
On_Yellow='\e[43m' # Yellow
On_Blue='\e[44m' # Blue
On_Purple='\e[45m' # Purple
On_Cyan='\e[46m' # Cyan
On_White='\e[47m' # White
Ainda não entendo conceitualmente quais são esses "espaços" vazios / em branco / em segundo plano que não digitei quando uso o console, ou seja, "do que eles são feitos?" por assim dizer. Especialmente aqueles que não estão no prompt e que envolvem os comandos que são repetidos. Com relação ao que acontece na linha ativa, é possível demonstrar que bash
atua de maneira "orientada à linha" e que algumas operações acionam uma limpeza da linha ativa ( for i in $(seq 1 $(expr $(tput lines) \* $(tput cols))); do echo -n M; done; tput cup 15 1
, em seguida, no prompt, digite um caractere e a retorne - demonstrada um colaborador) - cuja extensão pode variar de uma CLI para outra, ou seja, zsh. Além disso, parece que quando adiciono algo parecido \[\033[44m\]
à minha linha PS1, bash.bashrc
recebo um plano de fundo azul após recarregar o bash - então, obviamente, eu sei que há algumasaproveite aqui a aparência da saída no que diz respeito ao plano de fundo .
Mas também sei que o bash é um software que depende de alguma outra instalação na forma do subsistema TTY para trazer coisas para a tela - e isso vai daí para o componente VT no kernel que eu assumo. pstree -Ap
no Arch mostra systemd
vinculado ae login
depois a bash
.
A distribuição do Arch Linux depende agetty
de serviços TTY. Um simples echo $TERM
produzirá o tipo de terminal em uso ("linux" aqui fora de qualquer DE) e o infocmp[-d spec1 spec2]
comando sem parâmetro mostra os recursos ativos do terminal e as informações de perfil do banco de dados do terminal terminfo (5) :
# Reconstructed via infocmp from file: /usr/share/terminfo/l/linux
linux|linux console,
am, bce, ccc, eo, mir, msgr, xenl, xon,
colors#8, it#8, ncv#18, pairs#64,
acsc=+\020\,\021-\030.^Y0\333'\004a\261f\370g\361h\260i\316j\331k\277l\332m\300n\305o~p\304q\304r\304s_t\303u\264v\301w\302x\263y\363z\362{\343|\330}\234~\376,
bel=^G, blink=\E[5m, bold=\E[1m, civis=\E[?25l\E[?1c,
clear=\E[H\E[J, cnorm=\E[?25h\E[?0c, cr=^M,
csr=\E[%i%p1%d;%p2%dr, cub=\E[%p1%dD, cub1=^H,
cud=\E[%p1%dB, cud1=^J, cuf=\E[%p1%dC, cuf1=\E[C,
cup=\E[%i%p1%d;%p2%dH, cuu=\E[%p1%dA, cuu1=\E[A,
cvvis=\E[?25h\E[?8c, dch=\E[%p1%dP, dch1=\E[P, dim=\E[2m,
dl=\E[%p1%dM, dl1=\E[M, ech=\E[%p1%dX, ed=\E[J, el=\E[K,
el1=\E[1K, flash=\E[?5h\E[?5l$, home=\E[H,
hpa=\E[%i%p1%dG, ht=^I, hts=\EH, ich=\E[%p1%d@, ich1=\E[@,
il=\E[%p1%dL, il1=\E[L, ind=^J,
initc=\E]P%p1%x%p2%{255}%*%{1000}%/%02x%p3%{255}%*%{1000}%/%02x%p4%{255}%*%{1000}%/%02x,
kb2=\E[G, kbs=\177, kcbt=\E[Z, kcub1=\E[D, kcud1=\E[B,
kcuf1=\E[C, kcuu1=\E[A, kdch1=\E[3~, kend=\E[4~, kf1=\E[[A,
kf10=\E[21~, kf11=\E[23~, kf12=\E[24~, kf13=\E[25~,
kf14=\E[26~, kf15=\E[28~, kf16=\E[29~, kf17=\E[31~,
kf18=\E[32~, kf19=\E[33~, kf2=\E[[B, kf20=\E[34~,
kf3=\E[[C, kf4=\E[[D, kf5=\E[[E, kf6=\E[17~, kf7=\E[18~,
kf8=\E[19~, kf9=\E[20~, khome=\E[1~, kich1=\E[2~,
kmous=\E[M, knp=\E[6~, kpp=\E[5~, kspd=^Z, nel=^M^J, oc=\E]R,
op=\E[39;49m, rc=\E8, rev=\E[7m, ri=\EM, rmacs=\E[10m,
rmam=\E[?7l, rmir=\E[4l, rmpch=\E[10m, rmso=\E[27m,
rmul=\E[24m, rs1=\Ec\E]R, sc=\E7, setab=\E[4%p1%dm,
setaf=\E[3%p1%dm,
sgr=\E[0;10%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p5%t;2%;%?%p6%t;1%;%?%p7%t;8%;%?%p9%t;11%;m,
sgr0=\E[0;10m, smacs=\E[11m, smam=\E[?7h, smir=\E[4h,
smpch=\E[11m, smso=\E[7m, smul=\E[4m, tbc=\E[3g,
u6=\E[%i%d;%dR, u7=\E[6n, u8=\E[?6c, u9=\E[c,
vpa=\E[%i%p1%dd,
Tal como está, muitos recursos podem ser aproveitados a partir da estrutura do terminal e são basicamente os recursos expostos no arquivo de configuração bash.bashrc, desde que o prompt seja personalizado definindo a variável PS1. As seqüências de controle e escape são usadas para interromper basicamente o fluxo de caracteres exibidos no terminal para fornecer funções, incluindo mover o cursor e outros recursos descritos no banco de dados de informações do terminal. Muitas dessas funções são passadas usando o conhecido ESC[
(ou \ 33) Control Sequence Introducer (mais sequências aqui e aqui e alguns exemplos ). Além disso, também é possível usar otput
utilitário diretamente na CLI para alterar algumas propriedades do terminal; por exemplo tput setab 4
, terá comandos bash echo em um fundo azul.
Se pudermos strace bash
ver as seqüências de escape e o comportamento em ação:
write(2, "[il@Arch64vm1 ~]$ ", 19[il@Arch64vm1 ~]$ ) = 19 //bash starts
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, " ", 1) = 1 //pressed <space>
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, " ", 1 ) = 1
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, "\177", 1) = 1 //pressed <backspace>...
rt_sigprocmask(SIG_BLOCK, [INT], [], 8) = 0
write(2, "\10\33[K", ) = 4 //triggers erasing the line
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0
read(0, "\33", 1) = 1 //pressed <esc> per se
Isso fornece contexto para a pergunta Os espaços vazios / cor de fundo em um terminal podem ser substituídos por um conjunto aleatório (mas bonito) de caracteres ASCII? mas não dá idéia de como implementar os recursos ou o que estou procurando no terminal.
Então, eu criei uma maquete bruta como um exemplo de como o resultado final seria se isso fosse possível (não seriamente :):
Basicamente, todo o "espaço vazio" no terminal seria preenchido com o padrão (aqui eu coloco uma imagem da imagem acima, mas eu gostaria que, na implementação real, cada "branco" individual fosse gerado aleatoriamente a partir do conjunto de 5-6 caracteres e características documentadas a partir da montagem que seria especificada). Existe um padrão diferente para a linha de comando ativa, ou seja, "água" ondulada, mas eu aceitaria que a linha fosse azul. Como se imaginava, os comandos "apagariam" a "água" à medida que fossem digitados na linha ativa e, é claro, uma restrição seria que o padrão de caracteres nunca fosse interpretado pela CLI, caso contrário, seria inútil.
Portanto, existe alguma configuração exposta na bash
estrutura do terminal ou adequada, ou um script que permita usar um conjunto de caracteres e algum controle sobre as cores para modificar a saída do bash no terminal, de modo a gerar um padrão um tanto aleatório para o plano de fundo (o que seria semelhante ao que mostrei acima)? Ou devo simplesmente me contentar com algo como tentar fornecer uma imagem padrão completa como pano de fundo para o tty ?
Implementações
0.1 - Versão PatternOTD (oferta única quando você entra)
A seguinte expressão que adicionei ao meu arquivo .bashrc reúne algumas das noções que exploramos e constitui uma prova (muito) básica de conceito para os visuais no terminal linux padrão:
for i in $(seq 1 $(expr $(tput lines))); do echo -en '\E[32;32m'$(tr -dc '",.;:~' < /dev/urandom | head -c $(tput cols)); done; tput cup 15; tput setab 4; echo -en "\E[2K"; tput setab 0
Observações
- Obviamente, é apenas um comando que não é persistente, ou seja, rola para longe à medida que os comandos são digitados
- Optou por não embaralhar individualmente a seleção de caracteres, ou seja,
head -c 1
com atput cols
multiplicação das linhas, para começar, que iria imprimir caracteres aleatórios individuais da seleção citada - porque é muito lento. Eu não acho querandom
gera um inteiro longo (tput cols), mas ainda assim é mais rápido. Certamente tudo isso é um desperdício, mas funciona. - Não selecionou aleatoriamente nenhuma cor ou efeito por caractere ou de outra forma, exceto pelo verde, porque, como expliquei a renderização / processamento de cada caractere individualmente, é muito lento. Re: framebuffer?
- Fico feliz em ver que o padrão não interfere no uso da CLI no sentido de não ser interpretado pela CLI! (por que embora eu não pudesse explicar)
- A água se foi muito rápido! ;-)
0.2 - PROMPT_COMMAND hackear trabalho
O valor da variável PROMPT_COMMAND é examinado imediatamente antes do Bash imprimir cada prompt principal. Eu sei que geralmente você usaria a variável para chamar um script onde você pode processar elementos da exibição etc., mas estou tentando fazer isso diretamente no meu arquivo .bashrc. Inicialmente, pensei em implementar alguma percepção posicional, ou seja, onde está o cursor antes da execução (para que eu pudesse renderizar as coisas na tela em qualquer lugar tput
e voltar à posição em que estava antes, usando algo parecido com isto para extrair posição:
stty -echo; echo -n $'\e[6n'; read -d R x; stty echo; echo ${x#??} //value is in x;x format so...
Eu canalizaria o valor para cut -f1 -d";"
. Posso fazer isso na CLI, mas fazer esse trabalho dentro da sequência de elementos nas variáveis PS1 / P_C está fora do meu alcance no momento e é possível que qualquer comando colocado em PROMPT_COMMAND possa não ser avaliado a cada retorno de carro, mas sim apenas uma vez (?) apesar de ser executado todas as vezes (veja as observações abaixo).
Portanto, o melhor que pude fazer é carregar minha sequência inicial e adicionar alguns comandos ao PROMPT_COMMAND e à definição da variável PS1 no .bashrc. Igual a:
PROMPT_COMMAND="echo -en '\E[32;32m'$(tr -dc ',.:~' < /dev/urandom | head -c $(echo "$[$(tput cols) * 2]"))"
PS1="$(echo -en '\n') $(tput setab 4)$(echo -en "\E[2K")$(tput setab 0)\[\033[7;32m\]df:\[\033[1;34m\] \W @d \[\033[0m\]\e[32m"
for i in $(seq 1 $(expr $(tput lines))); do echo -en '\E[32;32m'$(tr -dc '",.;:~' < /dev/urandom | head -c $(tput cols)); done; tput cup 1; tput setab 4; echo -en "\E[2K"; tput setab 0
Em resumo, estou usando P_C para tentar implementar um padrão visual persistente, ou seja, duas linhas são adicionadas. Infelizmente, não consigo criar esse padrão enquanto repete meu truque de "água", ou seja, com a linha ativa azul (que está apenas alterando a cor do plano de fundo, fazendo uma linha clara e depois alterando o plano de fundo para preto). Eu montei uma imagem para mostrar como isso funciona juntos:
Observações
- O uso do backspace em uma linha ainda aciona o comportamento da linha clara e o azul desaparece
- Cada vez que a tecla Enter é pressionada, temos 2 linhas de padrão antes da nova linha ativa
- É claro que, como vemos mais abaixo, apesar das linhas extras, não estamos quebrando o padrão ao lado dos comandos, como
ls
- A aleatoriedade de / dev / urandom não parece tão aleatória quando chamada aqui em P_C. Essa imagem é composta de 2 imagens, mas é fácil entender que o padrão extra de 2 linhas é sempre o mesmo, ou seja, a aleatoriedade não é gerada a cada pressionamento de tecla Enter, mas apenas uma vez para cada uma das duas linhas - possivelmente apenas a primeira. time .bashrc é lido por
bash
. - O conteúdo da variável PS1 começa com
$(echo -en '\n') $(tput setab 4)
- bem, aquele espaço no meio, pouco antes de $ (tput ...), DEVE estar lá para que isso funcione. Caso contrário, a linha azul aparece em cima do prompt e não na frente dele, e não consigo resolver isso. E esse truque é o que dá nome a 0.2. :)
0,3 - tput cuu
&tput cud
for i in $(seq 1 $(expr $(tput lines))); do echo -en '\E[0;32m'$(tr -dc '",.o;:~' < /dev/urandom | head -c $(tput cols)); done; tput cup 1
PROMPT_COMMAND="echo -en '\033[0;32m$(tr -dc ',;o.:~' < /dev/urandom | head -c $(tput cols))\n\033[36;44m$(tr -dc '~' < /dev/urandom | head -c $(tput cols))\033[0;32m$(tr -dc ',.o+;:~' < /dev/urandom | head -c $(tput cols))'$(tput cuu 2)"
PS1="\[\033[0m\] \[\033[1;32m\][1]\[\033[7;32m\]=2=:\W)\[\033[0;32m\]=3=\[\033[1;32m\]=4=@>\[\033[0;32m\]"
O que é feito com PROMPT_COMMAND é que três linhas de padrões são impressas todas as vezes antes que o prompt seja gerado - e esses 3 conjuntos de padrões são gerados individualmente dentro das restrições explicadas em 0.2 - sem sentido para a água, pois é 1 caractere, mas ainda assim. Então subimos duas linhas (usando tput cuu 2
) e o prompt é gerado na linha do meio, de acordo com o PS1. Ainda temos nosso conjunto inicial de comandos para o padrão de tela cheia no carregamento .bashrc, que é executado apenas uma vez quando efetuamos login no terminal. Agora temos alguns preenchimentos ao redor da linha ativa, que tem seu próprio padrão azul, que sempre se repete quando há um carro de retorno. O conteúdo da variável PS1 e do P_C foi higienizado. A sintaxe das seqüências de escape e do código de cores incorporados emecho
seqüências podem ser complicadas. Erros levam a um comportamento terminal estranhoincluindo linhas que se substituem, um prompt que aparece fora da margem esquerda ou saída incomum para itens que foram processados sem intenção. Existe uma condição no que estou fazendo, em que é necessário um espaço extra dentro da variável PS1 para combater uma diferença visual entre o terminal linux e o lxterm na minha configuração (Arch Bang). Sem o espaço extra, o terminal linux imprime o primeiro caractere do prompt no final da última linha por algum motivo que não consigo entender (é claro que é algo que eu faço e não o comportamento padrão). Também não é possível descobrir como gerar algum efeito aleatório (negrito, inverso etc.) para o conjunto de caracteres entre aspas, pois foi decidido desde o início gerar seqüências mais longas para aumentar o desempenho.
Padrão inicial quando o terminal é aberto
Comportamento após a clear
e pressionando enter sucessivamente no prompt
Observações
- Deve ser redesenhado ou modificado para implementar a coloração dos padrões, além de fazê-lo em massa
- Começar a achar que ir muito além exigirá colocar tudo isso em um script ou alavancar alguma forma mais alta de abstração. Mas os recursos do terminal são bastante capacitadores para o usuário final (me lembra o "logo")!