上下文和问题
有许多方法可以使终端和外壳环境着色。单个命令(例如ls
和)的输出grep
也可以被着色。在控制台上播放媒体的概念虽然没有直接关系,但很有趣,但这似乎依赖于窗口系统顶部的某些框架(库)。以下问题仅针对bash
shell及其在Linux终端框架中的实现及其基础。
请考虑以下2D 游戏中场景的ASCII“渲染”蒙太奇:
这些不是随机生成的场景。我选择的所有段实际上都描绘了使用ASCII字符表示此类对象的游戏中某种形式的“草地”地形(树木,灌木丛,灌木,花卉,草等)。最后4个场景展示了用户制作的图块,这些图块基本上是具有颜色规格的ASCII字符的重新映射(这样的细节很简单-可以说这是我在视觉和[...图案”)。
蒙太奇共享中这些场景的共同特征是:
- 最多5-6个不同的ASCII字符(逗号,引号和其他一些字符)
- 使用2-4种颜色
- 对于字符
- 在某些情况下用于字符背景-最后一个示例在那里显示了使用具有很少或没有字符的颜色阴影来创建图案的方法,即颜色马赛克
目前,我在VM中拥有的是Arch Linux,尽管问题不是特定于发行版的,但我已经研究了他们的文档以自定义/etc/bash.bashrc
文件。我可以看到,对于配置提示的外观以及通常所有的前台元素都有很多解释。除了通常的纯色之外,关于背景的任何配置的信息都很少,例如这些设置和提示:
# 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
我仍然没有从概念上掌握使用控制台时没有输入的空白/空白/背景“空格”,即“它们是由什么组成的?” 可以这么说。尤其是那些不在提示符下且环绕回显命令的命令。关于活动行上发生的事情,有可能演示bash
以“面向行”的方式执行操作,并且某些操作触发清除活动行(for i in $(seq 1 $(expr $(tput lines) \* $(tput cols))); do echo -n M; done; tput cup 15 1
,然后在提示符下键入char并退格-演示了一个贡献者)-其范围可能从一个CLI到另一个(即zsh)有所不同。此外,似乎当我在重新加载bash之后\[\033[44m\]
在PS1行中添加类似内容时,bash.bashrc
背景变为蓝色-很明显,我知道有一些就背景而言,此处利用输出外观。
但是我也知道bash是一种软件,它依赖于TTY子系统形式的某些其他工具来将内容显示到屏幕上-并且从那里一直延伸到我假设的内核中的VT组件。pstree -Ap
在Arch上显示systemd
链接到login
,然后再链接到bash
。
在Arch Linux的发行依靠agetty
的TTY服务。一个简单的命令echo $TERM
将产生正在使用的终端类型(这里是任何DE之外的“ linux”)infocmp[-d spec1 spec2]
,不带参数的命令将显示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,
就目前而言,可以从终端框架中利用许多功能,并且只要设置PS1变量自定义提示,就基本上是bash.bashrc配置文件中公开的那些功能。控制和转义序列用于基本中断终端中字符显示的流程,以便提供功能,包括移动光标和终端信息数据库中描述的其他功能。这些功能中的许多功能都是使用众所周知的ESC[
(或\ 33)控制序列介绍器传递的(此处和此处的更多序列,以及一些示例)。此外,也可以使用tput
直接在CLI上使用实用程序来更改某些终端属性;例如tput setab 4
将在蓝色背景上显示bash echo命令。
如果我们strace bash
可以看到转义序列和实际行为:
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
这为问题提供了上下文。可以将终端中的空白/背景色替换为一组随机(但很漂亮)的ASCII字符吗?但是不知道如何实现功能或我在终端中寻找的东西。
因此,我创建了一个粗略的模型作为示例,说明如果可能的话,最终结果将是什么样(不严重:):
基本上,终端中的所有“空白空间”都将填充有模式(此处我从上面“平铺”了一张图像,但我希望在实际实现中从该组图像中随机生成每个“空白”)从蒙太奇记录的5-6个字符和特征(将被指定)。活动命令行有一种不同的模式,即波浪形的“水”,但我认为该行是蓝色的。就像想象中的那样,命令在活动行中键入时将“擦除”“水”,并且当然会受到约束,即CLI永远不会解释字符的模式,否则将使其无效。
bash
在终端框架中或终端框架中是否存在适当的公开配置,或者允许使用一组字符和对颜色的一些控制的脚本,以修改终端中bash的输出,从而为背景生成某种随机的图案? (这与我上面显示的内容类似)?还是我应该简单地解决一些问题,例如尝试提供完整的图案图像作为tty的背景?
实作
0.1-PatternOTD版本(登录时一次性付款)
我添加到.bashrc文件中的以下表达式汇总了我们探讨的一些概念,并构成了标准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
观察结果
- 显然,这只是一个命令,因此不是持久的,即当键入命令时它会滚动消失
- 选择了不单独随机选择的字符,即
head -c 1
与tput cols
该行乘以开始,这将引自选择打印单个随机字符-因为它的速度太慢。我不认为会random
生成一个(tput cols)长整数,但是仍然更快。当然,这都是非常浪费的,但是可以。 - 除了绿色以外,没有为每个字符或其他颜色随机分配任何颜色或效果,因为正如我所解释的,分别渲染/处理每个字符太慢。回复:帧缓冲?
- 我很高兴看到该模式在不被CLI解释的意义上不会干扰CLI的使用!(为什么我无法解释)
- 水太快了!;-)
0.2-PROMPT_COMMAND骇客作业
在Bash打印每个主提示之前,将检查变量PROMPT_COMMAND的值。我知道通常您会使用该变量来调用脚本,在其中可以处理显示等中的元素。但是,我宁愿尝试直接在.bashrc文件中执行此操作。最初我以为我可以实现一些位置感知,即执行之前光标在哪里(因此我可以在屏幕上的任何位置渲染事物,tput
然后返回到之前的位置,使用类似的方法来提取位置:
stty -echo; echo -n $'\e[6n'; read -d R x; stty echo; echo ${x#??} //value is in x;x format so...
我会将值传送到cut -f1 -d";"
。我可以在CLI上执行此操作,但此刻无法在PS1 / P_C变量中的元素序列内进行此操作,并且可能不会在每次回车时都评估放在PROMPT_COMMAND中的任何命令,而是尽管每次都执行一次,但只能执行一次(?)(请参阅以下观察结果)。
因此,我能做的最好是保留我的初始序列,并向PROMPT_COMMAND和.bashrc中PS1变量的定义添加一些命令。像这样:
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
总之,我正在使用P_C尝试实现持久的视觉模式,即添加了2行。不幸的是,在重复我的“水”技巧时(例如,使活动线变为蓝色(这只是改变背景颜色,做一条清晰的线,然后将背景变回黑色)),我无法成功创建这两种图案。我整理了一张图片,展示了它们如何协同工作:
观察结果
- 在行上使用退格键仍会触发清除行行为,并且蓝色消失了
- 每次按下Enter键,我们在新的活动行之前都会有2行图案
- 当然,尽管有多余的行,但正如我们进一步看到的那样,我们并未将模式包装在命令的侧面,例如
ls
- 在P_C中调用/ dev / urandom时,其随机性似乎不太随机。该图像由2张图像组成,但是很容易看出,额外的2行图案始终是相同的,即,并不是每次输入Enter键都会产生随机性,而是两行中的每行仅产生一次-可能只有第一行时间.bashrc由读取
bash
。 - PS1变量的内容以
$(echo -en '\n') $(tput setab 4)
-中间的空格开始,即$(tput ...)之前,它必须在此处才能起作用。否则,蓝线会出现在提示的顶部而不是提示的前面,我无法解决。而这种hack的名字就是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\]"
使用PROMPT_COMMAND所做的是,在生成提示之前,每次都会打印3行图案-并且在0.2中说明的约束内分别生成了这3组图案-对于水来说是毫无意义的,因为它是1个字符,但仍然是水。然后,我们走两行(使用tput cuu 2
),并根据PS1在中间行生成提示。对于.bashrc负载,我们仍然具有用于全屏模式的初始命令集,该命令仅在登录到终端时才执行一次。现在我们在活动线周围有一些填充,填充有其自己的蓝色图案,在有回车时总是会重复。PS1变量和P_C的内容已清除。转义序列的语法和嵌入在长字符串中的颜色编码echo
序列可能很棘手。错误导致奇怪的终端行为包括彼此覆盖的行,从左侧距出现的提示或不正常的输出到已经无意处理的内容的提示。我正在做的事情存在一个条件,在PS1变量内需要一个额外的空间,以抵消我的设置(Arch Bang)下Linux终端和lxterm之间的视觉差异。没有多余的空间,由于某些我无法弄清楚的原因,Linux终端会在最后一行的末尾打印提示的第一个字符(当然,这是我要做的,而不是默认的行为)。也无法弄清楚如何对引号中的字符集生成某种随机效果(粗体,逆等),因为早期就决定生成更长的字符串以提高性能。
终端打开时的初始模式
a之后的行为clear
并按提示依次按Enter
观察结果
- 应该重新设计或修改以实现对图案进行着色,而不是大量进行着色
- 开始觉得要走得更远,需要将所有内容放到脚本中或利用某种更高形式的抽象。但是终端功能确实为最终用户启用(使我想起了“徽标”)!