概述
终端
对终端进行读写
标准模式与非标准模式
规范模式 或 标准模式:
按下回车键才会把键入的数据传递给程序。
非标准模式:
应用程序对用户输入字符的处理拥有更大的控制权。
规范的英文:canonical
处理重定向输出
#include <unistd.h>
int isatty(int fd);
将文件描述符传递给isatty,它就可以判断该描述符是否连接到一个终端。如果是则返回1,不是则返回0。
与终端进行对话
Linux和UNIX提供特殊设备 /dev/tty,这个设备始终是指向当前终端或当前的登录会话。可以用一般文件的操作方式来对/dev/tty进行读写。
终端驱动程序和通用终端接口
可以通过一组函数调用( 通用终端接口,GTI )来 控制 终端,这组函数调用与用于读写数据的函数是分离的,这就使得读写数据的接口非常简洁。
能够控制的主要功能:
行编辑:是否允许用退格键进行编辑。
缓存:是立即读取字符,还是等待一段可配置的延迟之后再读取它们。
回显:允许控制字符的回显,例如读取密码时。
回车/换行(CR/LF):定义如何在输入/输出时映射回车/换行符,比如打印n字符时应该如何处理。
线速:这一功能少用于PC控制台,但对调制解调器或通过串行线连接的终端就很重要。
termios结构
termios是在POSIX定义的标准接口。通过设置termios类型的数据结构中的值和使用一小组函数调用,就可以对终端接口进行控制。termios数据结构和相关函数调用都定义在头文件 termios.h 中。
调用termios.h中的函数时,需要与一个正确的函数库链接,可能是标准的C函数库,也可能是curses函数库。连接curses函数库时,编译命令加上 -lcurses,有些是加 -lncurses(n表示new)。
可以被调整来影响终端的值按照不同的模式被分成如下几组:
输入模式、输出模式、控制模式、本地模式、特殊控制字符
#include <termios.h>
struct termios {
tcflag_t c_iflag; //输入模式
tcflag_t c_oflag; //输出模式
tcflag_t c_cflag; //控制模式
tcflag_t c_lfalg; //本地模式
cc_t c_cc[NCCS]; //特殊控制字符
};
/*
获取与一个终端(fd文件描述符指向的文件)对应的termios结构(存入到termios_p中)。
*/
#include <termios.h>
int tcgetattr(int fd, struct termios *termios_p);
#include <termios.h>
int tcsetattr(int fd, int actions, const struct termios *termios_p);
参数 actions 取值 | 说明 |
---|---|
TCSANOW | 立刻对值进行修改 |
TCSADRAIN | 等当前的输出完成后再对值进行修改 |
TCSAFLUSH | 等当前的输出完成后再对值进行修改,但丢弃还未从read调用返回的当前可用的任何输入 |
程序结束时应恢复终端状态,这是码农的职责。
输入模式
控制输入数据在被传递给程序之前的处理方式。
参数 c_iflag 取值 | 说明 |
---|---|
BRKINT | 当在输入行中检测到一个终止状态(连接丢失)时,产生一个中断 |
IGNBRK | 忽略输入行中的终止状态 |
ICRNL | 将接收到的回车符转换为新行符 |
IGNCR | 忽略接收到的回车符 |
INLCR | 将接收到的新行符转换为回车符 |
IGNPAR | 忽略奇偶校验错误的字符 |
INPCK | 对接收到的字符执行奇偶校验 |
PARMRK | 对奇偶校验错误做出标记 |
ISTRIP | 将所有接收到的字符裁减为7比特 |
IXOFF | 对输入启用软件流控 |
IXON | 对输出启用软件流控 |
输出模式
控制输出字符的处理方式,即由程序发送出去的字符在传递到串行口或屏幕之前是如何处理的。
参数 c_oflag 取值 | 说明 |
---|---|
OPOST | 打开输出处理功能 |
ONLCR | 将输出中的换行符转换为回车/换行符。 |
OCRNL | 将输出中的回车符转换为新行符。 |
ONOCR | 在第0列不输出回车符 |
ONLRET | 不输出回车符 |
OFILL | 发送填充字符以提供延时 |
OFDEL | 用DEL而不是NULL字符作为填充字符。 |
NLDLY | 新行符延时选择 |
CRDLY | 回车符延时选择 |
TABDLY | 制表符延时选择 |
BSDLY | 退格符延时选择 |
VTDLY | 垂直制表符延时选择 |
FFDLY | 换页符延时选择 |
控制模式
控制终端的硬件特性。
参数 c_cflag 取值 | 说明 |
---|---|
CLOCAL | 忽略所有调制解调器的状态行 |
CREAD | 启用字符接收器 |
CS5 | 发送或接收字符时使用5比特 |
CS6 | 发送或接收字符时使用6比特 |
CS7 | 发送或接收字符时使用7比特 |
CS8 | 发送或接收字符时使用8比特 |
CSTOPB | 第个字符使用两个停止位而不是一个 |
HUPCL | 关闭时挂断调制解调器 |
PARENB | 启用奇偶校验的生成和检测功能 |
PARODD | 启用奇校验而不是偶校验 |
本地模式
控制终端的各种特性。
参数 c_lflag 取值 | 说明 |
---|---|
ECHO | 启用输入字符的本地回显功能 |
ECHOE | 接收到ERASE时执行退格、空格、退格的动作组合 |
ECHOK | 接收到KILL字符时执行行删除操作 |
ECHONL | 回显新行符 |
ICANON | 启用标准输入处理 |
IEXTEN | 启用基于特定实现的函数 |
ISIG | 启用信号 |
NOFLSH | 禁止清空队列 |
TOSTOP | 在试图进行写操作之前给后台进程发送一个信号 |
特殊控制字符
对字符组合(如ctrl+c)采取一些特殊的处理方式。
标准模式
可使用下标 | 说明 |
---|---|
VEOF | EOF字符 |
VEOL | EOL字符 |
VERASE | ERASE字符 |
VINTR | INTR字符 |
VKILL | KILL字符 |
VQUIT | QUIT字符 |
VSUSP | SUSP字符 |
VSTART | START字符 |
VSTOP | STOP字符 |
非标准模式
可使用下标 | 说明 |
---|---|
VINTR | INTR字符 |
VMIN | MIN值 |
VQUIT | QUIT字符 |
VSUSP | SUSP字符 |
VTIME | TIME值 |
VSTART | START字符 |
VSTOP | STOP字符 |
字符 | 说明 |
---|---|
INTR | 该字符使终端驱动程序向与终端相连的进程发送SIGINT信号。 |
QUIT | 该字符使终端驱动程序向与终端相连的进程发送SIGQUIT信号。 |
ERASE | 该字符使终端驱动程序删除输入行中的最后一个字符。 |
KILL | 该字符使终端驱动程序删除整个输入行 |
EOF | 该字符使终端驱动程序将输入行中的全部字符传递给正在读取输入的应用程序。如果输入行为空,read调用将返回0,就好像在文件结尾调用read一样 |
EOL | 该字符的作用类似行结束符,效果和常用的新行符相同 |
SUSP | 该字符使终端驱动程序向与终端相连的进程发送SIGSUSP信号。如果你的UNIX系统支持作业控制功能,当前应用程序将被挂起 |
STOP | 该字符的作用是“截流”,即阻止向终端的进一步输出。它用于支持XON/XOFF流控,通常被设置为ASCII的XOFF字符,即组合键ctrl+s |
START | 该字符重新启动被STOP字符暂停的输出,它通常被设置为ASCII的XON字符 |
TIME和MIN值:
只用于非标准模式。
等待TIME个十分之一秒或接收到MIN个字符。如果两个都为0,read调用总是立刻返回,如果有一个以上不为0,只看不为0的条件。
通过shell访问终端模式:
$ stty -a
如果不小心把终端设置为非标准状态,可以用以下几种方法:
(1)使用如下命令。
$stty sane
(2)用命令 stty -g 将当前的stty设置保存到某种可以重新读取的形式中。
$ stty -g > save_stty
$ stty $(cat save_stty)
如果回车键和新行符的映射关系丢失了,可以用 ctrl+j(对应新行符)。
在命令提示符下设置终端模式:
例如:
$ stty -icannon min 1 time 0
$ stty -echo
终端速度
#include <termios.h>
speed_t cfgetispeed(const struct termios *);
speed_t cfgetospeed(const struct termios *);
int cfsetispeed(struct termios *, speed_t speed);
int cfsetospeed(struct termios *, speed_t speed);
termios结构提供的最后一个功能是控制终端速度,但termios结构中 并没有与终端速度对应的成员 ,它是通过函数调用来进行设置的。
参数 speed 取值 | 说明 |
---|---|
B0 | 挂起终端 |
B1200 | 1200波特 |
B2400 | 2400波特 |
… | … |
其他函数
#include <termios.h>
//让调用程序一直等待,直到所有排除的输出都已发送完毕
int tcdraint(int fd);
//暂停或重新开始输出
int tcflow(int fd, int flowtype);
//清空输入、输出或者两者都清空
int tcflush(int fd, int in_out_selector);
直接对文件描述符进行操作,不需要读写termios结构。
终端的输出
终端类型
不同的制造厂商生产了大量的各种类型的硬件终端。虽然它们几乎都用 escape转义序列 来控制光标的位置和终端的其他属性——比如黑体和闪烁等,但在具体实现手段上并没有统一的标准。
$ echo $TERM
查看自己正在使用的终端是何种类型。
terminfo软件包包含了一个由大量不同类型终端的功能标志和escape转义序列等信息构成的数据库,并且为使用它们提供了一个统一的编程接口。一个使用这个软件包的程序能够随着数据库的扩展来适应未来的终端类型,对不同类型终端的支持不再需要由应用程序自身来提供。
terminfo的功能标志由属性描述,它们被保存在一组编译好的terminfo文件中,这些文件通常可以在 /usr/lib/terminfo 或 lusr/share/terminfo 目录中找到。
如图,为linux终端对应的terminfo文件。
通过 infocmp 程序输出已编译terminfo数据项的可读版本。
每个terminfo定义由3种数据项组成。每个数据项被称为 capname,它们分别用于定义终端的一种功能标志。
布尔功能标志 指出终端是否支持某个特定的功能。
数值功能标志 定义长度。
字符串功能标志 用于访问终端功能的输出字符串和当用户按下特定按键时终端接收到的输入字符串。
其中%i表示增加参数值,E表示发送Escape字符,%pn为将第n个参数入栈。
使用terminfo功能标志
#include <term.h>
int setupterm(char *term, int fd, int *errret);
返回值:
-1:数据库不存在。
0:数据库中没有匹配的数据项。
1:成功。
将当前终端类型设置为参数term指向的值,如果term是空指针,就使用环境变量TERM的值。参数fd为一个打开的文件描述符,它用于向终端写数据。如果参数errret不是一个空指针,则函数的返回值保存在该参数指向的整型变量中。
#include <term.h>
int tigetflag(char *capname); //失败时返回-1
int tigetnum(char *capname); //失败时返回-2
char *tigetstr(char *capname); //失败时返回(char *)-1
#include <term.h>
char *tparm(char *cap, long p1, long p2, ..., long p9);
替换功能标志中的参数,最多九个,并返回一个可用的escape转义序列。
#include <term.h>
int putp(char *const str);
int tputs(char *const str, int affcnt, int (*putfunc)(int));
光标移动到第5行第30列,可以使用如下代码:
char *cursor;
char *esc_sequence;
cursor = tigetstr("cup");
esc_sequence = tparm(cursor, 5, 30);
putp(esc_sequence);
tputs函数是为不能通过标准输出stdout访问终端的情况准备的,它可以指定一个用于输出字符的函数。返回值为putfunc的返回结果。参数affcnt的作用是表明受这一变化影响的行数,一般被设置为1。putp(string)等同于tputs(string,1,putchar)。
最后
以上就是踏实冬日为你收集整理的Linux笔记五(终端)终端的全部内容,希望文章能够帮你解决Linux笔记五(终端)终端所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复