请教关于终端的几个问题

sh/bash/dash/ksh/zsh等Shell脚本
回复
头像
jiandan23
帖子: 86
注册时间: 2010-12-17 22:31
系统: Mint 19.2

请教关于终端的几个问题

#1

帖子 jiandan23 » 2023-09-19 16:30

各位好,最近在看《UNIX环境高级编程》关于终端的两章时,遇到一点问题,希望懂的人帮忙看下!

关于终端的回显,按照书里的意思,当回显开启后,用户输入的内容会自动回显到终端上面,且这个功能是由终端自己实现的,和bash无关。我的问题如下:
  • 在bash命令提示符后面输入命令,每敲入一个字符,终端上便会输出一个字符。这个机制是通过“终端回显”实现的吗?
  • 如果是,为什么将bash的stderr重定向到/dev/null之后(bash下执行“exec 2>/dev/null”),输入命令不再有回显了?
关于TERM变量:ssh登录某台linux主机,$TERM的值是xterm,这个xterm和/usr/bin/xterm是啥关系?

谢谢!!
头像
astolia
论坛版主
帖子: 6452
注册时间: 2008-09-18 13:11

Re: 请教关于终端的几个问题

#2

帖子 astolia » 2023-09-20 16:01

jiandan23 写了: 2023-09-19 16:30 且这个功能是由终端自己实现的,和bash无关
这个说法不太准确。回显与否可以看作是终端的一个选项。bash默认是通过readline库来读取用户的输入,在readline库内部会去查询这个选项,如果没有禁止回显,则会将用户的输入再输出到指定的输出流中,就实现了回显这一功能。这个过程是发生在bash进程内的,说和bash无关也不合适
jiandan23 写了: 2023-09-19 16:30 如果是,为什么将bash的stderr重定向到/dev/null之后(bash下执行“exec 2>/dev/null”),输入命令不再有回显了?
因为bash在初始化readline库时,将readline的输出流设置成了stderr(见bash源码 https://git.savannah.gnu.org/cgit/bash. ... h-5.2#n459 ),所以所有由readline输出的内容,包括回显文字以及提示符,都被重定向到了/dev/null

以上都是基于bash用readline库这一前提。如果在编译bash时禁用了readline库,那么即使你执行了exec 2>/dev/null,回显也不受影响
jiandan23 写了: 2023-09-19 16:30 关于TERM变量:ssh登录某台linux主机,$TERM的值是xterm,这个xterm和/usr/bin/xterm是啥关系?
TERM环境变量用来说明当前终端拥有的各项能力。设置成xterm,表示用terminfo数据库中xterm项的配置,对应的配置文件是/usr/share/terminfo/x/xterm。这个配置文件来自ncurses库,仅仅是表述了某一版xterm终端模拟器具有的能力,并不依赖xterm
头像
jiandan23
帖子: 86
注册时间: 2010-12-17 22:31
系统: Mint 19.2

Re: 请教关于终端的几个问题

#3

帖子 jiandan23 » 2023-09-22 16:34

astolia 写了: 2023-09-20 16:01
jiandan23 写了: 2023-09-19 16:30 且这个功能是由终端自己实现的,和bash无关
这个说法不太准确。回显与否可以看作是终端的一个选项。bash默认是通过readline库来读取用户的输入,在readline库内部会去查询这个选项,如果没有禁止回显,则会将用户的输入再输出到指定的输出流中,就实现了回显这一功能。这个过程是发生在bash进程内的,说和bash无关也不合适
jiandan23 写了: 2023-09-19 16:30 如果是,为什么将bash的stderr重定向到/dev/null之后(bash下执行“exec 2>/dev/null”),输入命令不再有回显了?
因为bash在初始化readline库时,将readline的输出流设置成了stderr(见bash源码 https://git.savannah.gnu.org/cgit/bash. ... h-5.2#n459 ),所以所有由readline输出的内容,包括回显文字以及提示符,都被重定向到了/dev/null

以上都是基于bash用readline库这一前提。如果在编译bash时禁用了readline库,那么即使你执行了exec 2>/dev/null,回显也不受影响
多谢解答!
我用strace跟踪了下,确实在命令提示符后面的回显,是由bash进程写到终端的。
同时在bash源码中也找到了“rl_outstream = stderr;”,所以重定向stderr到/dev/null,会导致输入命令回显不可见,这个可以理解。

但我进一步测试,发现了以下问题:(为了描述方便,我把上面这种回显暂且称之为“readline回显”)
在执行“exec 2>/dev/null”之后(此时敲入命令已经不再有回显),然后运行sleep 10m,在sleep阻塞时,再敲入字符,又有回显了,如下:

代码: 全选

[root@host ~]# exec 2>/dev/null
#敲入命令“sleep 10m”,无回显
#在sleep运行时,敲入"hello",有回显
hello   
这种回显是由终端的"line discipline"带来的吗?
前面提到的"readline回显"是不是会覆盖这种回显?不然bash命令提示符后面输入的命令,就要被回显两边了。

谢谢!
头像
astolia
论坛版主
帖子: 6452
注册时间: 2008-09-18 13:11

Re: 请教关于终端的几个问题

#4

帖子 astolia » 2023-09-25 11:35

jiandan23 写了: 2023-09-22 16:34 前面提到的"readline回显"是不是会覆盖这种回显?不然bash命令提示符后面输入的命令,就要被回显两边了。
这是由readline库主动控制的。

在readline库的实现中 https://git.savannah.gnu.org/cgit/bash. ... h-5.2#n379
在每一次读取时,是先执行rl_prep_term_function,再去执行readline_internal读取输入,最后执行rl_deprep_term_function。

当读取对象是终端时,rl_prep_term_function里会设置禁止回显 https://git.savannah.gnu.org/cgit/bash. ... h-5.2#n254 , rl_deprep_term_function里会恢复原来的设置。

实际上是这么一个循环过程:设置禁止回显 -> 读取输入 -> 如果原先有回显设置则输出字符 -> 恢复设置 -> 执行命令
所以你执行某个命令比如sleep,在命令执行过程中就仍然是处于有回显的状态,只要命令本身没有再次去动回显设置,此时输入的字符都会被回显。
头像
jiandan23
帖子: 86
注册时间: 2010-12-17 22:31
系统: Mint 19.2

Re: 请教关于终端的几个问题

#5

帖子 jiandan23 » 2023-09-27 14:37

明白了,多谢!
回复