Contesto e domanda
Esistono molti modi per colorare l' ambiente del terminale e della shell. L'output di singoli comandi, come ls
e grep
, può anche essere colorato. Non direttamente correlato, ma interessante è comunque l'idea di riprodurre file multimediali sulla console, ma ciò sembra basarsi su alcuni framework (librerie) in cima al sistema a finestre. La seguente domanda è orientata esclusivamente alla bash
shell e alla sua implementazione nel framework dei terminali Linux e alle sue basi.
Si prega di considerare il seguente montaggio di "rendering" ASCII di una scena in un gioco 2D :
Queste non sono scene generate casualmente. I segmenti che ho selezionato rappresentano in realtà una forma di terreno "prateria" (alberi, cespugli e arbusti, fiori, erba ecc.) Da un gioco che utilizza caratteri ASCII per rappresentare tali oggetti. Le ultime 4 scene mostrano i set di tessere creati dall'utente che sono sostanzialmente una rimappatura di caratteri ASCII con specifiche di colore (tali dettagli sono banali - basti dire che questa è l'ispirazione visiva per ciò che sto cercando di realizzare qui in termini di grafica e " modello").
Le caratteristiche comuni di quelle scene nella condivisione del montaggio sono:
- 5-6 caratteri ASCII diversi al massimo (virgole, virgolette e alcuni altri)
- 2-4 colori usati
- per i personaggi
- per gli sfondi dei personaggi in alcuni casi - l'ultimo esempio è lì per mostrare l'uso di sfumature di colore con caratteri piccoli o nulli per creare un motivo, ad esempio un mosaico di colori
Quello che ho in una VM al momento è Arch Linux e sebbene la domanda non sia specifica per la distribuzione, ho cercato nella loro documentazione per personalizzare il /etc/bash.bashrc
file. Vedo che molte spiegazioni vanno nella configurazione dell'aspetto del prompt e in generale di tutti gli elementi in primo piano. Ci sono poche informazioni su qualsiasi configurazione per lo sfondo, ad eccezione di solito per un colore solido, come queste impostazioni e suggerimenti :
# 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
Ancora non capisco concettualmente quali sono quegli "spazi" vuoti / vuoti / di sfondo che non ho digitato quando uso la console, cioè "di cosa sono fatti?" per così dire. Soprattutto quelli che non sono al prompt e che avvolgono i comandi che fanno eco. Rispetto a ciò che accade sulla linea attiva, è possibile dimostrare che bash
agisce in modo "orientato alla linea" e che alcune operazioni attivano una cancellazione della linea attiva ( for i in $(seq 1 $(expr $(tput lines) \* $(tput cols))); do echo -n M; done; tput cup 15 1
, quindi al prompt digitare un carattere e backspace - dimostrato un collaboratore) - la cui estensione può variare da una CLI a un'altra, ovvero zsh. Inoltre, sembra che quando aggiungo qualcosa di simile \[\033[44m\]
alla mia linea PS1 bash.bashrc
ottengo uno sfondo blu dopo aver ricaricato bash - quindi ovviamente so che ci sono alcunisfrutta qui l'aspetto dell'output per quanto riguarda lo sfondo .
Ma so anche che bash è un software che si basa su qualche altra struttura sotto forma del sottosistema TTY per portare le cose sullo schermo - e questo scende da lì al componente VT nel kernel presumo. pstree -Ap
su Arch mostra systemd
collegati ae login
quindi a bash
.
La distribuzione Arch Linux fa affidamento sui agetty
servizi TTY. Un semplice echo $TERM
produrrà il tipo di terminale in uso ("linux" qui al di fuori di qualsiasi DE) e il infocmp[-d spec1 spec2]
comando senza parametro mostra le capacità del terminale attivo e le informazioni del profilo dal database del terminale 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,
Allo stato attuale, molte funzionalità possono essere sfruttate dal framework del terminale ed è sostanzialmente quelle caratteristiche che sono esposte nel file di configurazione bash.bashrc nella misura in cui il prompt viene personalizzato impostando la variabile PS1. Le sequenze di controllo e di escape vengono utilizzate per interrompere sostanzialmente il flusso di visualizzazione dei caratteri nel terminale al fine di fornire funzioni, incluso lo spostamento del cursore e altre funzionalità descritte nel database delle informazioni del terminale. Molte di queste funzioni vengono passate usando il noto ESC[
(o \ 33) Control Sequence Introducer (più sequenze qui e qui , e alcuni esempi ). Inoltre, è anche possibile utilizzare iltput
utilità direttamente sulla CLI per modificare alcune proprietà del terminale; per esempio tput setab 4
avrà i comandi echo bash su uno sfondo blu.
Se riusciamo a strace bash
vedere sia le sequenze di escape che il comportamento in azione:
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
Questo fornisce un contesto per la domanda Gli spazi vuoti / il colore di sfondo in un terminale possono essere sostituiti con un set casuale (ma carino) di caratteri ASCII? ma non ho idea di come implementare le funzionalità o di ciò che sto cercando nel terminale.
Quindi ho creato un modello grezzo come esempio di come potrebbe essere il risultato finale se ciò fosse possibile (no sul serio :):
Fondamentalmente tutto lo "spazio vuoto" nel terminale verrebbe riempito con il modello (qui "affianco" un'immagine dall'alto ma vorrei che l'implementazione effettiva per ogni singolo "spazio" fosse generata casualmente dall'insieme di 5-6 caratteri e caratteristiche documentati dal montaggio che sarebbe specificato). Esiste un modello diverso per la riga di comando attiva, ovvero "acqua" ondulata, ma mi accontenterei che la linea fosse blu. Come è stato immaginato, i comandi "cancellano" l '"acqua" quando vengono digitati sulla linea attiva e, naturalmente, un vincolo sarebbe che il modello di caratteri non viene mai interpretato dalla CLI, altrimenti lo renderebbe inutile.
Quindi c'è qualche configurazione esposta nel bash
o nel framework del terminale vero o proprio o uno script che consentirebbe di usare un set di caratteri e un certo controllo sui colori per modificare l'output di bash nel terminale in modo da generare un pattern in qualche modo casuale per lo sfondo (che sarebbe simile a quello che ho mostrato sopra)? O dovrei semplicemente accontentarmi di qualcosa come provare a fornire un'immagine di modello completo come sfondo per il tty ?
implementazioni
0.1 - Versione PatternOTD (un colpo solo quando accedi)
La seguente espressione che ho aggiunto al mio file .bashrc mette insieme alcune delle nozioni che abbiamo esplorato e costituisce una (molto) prova di concetto di base per gli oggetti visivi nel terminale Linux standard:
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
osservazioni
- È ovviamente solo un comando quindi non persistente, cioè scorre via man mano che i comandi vengono digitati
- Ha scelto di non randomizzare individualmente la selezione di caratteri, ad esempio
head -c 1
con latput cols
moltiplicazione delle righe, per iniziare a stampare singoli caratteri casuali dalla selezione citata, perché è troppo lento. Non credo cherandom
generi un intero lungo (tput cols) ma è comunque più veloce. Sicuramente è tutto molto dispendioso ma funziona. - Non ho randomizzato alcun colore o effetto per personaggio o altrimenti tranne quel verde perché, come ho spiegato, il rendering / elaborazione di ogni carattere singolarmente è troppo lento. Ri: framebuffer?
- Sono felice di vedere che il modello non interferisce con l'utilizzo della CLI, nel senso che non viene interpretato dalla CLI! (perché anche se non riuscivo a spiegare)
- L'acqua è andata troppo veloce! ;-)
0.2 - PROMPT_COMMAND processo di hacking
Il valore della variabile PROMPT_COMMAND viene esaminato appena prima che Bash stampi ogni prompt principale. So che di solito useresti la variabile per chiamare uno script in cui potresti elaborare elementi dal display ecc. Ma sto piuttosto cercando di farlo direttamente nel mio file .bashrc. Inizialmente pensavo di poter implementare un po 'di consapevolezza della posizione, cioè dove si trova il cursore prima dell'esecuzione (quindi potrei andare a rendere le cose sullo schermo ovunque con tput
poi tornare alla posizione che ero prima, usando qualcosa del genere per estrarre la posizione:
stty -echo; echo -n $'\e[6n'; read -d R x; stty echo; echo ${x#??} //value is in x;x format so...
Vorrei convogliare il valore a cut -f1 -d";"
. Posso farlo sulla CLI ma fare questo lavoro all'interno della sequenza di elementi nelle variabili PS1 / P_C al momento è fuori dalla mia portata ed è possibile che qualunque comando venga inserito in PROMPT_COMMAND non possa essere valutato ad ogni ritorno a capo ma piuttosto solo una volta (?) nonostante sia stato eseguito ogni volta (vedere le osservazioni seguenti).
Quindi il meglio che potrei fare è riportare la mia sequenza iniziale e aggiungere alcuni comandi sia a PROMPT_COMMAND sia alla definizione della variabile PS1 in .bashrc. Così:
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
In sintesi, sto usando P_C per provare a implementare un modello visivo persistente, cioè 2 linee vengono aggiunte. Sfortunatamente non riesco a creare entrambi questi motivi mentre ripeto il mio trucco "acqua", ovvero avere la linea attiva blu (che sta semplicemente cambiando il colore di sfondo, facendo una linea chiara, quindi riportando lo sfondo in nero). Ho messo insieme un'immagine per mostrare come funziona insieme:
osservazioni
- L'uso del backspace su una linea attiva ancora il comportamento della linea chiara e il blu scompare
- Ogni volta che si preme il tasto Invio, abbiamo 2 linee di motivo prima della nuova linea attiva
- Naturalmente, come vediamo più in basso, nonostante le linee extra non stiamo avvolgendo lo schema sul lato dei comandi come
ls
- La casualità di / dev / urandom non sembra così casuale quando viene chiamata qui in P_C. Questa immagine è composta da 2 immagini, ma è facile capire che il modello extra di 2 linee è sempre lo stesso, cioè la casualità non viene generata con ogni pressione del tasto invio ma solo una volta per ciascuna delle due linee - probabilmente solo la prima time .bashrc viene letto da
bash
. - Il contenuto della variabile PS1 inizia con
$(echo -en '\n') $(tput setab 4)
- bene quello spazio nel mezzo lì, poco prima di $ (tput ...), DEVE essere lì perché questo funzioni. Altrimenti la linea blu appare sopra il prompt e non davanti e non posso risolverlo. E questo hack è ciò che dà il 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\]"
Quello che viene fatto con PROMPT_COMMAND è che 3 linee di motivi vengono stampate ogni volta prima che venga generato il prompt - e quei 3 gruppi di motivi sono generati individualmente entro i vincoli spiegati in 0.2 - insignificanti per l'acqua in quanto è 1 carattere ma ancora. Quindi saliamo due righe (usando tput cuu 2
) e il prompt viene generato sulla riga centrale secondo PS1. Abbiamo ancora il nostro set iniziale di comandi per il modello a schermo intero sul caricamento .bashrc che viene eseguito solo una volta quando eseguiamo l'accesso al terminale. Ora abbiamo delle imbottiture attorno alla linea attiva che ha il suo modello blu che si ripete sempre quando c'è un carrello di ritorno. I contenuti della variabile PS1 e del P_C sono stati disinfettati. La sintassi delle sequenze di escape e della codifica a colori incorporata all'interno di un lungoecho
le sequenze possono essere complicate. Gli errori portano a strani comportamenti terminalicomprese le linee che si sovrascrivono a vicenda, un prompt che appare lontano dal margine sinistro o output insolito verso elementi che sono stati elaborati involontariamente. Esiste una condizione con ciò che sto facendo, in cui è richiesto uno spazio aggiuntivo all'interno della variabile PS1 per contrastare una differenza visiva tra il terminale Linux e lxterm con la mia configurazione (Arch Bang). Senza lo spazio extra, il terminale Linux stampa il primo carattere del prompt alla fine dell'ultima riga per qualche motivo che non riesco a capire (ovviamente è qualcosa che faccio e non il comportamento predefinito). Inoltre, non riesco a capire come generare un effetto casuale (grassetto, inverso, ecc.) All'insieme di caratteri tra virgolette, poiché è stato deciso in anticipo di generare stringhe più lunghe per aumentare le prestazioni.
Schema iniziale all'apertura del terminale
Comportamento dopo a clear
e premendo invio successivo al prompt
osservazioni
- Dovrebbe essere riprogettato o modificato per implementare la colorazione dei motivi oltre a farlo in blocco
- Iniziare a pensare che andare molto oltre richiederà di inserire tutto ciò in una sceneggiatura o di sfruttare una forma più alta di astrazione. Ma le funzionalità del terminale sono abbastanza abilitanti per l'utente finale (mi ricorda il "logo")!