Kontekst i pytanie
Istnieje wiele sposobów pokolorowania środowiska terminala i powłoki. Dane wyjściowe poszczególnych poleceń, takich jak ls
i grep
, można również pokolorować. Nie jest bezpośrednio powiązane, ale interesujące jest pojęcie odtwarzania multimediów na konsoli, ale wydaje się, że opiera się ono na niektórych ramach (bibliotekach) na systemie okienkowym. Poniższe pytanie dotyczy wyłącznie bash
powłoki i jej implementacji w frameworku terminali Linux i jego podstawach.
Proszę rozważyć następujący montaż „renderingów” ASCII sceny w grze 2D :
To nie są losowo generowane sceny. Wszystkie wybrane przeze mnie segmenty przedstawiają jakąś formę „trawiastego” terenu (drzewa, krzewy i krzewy, kwiaty, trawa itp.) Z gry, w której do reprezentowania takich obiektów używane są postacie ASCII. Ostatnie 4 sceny przedstawiają zestawy klocków wykonane przez użytkownika, które są w zasadzie remapiem znaków ASCII ze specyfikacjami kolorów (takie szczegóły są banalne - wystarczy powiedzieć, że jest to wizualna inspiracja do tego, co próbuję osiągnąć tutaj pod względem wizualnym i „ wzór").
Wspólne cechy tych scen w udziale montażowym to:
- Maksymalnie 5-6 różnych znaków ASCII (przecinki, znaki cudzysłowu i kilka innych)
- Zastosowano 2-4 kolory
- dla postaci
- dla tła postaci w niektórych przypadkach - ostatnim przykładem jest pokazanie użycia odcieni kolorów z niewielką liczbą znaków lub bez znaku w celu utworzenia wzoru, tj. kolorowej mozaiki
To, co mam w tej chwili na maszynie wirtualnej, to Arch Linux i chociaż pytanie nie jest specyficzne dla dystrybucji, zajrzałem do ich dokumentacji w celu dostosowania /etc/bash.bashrc
pliku. Widzę, że wiele wyjaśnień dotyczy konfiguracji wyglądu monitu i ogólnie wszystkich elementów pierwszego planu. Istnieje niewiele informacji na temat dowolnej konfiguracji tła, z wyjątkiem zwykle jednolitego koloru, takich jak te ustawienia i wskazówki :
# 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
Nadal nie rozumiem koncepcyjnie tych „pustych / pustych / tła” „spacji”, których nie wpisałem podczas korzystania z konsoli, tj. „Z czego są zrobione?” że tak powiem. Zwłaszcza te, które nie są wyświetlane w wierszu poleceń i które zawierają polecenia, które są powtarzane. W odniesieniu do tego, co dzieje się na linii aktywnej, można wykazać, że bash
działa ona w sposób „zorientowany na linię” i że niektóre operacje wyzwalają czyszczenie linii aktywnej ( for i in $(seq 1 $(expr $(tput lines) \* $(tput cols))); do echo -n M; done; tput cup 15 1
, a następnie po znaku zachęty wpisz znak i cofnij ją - pokazano współpracownik) - którego zakres może się różnić w zależności od CLI, np. zsh. Co więcej, wydaje się, że gdy dodam coś \[\033[44m\]
do mojej linii PS1, bash.bashrc
po przeładowaniu dostaję niebieskie tło - więc oczywiście wiem, że jest trochęwykorzystać tutaj wygląd wyjściowy, o ile dotyczy to tła .
Ale wiem też, że bash to oprogramowanie polegające na jakimś innym narzędziu w postaci podsystemu TTY do przenoszenia rzeczy na ekran - i od tego momentu przechodzi do komponentu VT w jądrze, które zakładam. pstree -Ap
na Arch pokazuje, systemd
powiązane z, login
a następnie z bash
.
Arch Linux dystrybucja opiera się agetty
na usługi TTY. Prosty echo $TERM
da typ używanego terminala („linux” tutaj poza dowolnym DE), a infocmp[-d spec1 spec2]
polecenie bez parametru pokazuje aktywne możliwości terminala i informacje o profilu z bazy terminali 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,
Na obecnym etapie, wiele możliwości może być wykorzystanych z frameworku terminali i są to w zasadzie te funkcje, które są ujawnione w pliku konfiguracyjnym bash.bashrc, o ile monit jest dostosowywany poprzez ustawienie zmiennej PS1. Sekwencje kontrolne i sekwencje specjalne służą do przerwania przepływu wyświetlania znaków w terminalu w celu dostarczenia funkcji, w tym przesunięcia kursora i innych możliwości opisanych w bazie danych informacji o terminalu. Wiele z tych funkcji jest przekazywanych przy użyciu dobrze znanego ESC[
(lub \ 33) Kontrolera sekwencji wprowadzającej (więcej sekwencji tutaj i tutaj oraz kilka przykładów ). Ponadto można również korzystać ztput
narzędzie bezpośrednio w interfejsie CLI do zmiany niektórych właściwości terminala; na przykład tput setab 4
będą miały polecenia echa bash na niebieskim tle.
Jeśli strace bash
widzimy zarówno sekwencje specjalne, jak i zachowanie w akcji:
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
To stanowi kontekst dla pytania. Czy puste miejsca / kolor tła w terminalu można zastąpić losowym (ale ładnym) zestawem znaków ASCII? ale nie ma pojęcia, jak zaimplementować funkcje ani czego szukam w terminalu.
Więc stworzyłem prymitywną makietę jako przykład tego, jak mógłby wyglądać efekt końcowy, gdyby to było możliwe (nie poważnie :):
Zasadniczo cała „pusta przestrzeń” w terminalu byłaby wypełniona wzorem (tutaj „kafelkuję” jeden z obrazków z góry, ale chciałbym, aby w rzeczywistej implementacji dla każdego „pustego” miejsca generować losowo z zestawu 5-6 znaków i cech udokumentowanych z montażu, które zostaną określone). Aktywny wiersz poleceń ma inny wzór, tj. Falistą „wodę”, ale zadowoliłbym się, że linia jest niebieska. Jak to można sobie wyobrazić, polecenia „wymażą” „wodę”, gdy zostaną wpisane w aktywnym wierszu, i oczywiście istnieje ograniczenie, że wzór znaków nigdy nie zostanie zinterpretowany przez CLI, w przeciwnym razie uczyni go bezużytecznym.
Czy istnieje jakakolwiek konfiguracja ujawniona w bash
lub we właściwej strukturze terminala, lub skrypt, który pozwoliłby użyć zestawu znaków i pewnej kontroli kolorów, aby zmodyfikować wyjście bash w terminalu, aby wygenerować nieco losowy wzór tła (co byłoby podobne do tego, co pokazałem powyżej)? Czy powinienem po prostu zadowolić się próbą dostarczenia pełnego obrazu wzoru jako tła dla tty ?
Realizacje
0.1 - Wersja PatternOTD (jedna transakcja po zalogowaniu)
Następujące wyrażenie, które dodałem do mojego pliku .bashrc, łączy niektóre z pojęć, które badaliśmy i stanowi (bardzo) podstawowy dowód koncepcji wizualnej w standardowym terminalu 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
Spostrzeżenia
- To oczywiście tylko polecenie, więc nietrwałe, tzn. Przewija się w miarę wpisywania poleceń
- Zdecydowano się nie losować pojedynczo losowego wyboru znaków, tj
head -c 1
.tput cols
Przez pomnożenie wierszy na początku, co spowoduje wydrukowanie pojedynczych losowych znaków z cytowanego zaznaczenia - ponieważ jest zbyt wolny. Nie sądzę, żerandom
generuje długą liczbę całkowitą (tput cols), ale nadal jest szybsza. Z pewnością jest to bardzo marnotrawstwo, ale działa. - Nie losowałem żadnego koloru ani efektu na znak, ani w żaden inny sposób poza tym zielonym, ponieważ, jak wyjaśniłem, renderowanie / przetwarzanie każdego znaku osobno jest zbyt wolne. Odp: bufor ramki?
- Cieszę się, że wzorzec nie koliduje z korzystaniem z CLI w tym sensie, że nie jest interpretowany przez CLI! (dlaczego nie mogłem tego wyjaśnić)
- Woda za szybko wypłynęła! ;-)
0.2 - PROPOZYCJA HAKOWANIA PROMPT_COMMAND
Wartość zmiennej PROMPT_COMMAND jest sprawdzana tuż przed wydrukowaniem przez Bash każdego głównego monitu. Wiem, że zwykle używasz zmiennej do wywołania skryptu, w którym możesz przetwarzać elementy z wyświetlacza itp., Ale raczej próbuję to zrobić bezpośrednio w moim pliku .bashrc. Początkowo myślałem, że mogę wdrożyć trochę świadomości pozycyjnej, tj. Gdzie jest kursor przed wykonaniem (więc mogłem renderować rzeczy na ekranie w dowolnym miejscu, a tput
następnie powrócić do poprzedniej pozycji, używając czegoś takiego do wyodrębnienia pozycji:
stty -echo; echo -n $'\e[6n'; read -d R x; stty echo; echo ${x#??} //value is in x;x format so...
Zmieniłbym wartość do cut -f1 -d";"
. Mogę to zrobić w interfejsie CLI, ale wykonanie tej pracy w sekwencji elementów w zmiennych PS1 / P_C jest obecnie poza moim zasięgiem i możliwe jest, że jakiekolwiek polecenie wprowadzone w PROMPT_COMMAND może nie być oceniane przy każdym powrocie karetki, ale raczej tylko raz (?) pomimo wykonania za każdym razem (patrz uwagi poniżej).
Więc najlepsze, co mogłem zrobić, to przenieść moją początkową sekwencję i dodać kilka poleceń zarówno do PROMPT_COMMAND, jak i definicji zmiennej PS1 w .bashrc. Tak jak:
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
Podsumowując, używam P_C do próby zaimplementowania trwałego wzorca wizualnego, tzn. Dodania 2 linii. Niestety nie udało mi się stworzyć obu tych wzorów, powtarzając moją sztuczkę „wodną”, tj. Mając niebieską linię aktywną (która po prostu zmienia kolor tła, robi wyraźną linię, a następnie zmienia tło z powrotem na czarny). Przygotowałem obraz, aby pokazać, jak to gra razem:
Spostrzeżenia
- Użycie backspace na linii nadal wyzwala zachowanie czystej linii i niebieski zniknął
- Za każdym naciśnięciem klawisza Enter mamy 2 linie wzoru przed nową linią aktywną
- Oczywiście, jak widzimy dalej, pomimo dodatkowych linii, nie zawijamy wzoru z boku poleceń takich jak
ls
- Losowość / dev / urandom nie wydaje się tak losowa, gdy zostanie wywołana tutaj w P_C. Ten obraz składa się z 2 obrazów, ale łatwo jest zauważyć, że wzór 2 dodatkowych linii jest zawsze taki sam, tj. Losowość nie jest generowana przy każdym naciśnięciu klawisza Enter, ale tylko jeden raz dla każdej z dwóch linii - być może tylko pierwsza czas odczytu .bashrc
bash
. - Zawartość zmiennej PS1 zaczyna się od
$(echo -en '\n') $(tput setab 4)
- cóż, ta przestrzeń pośrodku, tuż przed $ (tput ...), MUSI tam być, żeby to zadziałało. W przeciwnym razie niebieska linia pojawi się na górze monitu, a nie przed nim, i nie mogę tego rozwiązać. A ten hack nadaje nazwę 0,2. :)
0,3 - tput cuu
itput 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\]"
PROMPT_COMMAND polega na tym, że 3 wiersze wzorów są drukowane za każdym razem przed wygenerowaniem pytania - i te 3 zestawy wzorów są generowane indywidualnie w ramach ograniczeń wyjaśnionych w 0.2 - bez znaczenia dla wody, ponieważ ma 1 znak, ale nadal. Następnie przechodzimy w górę o dwie linie (za pomocą tput cuu 2
) i monit jest generowany w środkowej linii zgodnie z PS1. Wciąż mamy nasz początkowy zestaw poleceń dla pełnego ekranu wzorca przy ładowaniu .bashrc, który jest wykonywany tylko raz, gdy logujemy się do terminala. Teraz mamy trochę wypełnienia wokół aktywnej linii, która ma swój własny niebieski wzór, który zawsze się powtarza, gdy jest karetka powrotna. Zawartość zmiennej PS1 i P_C zostały zdezynfekowane. Składnia sekwencji ucieczki i kodowania kolorów jest osadzona w długimecho
sekwencje mogą być trudne. Błędy prowadzą do dziwnego zachowania terminalaw tym wiersze, które się nadpisują, monit, który pojawia się z dala od lewego marginesu lub nietypowe wyjście do rzeczy przetworzonych przypadkowo. Z tym, co robię, istnieje warunek, w którym wymagana jest dodatkowa przestrzeń wewnątrz zmiennej PS1, aby zneutralizować wizualną różnicę między terminalem linux a lxterm przy mojej konfiguracji (Arch Bang). Bez dodatkowej spacji terminal linux wypisuje pierwszy znak zachęty na końcu ostatniego wiersza z jakiegoś powodu, którego nie mogę zrozumieć (oczywiście jest to coś, co robię, a nie zachowanie domyślne). Nie mogę również dowiedzieć się, jak wygenerować jakiś losowy efekt (pogrubienie, odwrotność itp.) Dla zestawu znaków w cudzysłowie, ponieważ wcześniej podjęto decyzję o generowaniu dłuższych ciągów w celu zwiększenia wydajności.
Początkowy wzór po otwarciu terminala
Zachowanie po a clear
i naciśnięciu klawisza Enter kolejno po znaku zachęty
Spostrzeżenia
- Powinny zostać przeprojektowane lub zmodyfikowane w celu wdrożenia kolorowania wzorów poza robieniem tego luzem
- Zrozumienie, że pójście o wiele dalej będzie wymagało albo umieszczenia tego wszystkiego w skrypcie, albo wykorzystania wyższej formy abstrakcji. Ale możliwości terminalu są całkiem dostępne dla użytkownika końcowego (przypomina mi „logo”)!