Contexto y Pregunta
Hay muchas formas de colorear el terminal y el entorno de shell. La salida de comandos individuales, como ls
y grep
, también se puede colorear. No está directamente relacionado pero es interesante, no obstante, la noción de reproducir medios en la consola, pero esto aparentemente se basa en algunos marcos (bibliotecas) en la parte superior del sistema de ventanas. La siguiente pregunta está orientada únicamente al bash
shell y su implementación en el marco de terminal de Linux y sus bases.
Considere el siguiente montaje de "representaciones" ASCII de una escena en un juego 2D :
Estas no son escenas generadas al azar. Todos los segmentos que he seleccionado en realidad representan alguna forma de terreno de "pastizales" (árboles, arbustos y arbustos, flores, césped, etc.) de un juego que utiliza caracteres ASCII para representar tales objetos. Las últimas 4 escenas muestran mosaicos creados por el usuario que son básicamente una reasignación de caracteres ASCII con especificaciones de color (tales detalles son triviales; basta con decir que esta es la inspiración visual de lo que estoy tratando de lograr aquí en términos de imágenes y " modelo").
Las características comunes de esas escenas en el montaje compartido son:
- 5-6 caracteres ASCII diferentes como máximo (comas, comillas y algunos otros)
- 2-4 colores usados
- para los personajes
- para los fondos de caracteres en algunos casos: el último ejemplo está allí para mostrar el uso de sombras de color con poco o ningún carácter para crear un patrón, es decir, mosaico de colores
Lo que tengo en una máquina virtual en este momento es Arch Linux y, aunque la pregunta no es específica de distribución, he examinado su documentación para personalizar el /etc/bash.bashrc
archivo. Puedo ver que muchas explicaciones van a configurar la apariencia del indicador y, en general, todos los elementos de primer plano. Hay poca información sobre cualquier configuración para el fondo, excepto generalmente para un color sólido, como estos ajustes y consejos :
# 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
Todavía no entiendo conceptualmente cuáles son esos "espacios" vacíos / en blanco / de fondo que no escribí cuando uso la consola, es decir, "¿de qué están hechos?" por así decirlo. Especialmente aquellos que no están en el indicador y que envuelven los comandos que se repiten. Con respecto a lo que sucede en la línea activa, es posible demostrar que bash
actúa de manera "orientada a la línea" y que algunas operaciones desencadenan un borrado de la línea activa ( for i in $(seq 1 $(expr $(tput lines) \* $(tput cols))); do echo -n M; done; tput cup 15 1
, luego, en el indicador, escriba un carácter y retroceda - demostró un contribuyente): el alcance del cual puede variar de una CLI a otra, es decir, zsh. Además, parece que cuando agrego algo parecido \[\033[44m\]
a mi línea PS1 bash.bashrc
aparece un fondo azul después de volver a cargar bash, así que obviamente sé que hay algunosAproveche aquí la apariencia de salida en lo que respecta al fondo .
Pero también sé que bash es una pieza de software que se basa en alguna otra instalación en forma de subsistema TTY para traer cosas a la pantalla, y esto pasa desde allí al componente VT en el núcleo, supongo. pstree -Ap
en Arch muestra systemd
vinculados a login
y luego a bash
.
La distribución Arch Linux se basa en los agetty
servicios TTY. Un simple echo $TERM
arrojará el tipo de terminal en uso ("linux" aquí fuera de cualquier DE) y el infocmp[-d spec1 spec2]
comando sin parámetro muestra las capacidades del terminal activo y la información de perfil de la base de datos del 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án las cosas, se pueden aprovechar muchas capacidades del marco del terminal y son básicamente esas características las que están expuestas en el archivo de configuración bash.bashrc en la medida en que la solicitud se personaliza configurando la variable PS1. Las secuencias de control y escape se utilizan básicamente para interrumpir el flujo de caracteres que se muestran en el terminal para proporcionar funciones, incluido el movimiento del cursor y otras capacidades descritas en la base de datos de información del terminal. Muchas de esas funciones se pasan usando el conocido ESC[
(o \ 33) Introductor de secuencia de control (más secuencias aquí y aquí , y algunos ejemplos ). Además, también es posible utilizar eltput
utilidad directamente en la CLI para cambiar algunas propiedades del terminal; por ejemplo, tput setab 4
tendrá comandos bash echo sobre un fondo azul.
Si podemos strace bash
ver tanto las secuencias de escape como el comportamiento en acción:
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
Esto proporciona contexto para la pregunta ¿Se pueden reemplazar los espacios vacíos / el color de fondo en un terminal con un conjunto aleatorio (pero bonito) de caracteres ASCII? pero no da idea de cómo implementar las funciones o de lo que estoy buscando en el terminal.
Así que he creado una maqueta cruda como ejemplo de cómo sería el resultado final si esto fuera posible (no en serio :):
Básicamente, todo el "espacio vacío" en la terminal se llenará con el patrón (aquí "enlosaré" una de las imágenes desde arriba, pero me gustaría en la implementación real que cada "espacio en blanco" individual se genere al azar a partir del conjunto de 5-6 caracteres y características documentadas del montaje que se especificarían). Hay un patrón diferente para la línea de comando activa, es decir, "agua" ondulada, pero me conformaría con que la línea sea azul. Como se imaginó, los comandos "borrarían" el "agua" a medida que se escriben en la línea activa y, por supuesto, una restricción sería que el patrón de caracteres nunca sea interpretado por la CLI; de lo contrario, sería inútil.
Entonces, ¿hay alguna configuración expuesta en bash
o en el marco de la terminal propiamente dicha, o un script que permita usar un conjunto de caracteres y cierto control sobre los colores para modificar la salida de bash en la terminal para generar un patrón algo aleatorio para el fondo (que sería similar a lo que he mostrado arriba)? ¿O simplemente debería conformarme con algo como intentar proporcionar una imagen de patrón completo como fondo para el tty ?
Implementaciones
0.1 - Versión de PatternOTD (oferta única cuando inicia sesión)
La siguiente expresión que agregué a mi archivo .bashrc reúne algunas de las nociones que exploramos y constituye una prueba de concepto (muy) básica para las imágenes en el terminal estándar de Linux:
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
Observaciones
- Obviamente es solo un comando, por lo que no es persistente, es decir, se desplaza a medida que se escriben los comandos
- Optado por no cambiar aleatoriamente de forma individual la selección de caracteres, es decir,
head -c 1
con latput cols
multiplicación de las líneas, para empezar, lo que imprimir caracteres aleatorios individuales de la selección de la cita - porque es demasiado lento. No creo querandom
genere un entero largo (tput cols) pero aún así es más rápido. Seguramente todo esto es muy derrochador, pero funciona. - No he aleatorizado ningún color o efecto por personaje o de otro modo, excepto ese verde porque, como he explicado, renderizar / procesar cada carácter individualmente es demasiado lento. Re: framebuffer?
- ¡Me alegra ver que el patrón no interfiere con el uso de CLI en el sentido de que CLI no lo interpreta! (¿Por qué aunque no podía explicarlo?)
- ¡El agua se fue demasiado rápido! ;-)
0.2 - PROMPT_COMMAND hackear trabajo
El valor de la variable PROMPT_COMMAND se examina justo antes de que Bash imprima cada solicitud principal. Sé que usualmente usaría la variable para llamar a un script donde podría procesar elementos de la pantalla, etc., pero estoy tratando de hacer esto directamente en mi archivo .bashrc. Inicialmente, pensé que podría implementar una conciencia posicional, es decir, dónde está el cursor antes de la ejecución (para poder renderizar las cosas en la pantalla en cualquier lugar y tput
luego volver a la posición que estaba antes, usando algo como esto para extraer la posición:
stty -echo; echo -n $'\e[6n'; read -d R x; stty echo; echo ${x#??} //value is in x;x format so...
Diría el valor a cut -f1 -d";"
. Puedo hacer esto en la CLI, pero hacer que esto funcione dentro de la secuencia de elementos en las variables PS1 / P_C está fuera de mi alcance en este momento y es posible que cualquier comando que se ponga en PROMPT_COMMAND no se evalúe en cada retorno de carro, sino más bien solo una vez (?) a pesar de ser ejecutado cada vez (ver observaciones a continuación).
Entonces, lo mejor que puedo hacer es transferir mi secuencia inicial y agregar algunos comandos tanto a PROMPT_COMMAND como a la definición de la variable PS1 en .bashrc. Al igual que:
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
En resumen, estoy usando P_C para intentar implementar un patrón visual persistente, es decir, se agregan 2 líneas. Desafortunadamente, no puedo tener éxito en crear este patrón mientras repito mi truco de "agua", es decir, tener la línea activa azul (que solo cambia el color de fondo, hace una línea clara y luego cambia el fondo de nuevo a negro). He reunido una imagen para mostrar cómo funciona esto juntos:
Observaciones
- El uso de retroceso en una línea aún activa el comportamiento de línea clara y el azul se ha ido
- Cada vez que se presiona la tecla Intro, tenemos 2 líneas de patrón antes de la nueva línea activa
- Por supuesto, como vemos más abajo a pesar de las líneas adicionales, no estamos ajustando el patrón al costado de los comandos, como
ls
- La aleatoriedad de / dev / urandom parece no ser tan aleatoria cuando se llama aquí en P_C. Esta imagen está hecha de 2 imágenes, pero es fácil deducir que el patrón adicional de 2 líneas siempre es el mismo, es decir, la aleatoriedad no se genera con cada pulsación de tecla enter, sino solo una vez para cada una de las dos líneas, posiblemente solo la primera tiempo .bashrc es leído por
bash
. - El contenido de la variable PS1 comienza con
$(echo -en '\n') $(tput setab 4)
: bueno, ese espacio en el medio allí, justo antes de $ (tput ...), DEBE estar allí para que esto funcione. De lo contrario, la línea azul aparece en la parte superior de la solicitud y no delante de ella y no puedo resolverlo. Y este truco es lo que da nombre a 0.2. :)
0.3 - tput cuu
ytput 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\]"
Lo que se hace con PROMPT_COMMAND es que se imprimen 3 líneas de patrones cada vez antes de que se genere la solicitud, y esos 3 conjuntos de patrones se generan individualmente dentro de las restricciones explicadas en 0.2, lo que no tiene sentido para el agua ya que es 1 char pero aún así. Luego subimos dos líneas (usando tput cuu 2
) y la solicitud se genera en la línea media de acuerdo con PS1. Todavía tenemos nuestro conjunto inicial de comandos para el patrón de pantalla completa en la carga .bashrc, que se ejecuta solo una vez cuando iniciamos sesión en el terminal. Ahora tenemos algo de relleno alrededor de la línea activa que tiene su propio patrón azul que siempre se repite cuando hay un carro de retorno. El contenido de la variable PS1 y el P_C se ha desinfectado. La sintaxis de las secuencias de escape y la codificación de colores incrustadas enecho
Las secuencias pueden ser complicadas. Los errores conducen a un comportamiento terminal extrañoincluidas líneas que se sobrescriben entre sí, un mensaje que aparece lejos del margen izquierdo o una salida inusual a cosas que se han procesado involuntariamente. Existe una condición con lo que estoy haciendo, donde se requiere un espacio adicional dentro de la variable PS1 para contrarrestar una diferencia visual entre el terminal de Linux y lxterm con mi configuración (Arch Bang). Sin el espacio extra, el terminal de Linux imprime el primer carácter de la solicitud al final de la última línea por alguna razón que no puedo entender (por supuesto, es algo que hago y no el comportamiento predeterminado). Además, no puedo entender cómo generar algún efecto aleatorio (negrita, inverso, etc.) al conjunto de caracteres entre comillas, ya que se decidió desde el principio generar cadenas más largas para aumentar el rendimiento.
Patrón inicial cuando se abre el terminal
Comportamiento después de a clear
y presionar enter sucesivamente en el indicador
Observaciones
- Debe ser rediseñado o modificado para implementar la coloración de los patrones más allá de hacerlo en masa
- Comenzar a sentir que ir mucho más allá requerirá poner todo eso en un guión o aprovechar alguna forma superior de abstracción. ¡Pero las capacidades del terminal son bastante habilitantes para el usuario final (me recuerda a "logo")!