linux有多少种终端,linux终端指令大全
终端输出
使用termios结构,我们可以控制键盘输入,但如果能控制屏幕上显示的输出在同一级别可能会更好。在本章的开始,我们使用printf将字符输出到屏幕上,但是没有办法将输出定位到屏幕上的特定位置。
终端类型
许多Unix系统使用终端,尽管在今天的许多情况下,终端实际上可能是运行终端程序的PC。历史上,不同的制造商提供了大量的硬件终端。尽管它们都使用转义序列(以转义字符开始的字符串)来提供对光标和属性的控制,如粗体和闪烁,但它们并没有以标准的方式提供这些功能。一些老终端也有不同的滚动功能,发送退格时滚动条可能会消失。
终端的多样性对于想要编写控制屏幕和运行在多种终端类型上的软件的程序员来说是一个很大的问题。例如,ANSI标准使用转义序列[A]将光标上移一行,而ADM-3a终端使用单独的控制字符Ctrl K。
编写处理连接到Unix系统的不同类型终端的程序是一项极其困难的任务。也许程序应该为每种终端类型提供不同的源代码。
在这样一个名为terminfo的包中提供解决方案并不奇怪。该计划不会迎合各种终端类型。相反,程序将查找终端类型的数据库以获得正确的信息。在大多数现代Unix系统中,包括Linux,这些都被集成到一个叫做curses的软件包中,这是我们将在下一章学习的内容。
在Linux上,我们可以使用名为ncurses的curses实现,并包含ncurses.h文件来提供terminfo函数的原型。Terminfo函数本身是在它们自己的头文件term.h中声明的,或者至少以前是这样。在新版Linux系统上,terminfo和ncurses之间有一个模糊的界限,很多需要terminfo函数的程序也必须包含ncurses头文件。为了避免将来的混乱,现代Linux发行版还提供了一个curses头文件和库,它与Unix系统更加兼容。在这些系统上,我们建议使用curses.h和-lcurses。
确定我们的终端类型。
Linux环境包含一个变量TERM,它被设置为我们正在使用的终端的类型。通常在系统登录时由系统自动设置。系统管理员可以为直接连接到终端的每个用户设置默认的终端类型。这些用户可能是想要提供终端类型的远程或网络用户。TERM的值可以通过telnet协商,并通过rlogin传递。
用户可以查询shell来确定他正在使用的终端的类型。
回声$TERM
终端仿真器
$
在这个例子中,shell由一个名为xterm的程序运行,该程序是X Window系统的终端模拟器,或者是提供类似功能的程序,如KDE的Konsole或Gnome的Gnome-Terminal。
Terminfo软件包包含了函数转义序列的数据库和大量的终端,并为程序员提供了统一的接口。这个程序可以在数据库扩展时利用未来终端的优势,而不是每个程序都必须支持不同的终端。
terminfo的功能由属性描述。这些属性存储在编译后的terminfo文件集合中,通常可以在/usr/lib/terminfo或/usr/share/terminfo中找到。对于每个终端(也有一些打印机可以在terminfo中指定),都有一个文件来定义其功能以及如何访问这些功能。为了避免创建非常大的目录,实际文件存储在子目录中,子目录的名称只是简单终端类型的第一个字符。因此,VT100的定义可以在中找到.terminfo/v/vt100
注意,我们将定义许多许多终端,但是幸运的是,大多数Unix和Linux系统已经预定义了大多数终端。如果我们需要添加新的终端,我们可以在terminfo手册页中找到完整的功能列表。一个好的起点是定位那些与我们的新终端相似的终端,并将新终端定义为现有终端的变体。
使用terminfo函数
现在我们知道了如何定义终端函数,我们需要知道如何访问它们。当我们使用terminfo时,首先要做的是通过调用setupterm来设置终端类型。这将初始化当前终端类型的终端结构。然后我们可以访问和使用终端功能。setupterm函数的原型如下:
#包含术语. h
int setupterm(char *term,int fd,int * errret);
setupterm库函数将当前终端类型设置为参数term指定的终端类型。如果term是空指针,那么将使用TERM环境变量。用于写入终端的打开文件描述符必须由参数fd传递。函数的执行结果存储在errret指向的整数变量中(如果不为空)。写入的值可以是:
-1:没有terminfo数据库。
terminfo数据库中没有匹配的实体。
1.成功
如果成功,setupterm函数将返回常量OK,如果失败,将返回ERR。如果errret设置为空指针,则当函数失败时,将输出一条诊断消息,程序将退出,如下例所示:
#包含stdio.h
#包含术语. h
#包含ncurses.h
int main()
{
setupterm("未列出",fileno(stdout),(int *)0);
printf("完成。/n ");
退出(0);
}
在我们的系统上运行的程序的输出可能不像这里显示的那样,但它的意义是足够明显的。这里没有显示Done,因为setupterm函数执行失败,导致程序退出。
$ cc-o bad term bad $ term . c-I/usr/include/ncurses-ln curses
巴德$ term
未列出:未知的终端类型。
$
注意上面例子中的编译命令:在这个Linux系统上,ncurses头文件位于/usr/include/ncurses目录中,所以我们必须使用-I选项来指示编译器查看这里。一些Linux系统可能会使ncurses库可以从标准位置访问。在这些系统上,我们只需要包含curses.h头文件并为库指定-lcurses选项。
对于我们的菜单选择功能,我们希望能够清除屏幕,在屏幕上移动光标,并在屏幕上的任何地方书写。一旦我们调用了setupterm函数,我们就可以使用不同的函数来访问terminfo函数。功能类型如下:
#包含术语. h
int tiget flag(char * cap name);
int tiget num(char * cap name);
char * tigetstr(char * cap name);
函数tigetflag、tigetnum和tigetstr分别返回布尔值、数值和字符串terminfo函数。如果失败,tigetflag将返回-1,tigetnum将返回-2,tigetstr将返回(char *)-1。
让我们使用程序sizeterm.c程序来获取cols和lines函数以确定终端大小:
#包含stdio.h
#包含术语. h
#包含ncurses.h
int main()
{
int nrows,ncolumns
setupterm(NULL,fileno(stdout),(int *)0);
nrows=tiget num(" lines ");
ncolumns=tiget num(" cols ");
printf("此终端有%d列和%d行/n ",ncolumns,n rows);
退出(0);
}
回声$TERM
vt100
尺寸$ term
该终端有80列和24行
$
如果我们在工作站的一个窗口中运行这个程序,我们将得到一个反映当前窗口大小的答案:
回声$TERM
终端仿真器
尺寸$ term
该终端有88列和40行
$
如果我们用tigetstr来获取xterm终端类型的光标移动函数(cup),就会得到一个参数化的答案:/E[% P1 % d;%p2%dH .
这个函数需要两个参数:光标要移动到的行和列。这两个坐标是从屏幕左上角的零点开始测量的。
我们可以使用tparm函数将函数中的参数替换为实际值。最多可以替换九个参数,并且将返回一个可用的转义序列:
#包含术语. h
char *tparm(char *cap,long p1,long p2,长p9);
一旦我们使用tparm来组织终端转义序列,我们就必须将它发送到终端。为了正确处理,我们不应该使用printf向终端发送字符串。相反,我们应该使用特殊的函数,这些函数为终端完成一个操作的正确处理提供必要的延迟。这些功能是:
#包含术语. h
int putp(char * const str);
int tputs(char *const str,int affcnt,int(* put func)(int));
如果成功,Putp返回OK,如果失败,则返回ERR。putp函数将终端控制字符串作为参数,并将其发送到标准输出。
因此,要移动到屏幕的第5行第30列,我们可以使用下面的代码块:
char *游标;
char * esc _ sequence
cursor=tigetstr(" cup ");
esc_sequence=tparm(cursor,5,30);
putp(ESC _ sequence);
Tputs函数是为那些不能通过stdout访问终端的情况提供的,它允许我们指定用于输出字符的函数。他将返回用户指定的函数putfunc的结果。affcnt参数用于指示受更改影响的行数,通常设置为1。用于输出字符串的函数必须与putchar函数具有相同的参数和返回结果。实际上,putp(string)相当于调用tputs(string,1,putchar)。我们将在下面的例子中看到如何使用tputs函数和用户指定的输出函数。
注意,一些老的Linux发行版将tputs函数的最后一个参数定义为int (*putfunc)(char),这将迫使我们修改下一个实验中定义的char_to_terminal函数。
请注意,如果我们查看tparm和terminal函数的信息手册页,我们可能会遇到一个tgoto函数。他提供了一个更简单的移动光标的方案,但是我们不使用这个函数的原因是X/Open规范在1997版本中没有包含它。所以我们建议不要在新程序中使用这些功能。
现在,我们准备将屏幕处理添加到菜单选择功能中。另一件事是简单地使用clear来清除屏幕。有些终端不支持清除功能,会让光标停留在屏幕左上角。在这种情况下,我们可以将光标放在左上角,并使用“删除直到显示结束”命令。
结合所有这些信息,我们可以编写示例菜单程序的最终版本screen-menu.c,我们将在屏幕上“绘制”选项供用户选择。
测试-完成终端控制
我们可以重写menu4.c的getchoice函数,为我们提供完整的终端控制。在这个列表中,省略了主函数,因为它没有改变。
#包含stdio.h
#包括unistd.h
#包含termios.h
#包含术语. h
#包含诅咒. h
静态文件* output _ stream=(FILE *)0;
char *menu[]={
" a -添加新记录"、
"删除记录",
“q戒”,
空,
};
int getchoice(char *greet,char *choices[],FILE *in,FILE * out);
int char _ to _ terminal(int char _ to _ write);
int main()
{
.
}
int getchoice(char *greet,char *choices[],FILE *in,FILE *out)
{
int choosed=0;
int选择;
int screenrow,screencol=10
char * *选项;
char *cursor,*清除;
output _ stream=out
setupterm(NULL,fileno(out),(int *)0);
cursor=tigetstr(" cup ");
clear=tigetstr(" clear ");
screenrow=4;
tputs(clear,1,(int *)char _ to _ terminal);
tputs(tparm(cursor,screenrow,screencol),1,char _ to _ terminal);
fprintf(out," Choice: %s,greet);
screenrow=2;
选项=选择;
while(*选项){
tputs(tparm(cursor,screenrow,screencol),1,char _ to _ terminal);
fprintf(out,“%s”,* option);
screenrow
选项;
}
fprintf(out,"/n ");
做{
fflush(出);
selected=fgetc(in);
选项=选择;
while(*选项){
if(selected==*option[0]) {
choosed=1;
打破;
}
选项;
}
如果(!已选择){
tputs(tparm(cursor,screenrow,screencol),1,char _ to _ terminal);
fprintf(out,“选择不正确,重新选择/n”);
}
} while(!被选中);
tputs(clear,1,char _ to _ terminal);
返回所选内容;
}
int char _ to _ terminal(int char _ to _ write)
{
if(output _ stream)putc(char _ to _ write,output _ stream);
返回0;
}
操作原理
重写后的getchoice函数实现了与上一个示例相同的菜单,但是输出函数被修改为使用terminfo函数。如果我们希望在屏幕被清除之前的一段时间内看到您已经选择的:信息,我们可以通过使用以下选择向主函数添加一个睡眠调用:
做{
choice=getchoice("请选择一个动作",菜单,输入,输出);
printf("/n您选择了:%c/n ",choice);
睡眠(1);
} while(选择!= q );
这个程序中的最后一个函数,char_to_terminal,包含了我们在第3章中提到的putc函数调用。
在本章的最后,我们将看一个如何检测击键的例子。