linux终端命令大全,linux有多少种终端
驱动程序与通用终端接口。
有时程序需要更好地控制终端,而不是使用简单的文件操作。Linux提供了一个接口集,允许我们控制终端驱动程序,这样我们就可以更好的控制终端的输入输出过程。
概述
如下图所示,我们可以通过一组独立于读写操作的函数调用来控制终端。这样使得数据界面更加清晰,同时也能更好的控制终端的行为。这并不是说终端I/O接口清晰,而是可以处理各种硬件。
在Linux术语中,控制接口设置了一个“行规则”,这使得程序在指定终端驱动程序的行为时更加灵活。
我们可以控制的主要功能包括:
行编辑:确定是否允许编辑使用退格键。
Buffer:决定是立即读取字符还是延迟读取。
Echo:允许我们控制echo,例如当我们读取密码时。
CR/LF:决定输入和输出之间的映射,也就是当我们输入a/n时会发生什么。
线路速度:很少在PC控制台上使用,这些速度对于串行线路上的调制解调器和终端非常重要。
硬件模型
在详细了解通用终端接口之前,了解它所驱动的硬件模型是非常重要的。
下图显示了一台Unix机器通过串行端口连接到一个调制解调器,但通过电话线和另一个调制解调器连接到远端。事实上,这是一些小型网络提供商采用的配置类型。这是相对较远的客户机/服务器模型,当程序在主机上运行而用户在终端上工作时使用。
如果我们在运行Linux的PC上工作,这似乎是一个过于复杂的模型。然而,如果两个人都有调制解调器,如果我们愿意,我们可以使用一个终端模拟程序,如minicom,在对方的机器上运行登录会话,就像使用一对调制解调器和一条电话线一样。
使用这种硬件模型的优点是大多数真实世界的情况将形成这种最复杂情况的子集。支持他们比失去这个功能容易。
Termios结构
Termios是POSIX规定的标准接口,类似于System V接口的termio。终端接口通过在termios类型的结构中设置值和使用一组函数调用来控制。所有这些都在头文件termios.h中定义
注意:使用termios.h中定义的函数的程序需要与适当的函数库链接。这通常是curses库,所以在编译本章时,我们需要在编译器命令行的末尾添加-lcurses。在一些旧的Linux系统上,curses库是由所谓的新curses或ncurses提供的。在这些情况下,库名和link参数分别变成-lncurses。
可操作以影响终端的值可分为几种模式:
输入(输入)
输出(输出)
控制(控制)
本地(本地)
特殊控制字符(特殊控制字符)
最小termios结构通常声明如下(X/Open规范允许添加一些其他域):
#包含termios.h
结构术语{
tcflag _ t c _ iflag
tcflag _ t c _ oflag
tcflag _ t c _ cflag
tcflag _ t c _ lflag
NCCS;
};
成员的名称对应于上面列表中的五个参数。
我们可以通过调用tcgetattr函数为终端初始化termios结构,其函数原型如下:
#包含termios.h
int tcgetattr(int fd,struct term IOs * term IOs _ p);
此函数调用将终端接口变量的当前值写入Termios _ p指向的结构中。如果这些值被修改,我们可以使用tcsetattr函数重新配置终端接口:
#包含termios.h
int tcsetattr(int fd,int actions,const struct term IOs * term IOs _ p);
tcsetattr函数中的actions字段控制如何应用这些修改。三个可能的值是:
TCSANOW:立即改变
TCSADRAIN:当前输出完成时更改。
TCSAFLUSH:当前输出在完成时被更改,但是当前可用的输入和read调用中未返回的输入被忽略。
注意:在程序启动前保存终端设置是非常重要的。通常,当程序完成时,程序负责初始保存和恢复设置。
让我们详细看看这些模式和相关的函数调用。有些细节模式比较特殊,很少用到,所以这里只讨论主要特性。如果我们想了解更多,我们可以查看我们当地的手册页或者POSIX或X/Open规范的副本。
关于最重要的模式,我们首先需要知道的是本地模式。正式和非正式模式是我们第一个程序中第二个问题的解决方案。我们可以指示我们的程序等待一行输入,或者在输入后立即将其声明为输入。
输入模式
输入模式控制输入(串行端口或键盘上的终端驱动程序接收的字符)在传递给程序之前的处理方式。我们通过在termios结构的c_iflag成员中设置相应的标签来设置它。所有这些标签都被定义为宏,并可以与位或。这适用于所有终端模式。
可用于c_iflag的宏有:
BRKINT:当在一行中检测到中断条件时,产生一个中断。
Ignk:忽略一行中的中断条件
INCRNL:将接收到的回车转换成换行符。
IGNCR:忽略收到的交通事故
INLCR:将收到的新行转换成回车。
IGNPAR:忽略有奇偶错误的字符。
INPCK:对接收到的字符进行奇偶校验。
PARMRK:标记奇偶校验错误
ISTRIP:删除所有输入字符。
IXOFF:允许对输入进行软件流控制
IXON:允许输出上的软件流控制
如果没有设置BRKINT和IGNBRK,一行中的中断条件将被读取为空(Ox00)字符。
我们不需要经常更换输入方式,因为默认值通常是最合适的,这里就不做更深入的讨论了。
输出方式
这些模式控制如何处理输出字符;也就是说,程序发送的字符在传输到串口或屏幕之前是如何处理的。正如我们所料,许多输出模式都有相应的输入模式。同时还有一些其他的标志,主要集中在允许需要时间处理字符的慢速终端。几乎所有这些模式都可以通过使用终端函数的terminfo数据得到很好的处理,我们后面会用到。
我们通过设置termios结构的c_flag成员标志来控制输出模式。我们可以在c_oflag中使用的标记有:
o:输出处理
ONLCR:将输出的新行转换成回车/换行对。
OCRNL:将输出的回车转换成新的一行
ONOCR:不输出第0列的回车。
ONLRET:新行也需要回车。
OFILL:发送填充字符以提供延迟。
OFDEL:使用DEL作为填充字符,而不是NULL。
NLDLY:新线路延迟选择
CRDLY:输入延迟选择
Tab dly: tab延迟选择
BSDLY:退格延迟选择
VTDLY:垂直制表符延迟选择
FFDLY:换页延迟选择
如果没有设置OPOST,所有其他标签都将被忽略。
输出模式不常用,这里不做进一步讨论。
控制模式
这些模式控制终端的硬件特性。我们可以通过设置termios结构中c_cflag成员的值来指定控制模式。其可用值为:
时钟:忽略调制解调器状态线
CREAD:允许字符接收
CS5:在发送或接收的字符中使用5位。
CS6:在发送或接收的字符中使用6位。
CS7:在发送或接收的字符中使用7位。
CS8:在发送或接收的字符中使用8位。
CSTOPB:每个字符使用两个结束位,而不是一个。
HUPCL:关闭调制解调器时将其挂起。
PARENB:允许奇偶校验生成和检测
PARODD:使用中间检查代替奇数检查。
如果设置了HUPCL,当终端驱动程序检测到指向终端的最后一个文件描述符已经关闭时,它会将调制解调器控制线设置为挂起。
控制模式主要在串行线连接到调制解调器时使用,尽管它们也可用于与终端交互。通常情况下,使用termios的控制模式来改变我们终端的配置要比改变默认的线路行为简单得多。
本地方式
这些模式控制终端的各种特性。我们可以通过设置termios结构中c_lflag成员的值来指定本地模式,其可用的宏如下:
ECHO:允许输入字符的本地回显。
ECHOE:接收EPASE时执行退格、空格、退格组合。
ECHOK:清除杀死角色的线
ECHONL:回显新行字符
ICANON:允许常规输入处理
IEXTEN:允许实现特定的功能。
ISIG:许可信号
禁止队列刷新
To:在尝试写入时发送后台处理信号。
两个最重要的标记是echo和ICANON,ECHO允许我们抑制输入字符的回声,ICANON在处理接收字符的两种不同模式下切换终端。如果ICANON标志被置位,这一行处理正常模式;如果不是,这条线处理非正式模式。
特殊控制字符
还有其他的字符集,比如Ctrl-C,当用户输入的时候会以一种特殊的方式运行。termios结构的c_cc数组成员包含映射到每个支持函数的字符。每个字符的位置(数组中的索引)由一个宏定义,但是对它们必须控制的字符没有限制。
根据终端是否设置为正常模式(例如,在termios的c_lfalg成员中设置ICANON标志),c_cc数组可以以两种不同的方式使用。
这里,我们应该注意两种不同的数组索引值模式的使用方式之间有一些重叠。正因为如此,我们永远不应该混淆这两种模式的价值观。
对于正常模式,数组索引为:
eof字符
VEOL:结束字符
VERASE:擦除字符
INTR的角色
v杀:杀死角色
退出字符
VSUSP:SUSP字符
VSTART:开始字符
VSTOP:停止字符
对于不规则模式,数组索引为:
INTR的角色
VMIN:最小值
退出字符
VSUSP:SUSP字符
VTIME:时间值
VSTART:开始字符
VSTOP:停止字符
性格;角色;字母
因为特殊字符和不规则字符的MIN和TIME值对于高级输入字符的处理如此重要,所以我们将在这里详细解释它们。
角色描述
INTR使终端驱动器向连接到终端的处理操作发送SIGINT信号。我们将在第11章更详细地讨论这些信息。
QUIT使终端驱动程序向连接到终端的处理操作发送SIGQUIT信号。
ERASE使终端驱动程序删除一行的最后一个字符。
KILL导致终端驱动程序删除整行。
EOF使终端驱动程序将一行中的所有字符传递给读取输入的程序。如果这一行是空的,读取调用将返回零个字符,就像读取操作到达文件末尾时一样。
EOL行结束符,类似于更常见的换行符。
SUSP使终端驱动程序向连接到终端的操作发送SIGSUSP信号。如果我们的Unix系统支持工作控制,当前程序将被挂起。
STOP防止更多的输出被发送到终端。用于支持XON/XOFF流量控制,通常设置为ASCII XOFF字符,Ctrl S。
在起止字符后重新开始输出,通常是ASCII XON字符。
和时间最小值
TIME MIN的值只使用非正式模式,共同控制输入的读取。同时,它们控制当程序试图读取与终端相关的文件描述符时会发生什么。
有四种情况:
MIN=0和TIME=0:在这种情况下,read调用将立即返回。如果某些角色可用,他们会立即返回;如果没有可用的字符,read将返回零,并且不会读取任何字符。
MIN=0和TIME 0:在这种情况下,当有任何可读的字符或十分之一秒的时间过去时,read将返回。如果由于时间已到而没有读取任何字符,read将返回零。否则,他将返回读取的字符数。
0 MIN和TIME=0:在这种情况下,read将等待直到有MIN个字符要读取,然后返回读取的字符数。文件末尾返回零。
0分钟,时间0:这是最复杂的情况。当read被调用时,他等待接收一个字符。当接收到第一个字符,并且在随后的时间序列中接收到一个字符时,将启动字符间定时器(如果已经在运行,则重新启动)。当有MIN个字符要读取或中间字符计时器的时间值已经过了十分之一秒时,Read返回。这可以用来区分按下退出键和功能键退出序列的开始之间的区别。但是要小心,网络通讯或者高级处理器会擦除时间信息。
通过设置非正式模式并使用MIN和TIME值,程序可以一次执行一个字符的输入处理。
Shell访问的终端模式
如果我们想要检查我们正在使用的Shell所使用的termios设置,我们可以使用下面的命令来获取一个列表:
$ styy -a
在我们的Linux系统上,对标准termios结构进行了一些扩展,输出如下:
速度38400波特;第44行;列109;line=0;
intr=^c;辞职=^/;抹掉=^?杀=^u;eof=^d;eol=undef eol2=
unde start=^q;停=^s;
susp=^z;RPR nt=^r;werase=^w;lnext=^v;同花顺=^o;min=1;时间=0;
-paren b-parodd cs8-hup cl-cstop b cread-clocal-crtscts
-ign brk-br kint-ign par-parm rk-in PCK-istrip-in LCR-ign Cr ICR nl ixon-ixoff-
iuclc -ixany -imaxbel
opost-ol cuc-ocr nl onlcr-onocr-onret-of ill-of del nl0 cr0 tab 0 bs0 vt0 ff0
isig icanon iexten echo echo echok-echo nl-noflsh-xcase-to stop-echo PRT echo CTL
埃科克
在这些输出之间,我们可以看到EOF字符是Ctrl D,echo是允许的。如果我们测试终端控制,我们可以很容易地使这个终端处理非标准状态,这将使它非常难以使用。有几种方法可以做到这一点。
第一种方法是,如果我们的stty版本支持,我们可以使用以下命令:
$ stty sane
如果我们丢失了回车键到新行字符的映射,我们需要输入stty sane,但是我们需要按Ctrl J(新行字符)而不是按enter。
第二种方法是使用stty -g命令将当前的stty设置保存为可以重新读取的格式。在命令行中,我们可以使用以下命令:
$ stty -g save_stty
.
尝试设置
.
$ stty $(cat save_stty)
对于最后一个stty命令,我们仍然需要使用Ctrl J而不是enter。我们将在shell脚本中使用相同的技术:
save_stty="$(stty -g)"
更改stty设置
stty $save_stty
第三种方法是使用不同的终端,使用ps命令查看我们想要使其不可用的shell,然后使用kill HUP进程id强制结束这个shell。因为stty参数总是在登录提示出现之前设置,所以我们可以正常登录。
通过命令行设置终端模式。
我们也可以使用stty命令直接从命令行设置终端模式。
要设置shell脚本可以读取单个字符的模式,我们需要关闭正常模式,并将MIN设置为1,TIME设置为0。该命令如下所示:
$ stty -icanon最小1时间0
既然终端被设置为立即读取字符,我们可以尝试运行我们的第一个程序。我们会发现它正如我们所希望的那样工作。
我们还可以在提示输入密码之前关闭回显功能。它的命令如下:
$ stty -echo
记得在我们的实验之后使用命令stty echo来打开echo。
最终汇率
termios结构提供的最后一个功能可以操作线路速率。没有为最终费率定义成员;相反,它是通过函数调用来设置的。输入和输出速率是分开处理的。
四个呼叫原型是:
#包含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结构,而不是直接作用于端口。这意味着,要设置一个新的速率,我们必须使用tcgetattr读取当前设置,使用上述函数调用之一来设置速率,然后使用tcsetattr写回termios结构。只有在调用tcsetattr后,线路速率才会改变。
在上述函数调用中允许各种速率值,其中最重要的如下:
B0:暂停终端
B 1200: 1200波特
B 2400: 2400波特
B 9600: 9600波特
B19200:19200波特
B 38400: 38400波特
标准没有定义大于38400的速率,大于这个速率的串口也没有相应的支持功能。
包括Linux在内的一些系统已经定义了B57600、B115200和B230400来选择更快的速率。如果我们使用的是早期版本的Linux并且不能使用这些常量,我们可以使用setserial命令来获得非标准的速率,比如57600和115200。在这种情况下,当选择B38400时,将使用这些速率。这两种方法都不能移植,使用时要慎重。
其余的功能
终端控制还有其他一些功能。这些函数直接作用于文件描述符,而不读取和设置termios结构。它们的定义如下:
#包含termios.h
int TC drain(int FD);
int tcflow(int fd,int flowtype);
int tcflush(int fd,int in _ out _ selector);
这些功能的目的如下:
Tcdrain使调用函数在发送所有输出队列之前等待。
Tcflow用于暂停或重启输出。
Tcflush可用于刷新输入和/或输出。
既然我们已经讨论了相当多的关于termios结构的话题,那么让我们来看一些实际的例子。也许最简单的事情就是在读取密码时禁止echo。我们可以通过关闭ECHO标志来做到这一点。
实验-使用termios读取密码
1我们的密码程序password.c从以下定义开始:
#包含termios.h
#包含stdio.h
#定义密码_LEN 8
int main()
{
struct termios initialrsettings,newrsettings。
char PASSWORD[PASSWORD _ l EN 1];
2接下来,添加一行从当前标准输入中读取当前设置,并将其复制到我们之前创建的termios结构中:
tcgetattr(fileno(stdin),initial rsettings);
3复制原始设置以替换它们。关闭newrsettings中的ECHO标志,并要求用户输入密码:
new r settings=initial r settings;
newrsettings.c _ lflag=~ ECHO
printf("输入密码:");
4然后将terminal属性设置为newrsettings并读取密码。最后将终端属性设置为原来的属性,并打印密码验证之前的效果。
if(tcsetattr(fileno(stdin),TCSAFLUSH,newrsettings)!=0) {
fprintf(stderr,"无法设置属性/n ");
}
否则{
fgets(password,PASSWORD_LEN,stdin);
tcsetattr(fileno(stdin),TCSANOW,initial rsettings);
fprintf(stdout,"/n您输入了%s/n ",密码);
}
退出(0);
}
操作原理
$ ./密码
输入密码:
你输入了你好
$
在本例中,在输入密码:提示符后,输入hello,但输入的字符没有回显。直到用户按下Enter键,才生成输出。
我们小心地使用语句X=~FLAG(清除相应的标志位)来改变我们需要改变的标志位。如果需要,我们可以使用X =FLAG来设置由FLAG定义的位,尽管在上面的例子中并不需要这样做。
当我们设置属性时,我们使用TCSAFLUSH来忽略用户在程序准备读取之前输入的字符。对于用户来说,这是一个在关闭echo之前不输入密码的好方法。同时,我们在节目结束前恢复了之前的设置。
termios结构的另一个常见用途是将终端设置为一种状态,在这种状态下,我们可以立即读取用户输入的字符。我们可以通过关闭正常模式并设置分钟和时间的值来做到这一点。
实验-阅读每个字符。
一使用我们的新程序,我们可以对我们的菜单程序做出修改。下面的代码与密码。c相类似,但是需要插入到菜单3.c中来生成我们的新程序菜单4 .在开始这前,我们需要在程序顶部包含一个新的头文件:
#包含标准视频
#包括unistd.h
#包含termios.h
2然后我们需要在主要的函数中定义一些新的变量:
int choice=0;
文件*输入;
文件*输出;
结构术语初始设置,新设置
3我们需要在调用getchoice函数之前修改终端特点,这就是我们需要插入代码的地方:
fprintf(stderr,"无法打开/dev/tty/n ");
出口(1);
}
tcgetattr(fileno(input),initial _ settings);
新设置=初始设置;
new _ settings.c _ lflag=~ ICANON
new _ settings.c _ lflag=~ ECHO
新设置。c _ cc[VMIN]=1;
新设置。c _ cc[VTIME]=0;
if(tcsetattr(fileno(input),TCSANOW,new_settings)!=0) {
fprintf(stderr,"无法设置属性/n ");
}
fprintf(stderr,"无法打开/dev/tty/n ");
出口(1);
}
tcgetattr(fileno(input),initial _ settings);
新设置=初始设置;
new _ settings.c _ lflag=~ ICANON
new _ settings.c _ lflag=~ ECHO
新设置。c _ cc[VMIN]=1;
新设置。c _ cc[VTIME]=0;
if(tcsetattr(fileno(input),TCSANOW,new_settings)!=0) {
fprintf(stderr,"无法设置属性/n ");
}
四同时我们需要在程序结束之前恢复原始设置:
做{
choice=getchoice("请选择一个动作",菜单,输入,输出);
printf("您已选择:%c/n ",选择);
}而(选择!= q );
tcsetattr(fileno(input),TCSANOW,initial _ settings);
退出(0);
}
5现在我们需要检测回车/r以确保我们在非正规模式,因为不会再执行默认的复活社到低频的映射:
做{
selected=fgetc(in);
} while(selected==/n selected==/r );
6 不幸的是,如果此时用户在我们程序运行时按下Ctrl C,程序就会终止。我们可以通过在本地模式中清除电流信号标记来禁止特殊字符的处理。在主函数中添加下面的代码行:
新设置。c _ lflag=~ ISIG;
如果我们将这些修改加入到我们的程序中,我们现在就会得到一个立即响应并且输入不会回显朱程序:
$ ./menu4
选择:请选择一项活动
表示“不”添加新记录
删除记录
问-退出
您选择了:a
选择:请选择一项活动
表示“不”添加新记录
删除记录
问-退出
你选择了:问
$
如果我们按下Ctrl C,他就会被直接传递给程序,并且将其看作是不正确的选择。