2019年6月26日 星期三

Unix命令行编辑键盘键

1. 命令行编辑
Unix命令行编辑键是非常常用的键,当在命令行键入时,光标指向一个可用位置。每键入一个字符,光标向右移动一个位置。
在键入过程中出错的处理方法:
a. 您可以按<Backspace>键删除一个或多个字符,然后再键入新字符。
b. 如果希望修复命令行开头的错误,而且您已经键入了20个字符。对于大多数shell(并不是全部)来说,可以简单地使用(以后称之为<left>)。每按一次这个键,光标就会在不删除任何内容的情况下向左移动一个位置。然后就可以进行希望的修改,并<Return>键运行命令。

试试下面的例子,这个例子使用的命令是echo(echo命令简单显示赋予它的内容)。键入下述命令:

echo “This is a test”
现在按<Return>键之前。Shell将显示“This is a test!”。现在键入下述内容,但是不按<Return>键:

echo “Thus is a test!”
在按<Return>键之前,需要将Thus改为This。此时,需要重复按<Left>键,直到光标正好位于Thus中u的右边。按下<Backspace>键一次,删除u,然后键入i。按下<Return>键,将会看到正确的输出。
这就是Unix命令行编辑(command line editing)的一个例子,也就是说,在将命令行上的内容发送给shell之前,修改命令行的内容。注意在按<Return>键之前,不必再将光标一直命令行的末尾。(因为光标不生成字符,所以shell不关心在向它发送命令时光标所在的位置)。
现在,讲授3个Unix命令行编辑键盘键最重要的技术。您可以试一试,看看这3个技术是否适合您的特定shell。
第一,在键入时,可以使用<Left>和<Right>箭头在命令行中移动光标。上述例子使用了这种方法。
第二,在任何时间,都可以按<Backspace>键删除前一个字符。对于一些shell来说,还可以使用<Delete >键删除当前字符。
第三,在输入命令时,shell将把命令保存在一个不可见的:“历史列表 ”中。可以使用<up>和<Down>箭头键在历史列表中向后或者向前移动查看命令。当按<up>键时,当前命令消失,被前一条命令取代。如果再次按<up>键,就会得到后者的前一条命令。
因此,可以按<up>键多次,恢复前面的命令。如果发现返回得太多,则可以通过按<down>键在列表中向下移动。在选择了命令之后,还可以编辑命令行,并且通过按下<Return>键重新向shell提交命令。
名称含义:
破坏性退格(destructive backspace)指的是当光标向后移动时,光标经过的字符被删除。当按< backspace >键时就发生这种情况。
非破坏性退格(non-destructive backspace)指的是当光标向后移动时,没有内容被修改。当按<Left>键时就发生这种情况。

2. 返回和换行
在之前,我们讨论了Unix处理<Backspace>键的方式可以追溯到最初的Unix终端Teletype ASR33。具体而言Teletype ASR33在删除纸带上的字符是包含两种Teletype码(BS和DEL)。Unix开发人员选择其中一个代码用于erase信号。
更有趣的是当轮到决定<Return>键的操作内容时,他们都选择相同类型的选项。此外事实证明他们有关<Return>键的决定要比对<Backspace>键的决定更加重要。这是因为他们选择的代码,不仅用于<Return>键,而且还是文本文件每行结束的一个特殊标记。为了开始我们的讨论,需要再返回到Teletype ASR33的那个时代。
Teletype ASR33有一个打印头,使用色带在纸上打印字符。在字符打印时,打印头从左向右移动。当打印头移动到一行的末尾时,必须进行两件事情。首先,打印纸需要向上移动一行;其次打印头(依附在“托架”^)必须返回到最左边。
为了是Teletype执行这些操作,需要在打印的数据中植入代码。而数据可能来自于键盘,也可能来源于通信线路,或者来自于纸带阅读机。
第一个代码是CR(carriage return,托架返回)将托架返回到最左边的位置。第二个代码是LF(linefeed,换行),使打印纸向上移动一行。因此,序列CR-LF执行打印一个新行所需的准备动作。
在键盘上,按下<Return>键或者^M(它们等价)可以发送一个CR码。按下<Linefeed>或者^J键可以发送LF码。(之前的键盘是这样的)
当Unix开发人员开始使用Teletype作为终端时,他们基于CRLF码创建了两个信号。CR码变成了返回信号。LF码变成了换行信号。

3. 新行字符的重要性
正如前面所说,Unix使用两个基于老式的Teletype的信号:返回和换行。在键盘上按下^M将发送返回信号,按下^J将发送换行信号。
既然返回和换行其实^M^J相同,所以我们通常称它们为字符,而不是信号。下面是使用它们的3种不同场景。
第一:当文件中包含有文本数据时,通常将数据分成行。在Unix中,使用^J字符标记每行的结束。当以这种方式使用^J时,我们称它是新行字符,而不是换行字符。因此,在程序从文件中读取数据时,当程序遇到一个新行字符(也就是一个^J字符)时,程序就知道它已经到达了一行的末尾。
第二:当在终端上输入字符时,在行的末尾按下<Return>键。这样做可以发送返回字符,也就是^M
第三:当数据显示时,每次向终端发送一行字符。在每行的末尾,光标必须移动到下一行的开头。和Teletype一样,这包括两个单独的动作:一个“托架返回”动作将光标移动到行的开头,后面跟一个“换行”动作将光标移动到下一行。对于“托架返回”动作,Unix发送一个返回字符(也就是^M对于“换行”动作,Unix发送一个换行字符 (也就是^J)。因此,当数据显示时,每行必须以^M^J结束。
Unix最一流的特性之一就是将键盘键入的数据视为与从文件中读取的数据相同。例如,假如您有一个程序需要读取一系列的名称,每行一个。这样的程序既可以从磁盘上的文件中读取名称,也可以从键盘输入读取名称。该程序不需要以特殊的方式编写就可以拥有这样的灵活性。这一特性称为“标准输入”,已经构建在Unix中。标准输入允许所有的Unix程序以相同的方式读取数据,而不必考虑数据源(我们将在后面讨论这一思想)。
为了使标准输入正常工作,每行数据都必须以一个新行字符结束。但是,当使用键盘键入字符时,字符以一个返回字符结束每行,而不是新行字符。这就产生一个问题。
同理,当Unix程序输出数据时,它们可以利用“标准输出”。这允许所有的程序以相同的方式写数据,而不必担心数据额写到哪里去。
当数据写到文件中时,每行必须以一个新行字符(也就是^J)结束。但是,当数据写到终端上时,每行须以返回+新行(^M^J)结束。这就产生了第二个问题。
这些问题可以以两种方式解决。
第一种:在键入过程中,无论何时,当按下<Return>键时,Unix都将返回字符改变为新行字符。也就是说,Unix将^M改变为^J
第二种:当数据要写到终端上时,Unix将每个新行字符改变为返回字符+新行字符。也就是说,Unix将^J改变为^M^J

为了便于领会,下面给出一个简短的小结:
(1) 返回字符 = ^M
(2) 换行字符=新行字符=^J
(3) 一般而言,每行文本必须以一个新行字符结束。
(4)当按下<Return>键时,将发送一个返回字符,Unix自动地将返回字符变为新行字符。
(5)在终端上显示数据时,每行必须以字符序列“返回+新行”结束
因此,当数据从文件发送到终端显示时,Unix自动地将每行末尾的新行字符改变为返回字符+换行字符。
刚开始时,这看上去可能有点诗人迷惑。最终,您将会明白所有这些非常合理,这时候,您就会知到自己最终开始思考Unix了。
提示:
在文本文件中,Unix使用^Jnewline)字符标记每行结束。但是,Microsoft Windows的做法不同。Windows使用^M^J标记每行的结束(在Unix术语中,这僵尸返回+换行字符)。
因此,当从Unix中向Windows中复制文本文件时,每个^J必须改变为^M^J必须改变为^J
当使用程序在两台这样的计算机之间复制文件时,程序应该直到如何自动地进行这种改变。如果称不能自动的改变,则可以使用实用工具完成该工作。

4. Unix命令行编辑键盘键 ^J 的一个重要用途:stty sane, reset
除非您是一名程序员,否则您并不真的需要掌握与返回字符和新行字符相关的全部技术细节。您只需要记住在每行的末尾按下<Return>即可,其他的让Unix去做。
但是,在某些情形中理解这些思想非常有帮助。在些罕见情况中,终端的设置可能将终端搞乱,从而不能正常工作。在这种情况下,有两条命令可以用来将终端设置恢复为合理值,这两条命令是stty sane和reset。
在一些罕见的情况中,您可能发现当您试图按下<Return>键输入这些命令中的一个时,返回字符不能向新行字符正常转换,Unix不接收命令。如果发生了这种情况,只需简单地按下^M取代<Return>即可。这样就会有效,因为这两个键实质上相同。
解决办法就是按下^J(同新行字符),而^J是所有Unix都接受的。因此,当其他所有方法都失效时,键入下述命令之一可以复原终端。一定要确保在命令前和命令后键入Unix命令行编辑键盘键^J。如果您希望,现在就可以试一试,这两条命令不会破害任何东西。

<Ctrl-J>stty sane<Ctrl-J>
<Ctrl-J>reset<Ctrl-J>

您可能会问,如果是这种情况,那么可以在任何时间按下^J来取代<Return>输入一条命令吗?当然可以——您也可以试一试。
为了证明这些命令是多么有用,我来一个讲述个真实的故事。
有一个人叫Susan,有一天她在帮助别人安装Linux。他们使用了一个程序,这个程序允许选择在内核中包含什么选项。该程序需要一个特定的目录,但是这个目录还不存在,因此在Susan按下^Z暂停程序。她现在有机会创建该目录了。
但是,碰巧的是该程序为了防止改变显示禁用了返同字符的作用。这意味着,无论Susan何时输入命令,输出都不正常显示。
(请记住,当Unix将数据写到终端时,它将返同字符+换行字符放在每行的末尾。您可以想一想,当只有换行字符起作用时,会发生什么情况呢?)
但是,Susan也不简单。她输入了reset命令,很快,终端工作正常了。然后她创建了需要的目录,重新启动程序的安装过程,从而顺利地安装了程序。

沒有留言:

張貼留言