发帖时间: 02-08-22, 01:12
shell命令[转帖]
--------------------------------------------------------------------------------
shell是用户和Linux操作系统之间的接口。Linux中有多种shell,其中缺省使用的是Bash。本章讲述了shell的工作原理,shell的种类,shell的一般操作及Bash的特性。
什么是shell
Linux系统的shell作为操作系统的外壳,为用户提供使用操作系统的接口。它是命令语言、命令解释程序及程序设计语言的统称。
shell是用户和Linux内核之间的接口程序,如果把Linux内核想象成一个球体的中心,shell就是围绕内核的外层。当从shell或其他程序向Linux传递命令时,内核会做出相应的反应。
shell是一个命令语言解释器,它拥有自己内建的shell命令集,shell也能被系统中其他应用程序所调用。用户在提示符下输入的命令都由shell先解释然后传给Linux核心。
有一些命令,比如改变工作目录命令cd,是包含在shell内部的。还有一些命令,例如拷贝命令cp和移动命令rm,是存在于文件系统中某个目录下的单独的程序。对用户而言,不必关心一个命令是建立在shell内部还是一个单独的程序。
shell首先检查命令是否是内部命令,若不是再检查是否是一个应用程序(这里的应用程序可以是Linux本身的实用程序,如ls和rm,也可以是购买的商业程序,如xv,或者是自由软件,如emacs)。然后shell在搜索路径里寻找这些应用程序(搜索路径就是一个能找到可执行程序的目录列表)。如果键入的命令不是一个内部命令并且在路径里没有找到这个可执行文件,将会显示一条错误信息。如果能够成功找到命令,该内部命令或应用程序将被分解为系统调用并传给Linux内核。
shell的另一个重要特性是它自身就是一个解释型的程序设计语言,shell程序设计语言支持绝大多数在高级语言中能见到的程序元素,如函数、变量、数组和程序控制结构。shell编程语言简单易学,任何在提示符中能键入的命令都能放到一个可执行的shell程序中。
当普通用户成功登录,系统将执行一个称为shell的程序。正是shell进程提供了命令行提示符。作为默认值(TurboLinux系统默认的shell是BASH),对普通用户用“$”作提示符,对超级用户(root)用“#”作提示符。
一旦出现了shell提示符,就可以键入命令名称及命令所需要的参数。shell将执行这些命令。如果一条命令花费了很长的时间来运行,或者在屏幕上产生了大量的输出,可以从键盘上按ctrl+c发出中断信号来中断它(在正常结束之前,中止它的执行)。
当用户准备结束登录对话进程时,可以键入logout命令、exit命令或文件结束符(EOF)(按ctrl+d实现),结束登录。
我们来实习一下shell是如何工作的。
$ make work
make:***No rule to make target ‘work’. Stop.
$
注释:make是系统中一个命令的名字,后面跟着命令参数。在接收到这个命令后,shell便执行它。本例中,由于输入的命令参数不正确,系统返回信息后停止该命令的执行。
在例子中,shell会寻找名为make的程序,并以work为参数执行它。make是一个经常被用来编译大程序的程序,它以参数作为目标来进行编译。在“make work”中,make编译的目标是work。因为make找不到以work为名字的目标,它便给出错误信息表示运行失败,用户又回到系统提示符下。
另外,用户键入有关命令行后,如果shell找不到以其中的命令名为名字的程序,就会给出错误信息。例如,如果用户键入:
$ myprog
bash:myprog:command not found
$
可以看到,用户得到了一个没有找到该命令的错误信息。用户敲错命令后,系统一般会给出这样的错误信息。
shell的种类
Linux中的shell有多种类型,其中最常用的几种是Bourne shell(sh)、C shell(csh)和Korn shell(ksh)。三种shell各有优缺点。Bourne shell是UNIX最初使用的shell,并且在每种UNIX上都可以使用。Bourne shell在shell编程方面相当优秀,但在处理与用户的交互方面做得不如其他几种shell。Linux操作系统缺省的shell是Bourne Again shell,它是Bourne shell的扩展,简称Bash,与Bourne shell完全向后兼容,并且在Bourne shell的基础上增加、增强了很多特性。Bash放在/bin/bash中,它有许多特色,可以提供如命令补全、命令编辑和命令历史表等功能,它还包含了很多C shell和Korn shell中的优点,有灵活和强大的编程接口,同时又有很友好的用户界面。
C shell是一种比Bourne shell更适于编程的shell,它的语法与C语言很相似。 Linux为喜欢使用C shell的人提供了Tcsh。Tcsh是C shell的一个扩展版本。Tcsh包括命令行编辑、可编程单词补全、拼写校正、历史命令替换、作业控制和类似C语言的语法,它不仅和Bash shell是提示符兼容,而且还提供比Bash shell更多的提示符参数。
Korn shell集合了C shell和Bourne shell的优点并且和Bourne shell完全兼容。Linux系统提供了pdksh(ksh的扩展),它支持任务控制,可以在命令行上挂起、后台执行、唤醒或终止程序。
Linux并没有冷落其他shell用户,还包括了一些流行的shell如ash、zsh等。每个shell都有它的用途,有些shell是有专利的,有些能从Internet网上或其他来源获得。要决定使用哪个shell,只需读一下各种shell的联机帮助,并试用一下。
用户在登录到Linux时由/etc/passwd文件来决定要使用哪个shell。例如:
# fgrep lisa /etc/passwd
lisa:x:500:500:TurboLinux User:/home/lisa:/bin/bash
shell被列每行的末尾(/bin/bash)。
由于Bash是Linux上缺省的shell,本章主要介绍Bash及其相关知识。
shell命令
命令行c
用户登录到Linux系统时,可以看到一个shell提示符,标识了命令行的开始。用户可以在提示符后面输入任何命令及参数。例如:
$ date
二 11 23 01:34:58 CST 1999
$
用户登录时,实际进入了shell,它遵循一定的语法将输入的命令加以解释并传给系统。命令行中输入的第一个字必须是一个命令的名字,第二个字是命令的选项或参数,命令行中的每个字必须由空格或TAB隔开,格式如下:
$ Command Option Arguments
1. 选项和参数
选项是包括一个或多个字母的代码,它前面有一个减号(减号是必要的,Linux用它来区别选项和参数),选项可用于改变命令执行的动作的类型。例如:
$ ls
motd passwd
$
这是没有选项的ls命令,可列出当前目录中所有文件,只列出各个文件的名字,而不显示其他更多的信息。
$ ls -l
total 2
-rw-r--r-- 2 wzh book 22 Apr 20 20:37 motd
-rw-r--r-- 2 wzh book 796 Apr 20 20:37 passwd
$
加入-l选项,将会为每个文件列出一行信息,诸如数据大小和数据最后被修改的时间。
大多数命令都被设计为可以接纳参数。参数是在命令行中的选项之后键入的一个或多个单词,例如:
$ ls -l text
-rw-r--r-- 2 wzh book 22 Apr 20 20:37 motd
-rw-r--r-- 2 wzh book 796 Apr 20 20:37 passwd
$
将显示text目录下的所有文件及其信息。
有些命令,如ls可以带参数,而有一些命令可能需要一些最小数目的参数。例如,cp命令至少需要两个参数,如果参数的数目与命令要求不符,shell将会给出出错信息。例如:
$ cp -i mydata newdata
注意:命令行中选项先于参数输入。
2. 命令行特征
命令行实际上是可以编辑的一个文本缓冲区,在按回车之前,可以对输入的文本进行编辑。比如利用BACKSPACE键可以删除刚键入的字符,可以进行整行删除,还可以插入字符,使得用户在输入命令,尤其是复杂命令时,若出现键入错误,无须重新输入整个命令,只要利用编辑操作,即可改正错误。
利用上箭头可以重新显示刚执行的命令,利用这一功能可以重复执行以前执行过的命令,而无须重新键入该命令。
bash保存着以前键入过的命令的列表,这一列表被称为命令历史表。按动上箭头,便可以在命令行上逐次显示各条命令。同样,按动下箭头可以在命令列表中向下移动,这样可以将以前的各条命令显示在命令行上,用户可以修改并执行这些命令。这一特征将在10.4节中进行详细的论述。
在一个命令行中还可以置入多个命令,用分号将各个命令隔开。例如:
$ ls -F;cp -i mydata newdata
也可以在几个命令行中输入一个命令,用反斜杠将一个命令行持续到下一行。
$ cp –i
mydata
newdata
上面的cp命令是在三行中输入的,开始的两行以反斜杠结束,把三行作为一个命令行。
shell中的特殊字符
shell中除使用普通字符外,还可以使用一些具有特殊含义和功能的特殊字符。在使用它们时应注意其特殊的含义和作用范围。下面分别对这些特殊字符加以介绍。
1. 通配符
通配符用于模式匹配,如文件名匹配、路经名搜索、字符串查找等。常用的通配符有*、?和括在方括号[ ]中的字符序列。用户可以在作为命令参数的文件名中包含这些通配符,构成一个所谓的“模式串”,在执行过程中进行模式匹配。
* 代表任何字符串(长度可以不等),例如:“f*”匹配以f打头的任意字符串。但应注意,文件名前的圆点(.)和路经名中的斜线(/)必须显式匹配。例如“*”不能匹配.file,而“.*”才可以匹配.file。
? 代表任何单个字符。
[] 代表指定的一个字符范围,只要文件名中[ ]位置处的字符在[ ]中指定的范围之内,那么这个文件名就与这个模式串匹配。方括号中的字符范围可以由直接给出的字符组成,也可以由表示限定范围的起始字符、终止字符及中间的连字符(-)组成。例如,f [a- d] 与f [abcd]的作用相同。Shell将把与命令行中指定的模式串相匹配的所有文件名都作为命令的参数,形成最终的命令,然后再执行这个命令。
下面我们给出表10-1说明这些通配符的具体含义。
表10-1 通配符含义举例
模式串
意 义
*
当前目录下所有文件的名称。
*Text*
当前目录下所有文件名中包含有Text的文件的名称。
[ab-dm]*
当前目录下所有以a、b、c、d、m开头的文件的名称。
[ab-dm]?
当前目录下所有以a、b、c、d、m开头且后面只跟有一个字符的文件的名称。
/usr/bin/??
目录/usr/bin下所有名称为两个字符的文件的名称。
特别需要注意的是,连字符“-”仅在方括号内有效,表示字符范围,如在方括号外面就成为普通字符了。而*和?只在方括号外面是通配符,若出现在方括号之内,它们也失去通配符的能力,成为普通字符了。例如,模式“- a[*?]abc”中只有一对方括号是通配符,*和?均为普通字符,因此,它匹配的字符串只能是- a*abc和- a?abc。
最后说明一下使用通配符时需要注意的一些问题。由于*、?和[ ]对于shell来说具有比较特殊的意义,因此在正常的文件名中不应出现这些字符。特别是在目录名中不要出现它们,否则Shell匹配起来可能会无穷的递归下去。另外要注意的一点是:如果目录中没有与指定的模式串相匹配的文件名,那么Shell将使用此模式串本身作为参数传给有关命令。这可能就是命令中出现特殊字符的原因所在。
2. 引号
在shell中引号分为三种:单引号,双引号和反引号。
* 单引号 ‘
由单引号括起来的字符都作为普通字符出现。特殊字符用单引号括起来以后,也会失去原有意义,而只作为普通字符解释。例如:
$ string=’$PATH’
$ echo $string
$PATH
$
可见$保持了其本身的含义,作为普通字符出现。
* 双引号 “
由双引号括起来的字符,除$、、’、和”这几个字符仍是特殊字符并保留其特殊功能外,其余字符仍作为普通字符对待。对于$来说,就是用其后指定的变量的值来代替这个变量和$;对于而言,是转义字符,它告诉shell不要对其后面的那个字符进行特殊处理,只当作普通字符即可。可以想见,在双引号中需要在前面加上的只有四个字符$,,’和”本身。而对”号,若其前面没有加,则Shell会将它同前一个”号匹配。
例如,我们假定PATH的值为.:/usr/bin:/bin,输入如下命令:
$ TestString=”$PATH/”$PATH”
$ echo $TestString
.:/usr/bin:/ bin”$PATH
$
读者可以自己试一下在第二个双引号之前不加会产生什么结果。
* 反引号 `
反引号(`)这个字符所对应的键一般位于键盘的左上角,不要将其同单引号(’)混淆。反引号括起来的字符串被shell解释为命令行,在执行时,shell首先执行该命令行,并以它的标准输出结果取代整个反引号(包括两个反引号)部分。例如:
$ pwd
/home/xyz
$ string=”current directory is `pwd`”
$ echo $string
current directour is /home/xyz
$
shell执行echo命令时,首先执行`pwd`中的命令pwd,并将输出结果/home/xyz取代`pwd`这部分,最后输出替换后的整个结果。
利用反引号的这种功能可以进行命令置换,即把反引号括起来的执行结果赋值给指定变量。例如:
$ today=`date`
$ echo Today is $today
Today is Mon Apr 15 16:20:13 CST 1999
$
反引号还可以嵌套使用。但需注意,嵌套使用时内层的反引号必须用反斜线()将其转义。例如:
$ abc=`echo The number of users is `who| wc-l``
$ echo $abc
The number of users is 5
$
在反引号之间的命令行中也可以使用shell的特殊字符。Shell为得到``中命令的结果,它实际上要去执行``中指定的命令。执行时,命令中的特殊字符,如$,”,?等又将具有特殊含义,并且``所包含的可以是任何一个合法的Shell命令,如:
$ ls
note readme.txt Notice Unix.dir
$ TestString=”`echo $HOME ` ` ls [nN]*`”
$ echo $TestString
/home/yxz note Notice
$
其他情况,读者可自行试之。
1. 注释符
在shell编程中经常要对某些正文行进行注释,以增加程序的可读性。在Shell中以字符“#”开头的正文行表示注释行。
此外还有一些特殊字符如:用于输入/输出重定向与管道的<、>、<<、>>和|;执行后台命令的&;命令执行操作符&&和||及表示命令组的{}将在下面各小节中加以介绍。
标准输入/输出和重定向
1. 标准输入与输出
我们知道,执行一个shell命令行时通常会自动打开三个标准文件,即标准输入文件(stdin),通常对应终端的键盘;标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。
我们以cat命令为例,cat命令的功能是从命令行给出的文件中读取数据,并将这些数据直接送到标准输出。若使用如下命令:
$ cat config
将会把文件config的内容依次显示到屏幕上。但是,如果cat的命令行中没有参数,它就会从标准输入中读取数据,并将其送到标准输出。例如:
$ cat
Hello world
Hello world
Bye
Bye
<ctrl+d>
$
用户输入的每一行都立刻被cat命令输出到屏幕上。
另一个例子,命令sort按行读入文件正文(当命令行中没有给出文件名时,表示从标准输入读入),将其排序,并将结果送到标准输出。下面的例子是从标准输入读入一个采购单,并将其排序。
$ sort
bananas
carrots
apples
<ctrl+d>
apples
bananas
carrots
$
这时我们在屏幕上得到了已排序的采购单。
直接使用标准输入/输出文件存在以下问题:
输入数据从终端输入时,用户费了半天劲输入的数据只能用一次。下次再想用这些数据时就得重新输入。而且在终端上输入时,若输入有误修改起来不是很方便。
输出到终端屏幕上的信息只能看不能动。我们无法对此输出作更多处理,如将输出作为另一命令的输入进行进一步的处理等。
为了解决上述问题,Linux系统为输入、输出的传送引入了另外两种机制,即输入/输出重定向和管道。
2. 输入重定向
输入重定向是指把命令(或可执行程序)的标准输入重定向到指定的文件中。也就是说,输入可以不来自键盘,而来自一个指定的文件。所以说,输入重定向主要用于改变一个命令的输入源,特别是改变那些需要大量输入的输入源。
例如,命令wc统计指定文件包含的行数、单词数和字符数。如果仅在命令行上键入:
$ wc
wc将等待用户告诉它统计什么,这时shell就好象死了一样,从键盘键入的所有文本都出现在屏幕上,但并没有什么结果,直至按下<ctrl+d>,wc才将命令结果写在屏幕上。
如果给出一个文件名作为wc命令的参数,如下例所示,wc将返回该文件所包含的行数、单词数和字符数。
$ wc /etc/passwd
20 23 726 /etc/passwd
$
另一种把/etc/passwd文件内容传给wc命令的方法是重定向wc的输入。输入重定向的一般形式为:命令<文件名。可以用下面的命令把wc命令的输入重定向为/etc/passwd文件:
$ wc < /etc/passwd
20 23 726
$
另一种输入重定向称为here文档,它告诉shell当前命令的标准输入来自命令行。here文档的重定向操作符使用<<。它将一对分隔符(本例中用delim表示)之间的正文重定向输入给命令。下例将一对分隔符delim之间的正文作为wc命令的输入,统计出正文的行数、单词数和字符数。
$ wc<<delim
>this text forms the content
>of the here document,which
>continues until the end of
>text delimter
>delim
4 17 98
在<<操作符后面,任何字符都可以作为正文开始前的分隔符,本例中使用delim作为分隔符。here文档的正文一直延续到遇见另一个分隔符为止。第二个分隔符应出现在新行的开头。这时here文档的正文(不包括开始和结束的分隔符)将重新定向送给命令wc作为它的标准输入。
由于大多数命令都以参数的形式在命令行上指定输入文件的文件名,所以输入重定向并不经常使用。尽管如此,当要使用一个不接受文件名作为输入参数的命令,而需要的输入内容又存在一个文件里时,就能用输入重定向解决问题。
1. 输出重定向
输出重定向是指把命令(或可执行程序)的标准输出或标准错误输出重新定向到指定文件中。这样,该命令的输出就不显示在屏幕上,而是写入到指定文件中。
输出重定向比输入重定向更常用,很多情况下都可以使用这种功能。例如,如果某个命令的输出很多,在屏幕上不能完全显示,那么将输出重定向到一个文件中,然后再用文本编辑器打开这个文件,就可以查看输出信息;如果想保存一个命令的输出,也可以使用这种方法。还有,输出重定向可以用于把一个命令的输出当作另一个命令的输入(还有一种更简单的方法,就是使用管道,将在下面介绍)。
输出重定向的一般形式为:命令>文件名。例如:
$ ls > directory.out
$ cat directory.out
ch1.doc ch2.doc ch3.doc chimp config mail/ test/
$
将ls命令的输出保存为一个名为directory.out的文件。
注:如果>符号后边的文件已存在,那么这个文件将被重写。
为避免输出重定向中指定文件只能存放当前命令的输出重定向的内容,shell提供了输出重定向的一种追加手段。输出追加重定向与输出重定向的功能非常相似,区别仅在于输出追加重定向的功能是把命令(或可执行程序)的输出结果追加到指定文件的最后,而该文件原有内容不被破坏。
如果要将一条命令的输出结果追加到指定文件的后面,可以使用追加重定向操作符>>。形式为:命令>>文件名。例如:
$ ls *.doc>>directory.out
$ cat directory.out
ch1.doc ch2.doc ch3.doc chimp config mail/ test/
ch1.doc ch2.doc ch3.doc
$
和程序的标准输出重定向一样,程序的错误输出也可以重新定向。使用符号2>(或追加符号2>>)表示对错误输出设备重定向。例如下面的命令:
$ ls /usr/tmp 2> err.file
可在屏幕上看到程序的正常输出结果,但又将程序的任何错误信息送到文件err.file中,以备将来检查用。
还可以使用另一个输出重定向操作符(&>)将标准输出和错误输出同时送到同一文件中。例如:
$ ls /usr/tmp &> output.file
利用重定向将命令组合在一起,可实现系统单个命令不能提供的新功能。例如使用下面的命令序列:
$ ls /usr/bin > /tmp/dir
$ wc –w < /tmp/dir
459
统计了/usr/bin目录下的文件个数。
管 道
将一个程序或命令的输出作为另一个程序或命令的输入,有两种方法,一种是通过一个临时文件将两个命令或程序结合在一起,例如上个例子中的/tmp/dir文件将ls和wc命令联在一起;另一种是Linux所提供的管道功能。这种方法比前一种方法更好。
管道可以把一系列命令连接起来,这意味着第一个命令的输出会作为第二个命令的输入通过管道传给第二个命令,第二个命令的输出又会作为第三个命令的输入,以此类推。显示在屏幕上的是管道行中最后一个命令的输出(如果命令行中未使用输出重定向)。
通过使用管道符“|”来建立一个管道行。用管道重写上面的例子:
$ ls /usr/bin|wc -w
1789
再如:
$ cat sample.txt|grep "High"|wc -l
管道将cat命令(列出一个文件的内容)的输出送给grep命令。grep命令在输入里查找单词High,grep命令的输出则是所有包含单词High的行,这个输出又被送给wc命令,wc命令统计出输入中的行数。假设sample.txt文件的内容如下:
Things to do today:
Low:Go grocery shopping
High:Return movie
High:Clear level 3 in Alien vs. Predator
Medium:Pick up clothes from dry cleaner
那么该管道行的结果是2。
命令替换
命令替换和重定向有些相似,但区别在于命令替换是将一个命令的输出作为另外一个命令的参数。常用命令格式为:
command1 `command2`
其中,command2的输出将作为command1的参数。需要注意的是这里的`符号,被它括起来的内容将作为命令执行,执行后的结果作为command1的参数。例如:
$ cd `pwd`
该命令将pwd命令列出的目录作为cd命令的参数,结果仍然是停留在当前目录下。
第二十二课 在Bash中的操作 2000年/5月/29日
命令和文件名扩展特性
Bash命令行具有命令和文件名扩展特性。当输入一个还没完成的命令或文件名时,只需键入Tab键就能激活命令和文件名扩展特性,从而完成该命令的剩余输入。如果有多个命令或文件的前缀相同,Bash将响铃并等待用户输入足够的字符,以便选择唯一的命令或文件名,如果找到,系统将自动补齐搜索到的命令或文件名,用户按回车键后,系统将执行这条指令。例如:
$ cat pre <Tab>
$ cat preface
Bash也能列出当前目录下部分匹配的文件名来完成文件名扩展。如果键入Esc,然后键入?,shell将列出所有与输入的字符串相匹配的文件名。例如下例,在没有完成的输入后键入Esc ?,shell将列出所有与输入的字符串相匹配的字符串,然后shell回显命令行,根据列出的文件名,可以键入要输入的文件名或按下Tab键来完成文件名扩展。例如:
$ ls
document docudrama
$ cat doc <ESC ?>
document
docudrama
$ cat docudrama
[例】下面是一个目录包含的文件列表:
Firebird2.7.tgz Firebird.README Firebird2.60.tgz
FireBird Firebird2.60.tgz.README
现在要删除Firebird2.60.tgz.README文件,键入:
$ rm –f Fi<Tab>
系统会发出警报声,并且自动将命令行补全为:
$ rm –f Fire
并等待用户进一步输入文件名的后面部分。现在再键入:
b<Tab>
系统再次发出警报声,并且自动将命令行补全为:
$ rm –f Firebird
并等待用户进一步输入文件名的后面部分。现在再键入:
2.6<Tab>
系统再次发出警报声,并且自动将命令行补全为:
$ rm –f Firebird2.60.tgz
并等待用户进一步输入文件名的后面部分。现在再键入:
.<Tab>
此时命令将被补全为:
$ rm –f Firebird2.60.tgz..README
从上例可以看到,bash总是尽力根据用户输入的信息来补全命令。当无法根据现有信息补全命令时,则提示用户再给出更多的信息,然后再根据用户的提示来进一步补全命令。作为用户最好是能够一次性给出足够的信息以便于bash进行命令补全;否则多按几次<Tab>,时间也就消耗掉了。
命令行编辑
在Bash中可以对命令行进行编辑,以便用户在执行所键入的命令之前能够修改所键入的命令。如果在键入命令时出现拼写错误,只需在运行所键入的命令之前,使用编辑命令来纠正编辑错误,然后执行它,而不用重新输入整行命令。这个功能对以长路径文件名作参数的命令特别有用。
表10-2是对命令行编辑操作的一个总结。
表10-2 命令行编辑操作
命令行编辑操作
功能
Ctrl+b或左箭头键
左移一个字符(移至前一个字符)
Ctrl+f或右箭头键
右移一个字符(移至后一个字符)
Ctrl+a
移至行首
Ctrl+e
移至行尾
Esc b
左移一个单词
Esc f
右移一个单词
Del
删除光标所在处的字符
Ctrl+d
删除光标所在处的字符
BACKSPACE或Ctrl+h
删除光标左边的字符
Ctrl+k
删除至行尾
命令历史
在Bash中,history命令能够保存最近所执行的命令。这些命令的历史记录号从1开始,只有有限个命令可以被保存起来,最多500个,即history命令的历史记录号缺省值为500。要查看最近执行的命令,只要键入history命令,然后键入回车键,最近执行过的命令即按先后顺序被显示出来(各条命令前的数字为历史记录号)。
[例】
$ history
1 cp mydata today
2 vi mydata
3 mv mydata reports
4 cd reports
5 ls
…
所有这些命令都被称为事件(event),一个事件表示一个操作已经发生,即一个命令已被执行。这些事件根据它们被执行的先后顺序用数字标识,这一标识称为历史事件号。最后执行的历史事件的事件号最大。每个事件都可由它的历史事件号或命令的初始字符或字符串等确定。
利用history命令能够查询以前的事件,并可把它们显示到命令行上执行这一事件。最简便的方法就是利用上下箭头键,把先前的事件逐次显示到命令行。这个操作不需要运行history命令就可以执行。按动一下上箭头键,那么上一次执行的一个事件就将出现在命令行上,再按一下,上一次的前一事件又会出现在命令行上;按动一下下箭头键,将会使当前事件的下一事件出现在命令行上。
Bash也可以通过键入Esc、Tab键来完成对历史事件的字符扩展。和标准命令行扩展特性一样,键入历史事件的部分字符串,然后键入Esc,再键入Tab键,与刚才键入的字符串相匹配的历史事件将自动扩展并回显到命令行处。如果不止一个事件与输入的字符串相匹配,就会听到一声响铃,继续键入字符或字符串,shell将会唯一确定用户所要键入的历史事件。
还有一个查询和执行历史事件的命令——!命令。在!命令后键入与历史事件相关联的字符,这个关联字符可以是历史事件的历史事件号,也可以是该事件的前几个字符。在下面的例子中,查询到历史事件号为3的事件,然后又用其开头的几个字符去匹配,也查询到该命令。
[例】
$ !3
mv mydata reports
$ !mv
mv mydata reports
也可以用一个偏移量(相对于历史事件列表中最后一个事件)来查询历史事件。负的偏移量将从历史事件列表表尾向前偏移。在下面的例子中,历史事件号为2的事件“vi mydata”就是用一个负的偏移量查询到的。必须注意的是,这个偏移量是相对于历史事件列表中的最后一个事件的。在本例中,历史事件列表中最后一个事件是事件5,历史事件列表中第一个事件为1。从历史事件号为5的事件,往前偏移4,即是历史事件号为2的事件。
[例】
$ !-4
vi mydata
如果键入!!,则系统默认为上一事件。下面的例子中,用户在命令行上键入!!命令,系统将执行上一事件:“ls”命令。
[例】
$ !!
ls
mydata today reports
也可以用“模式”来搜索一个历史事件。搜索的“模式”必须用符号“?”括起来。下例是用“模式”“?myd?”来搜索历史事件号为3的历史事件“vi mydata”。
[例】
$ !?myd?
vi mydata
1. 查询历史事件
可以在命令行上编辑历史事件列表中的事件。表10-3列出了查询历史事件列表的各种操作。
表10-3 查询历史事件操作
查询历史事件操作
功能
Ctrl+n或向下光标键
移至历史事件列表中当前事件的下一历史事件
Ctrl+p或向上光标键
移至历史事件列表中当前事件的前一历史事件
Esc <
移至历史事件列表表首
Esc >
移至历史事件列表表尾
!event_num
用历史事件号来定位一个历史事件
!characters
用历史事件的字符前缀来查询一个历史事件
!?pattern
用“模式”来查询历史事件列表中的事件
!-event_num
通过偏移量来定位历史事件
2. 配置history:HISTFILE及HISTSIZE
系统保存的历史事件数被保存在一个特定的系统变量中,这个变量就是HISTSIZE。这个变量的缺省值通常被设置为500。这个值可以被修改。例如:
$ HISTSIZE=10
将HISTSIZE的值重新设置为10。
历史事件被保存在一个文件中,文件名由变量HISTFILE指定。通常这个文件的缺省名是.bash_history。通过给变量HISTFILE赋值,可以指定新的文件名。
[例】
$ echo $HISTFILE
/home/lisa/.bash_history
$ HISTFILE=”/home/lisa/newhist”
$ echo $HISTFILE
/home/lisa/newhist
以上操作先显示变量HISTFILE的值,然后赋予它新的值“/home/lisa/newhist”,以后所有的历史事件将被保存在newhist文件中。
别名
还有一个使工作变得轻松的方法是使用命令别名。命令别名通常是其他命令的缩写,用来减少键盘输入。
命令格式为:
alias [alias-name=’original-command’]
其中,alias-name是用户给命令取的别名,original-command是原来的命令和参数。需要注意的是,由于Bash是以空格或者回车来识别原来的命令的,所以如果不使用引号就可能导致Bash只截取第一个字,从而出现错误。如果alias命令后面不使用任何参数,则显示当前正在使用的被别名化的命令及其别名。为命令取的别名在该次登录期间始终有效。如果用户需要别名在每次登录时都有效,那么就将alias命令写到初始化脚本文件中。
[例]如果经常要键入如下的命令,最好为它建立一个别名来减少工作量。
$ cd /usr/X11/lib/X11
假如为这个长命令建立一个名为goconfig的别名,在Bash提示符下键入如下命令:
$ alias goconfig=’cd /usr/X11/lib/X11’
现在,除非您退出Bash,键入goconfig将和原来的长命令有同样的作用。如果想取消别名,可以使用下面的命令:
$ unalias goconfig
这是一些很多人认为有用的别名,可以把它们写入初始化脚本文件中来提高工作效率:
alias ll=’ls –l’
alias log=’logout’
alias ls=’ls –F’
如果您是一名DOS用户并且习惯了DOS命令,可以用下面的别名定义使Linux表现得象DOS一样:
alias dir=’ls’
alias copy=’cp’
alias rename=’mv’
alias md=’mkdir’
alias rd=’rmdir’
注意:在定义别名时,等号两边不能有空格,否则shell不能决定您需要做什么。仅在命令中包含空格或特殊字符时才需要引号。
如果键入不带任何参数的alias命令,将显示所有已定义的别名。
提示符
Bash有两级提示符。第一级提示符是经常见到的Bash在等待命令输入时的情况。第一级提示符的默认值是$符号。如果用户不喜欢这个符号,或者愿意自己定义提示符,只需修改PS1变量的值。例如将其改为:
PS1=”Enter a command:”
第二级提示符是当Bash为执行某条命令需要用户输入更多信息时显示的。第二级提示符默认为>。如果需要自己定义该提示符,只需改变PS2变量的值。例如将其改为:
PS2=”More information:”
上面的两个例子都是设定提示符为静态字符串的情况。其实用户也可以使用一些事先已经定义好的特殊字符。这些特殊字符将使提示符中包含当前时间之类的信息。表10-4列出了最常用的一些特殊字符及其含义。
表10-4 bash提示符常用特殊字符
特殊字符
说 明
!
显示该命令的历史编号
#
显示shell激活后,当前命令的历史编号
$
显示一个$符号,如果当前用户是root则显示#符号
/
显示一个反斜杠
d
显示当前日期
h
显示运行该shell的计算机主机名
n
打印一个换行符,这将导致提示符跨行
s
显示正在运行的Shell的名称
t
显示当前时间
u
显示当前用户的用户名
W
显示当前工作目录基准名
w
显示当前工作目录
这些特殊字符可以组合起来,为用户提供一些提示符,提供很有用的信息。下面来看几个实际例子:
PS1=”t”
将使提示符变成如下所示:
02:16:15
而 PS1=t
将使提示符变成如下所示:
t
若PS1=”t/”
将使提示符变成如下所示:
02:16:30
该例就是使用两个特殊字符的组合得到的。
控制shell的运行方式
Bash有一些特殊变量,能控制shell以不同的方式工作。例如,变量noclobber能防止在重定向输出时意外地覆盖一个文件。通过set命令可以设置noclobber变量的有效或无效。set命令有两个参数:一个是指定变量开(on)或关(off)的选项,一个是特殊变量的变量名。要使某一特殊变量开(有效),用-o选项,要使其关(无效),用+o选项。例如:
$ set –o noclobber // 使noclobber变量开
$ set +o noclobber // 使noclobber变量关
三个最常用的shell特殊变量有:ignoreeof、noclobber及noglob。
ignoreeof
ignoreeof变量用来禁止使用ctrl+d来退出shell(ctrl+d不仅用来退出shell,而且可以终止用户直接输往标准输出上的输入。该操作经常在一些shell实用命令中使用,例如实用命令cat。在这些实用程序操作中,非常容易误操作而意外地退出shell。ignoreeof特殊变量正是用来防止这种意外的退出。例如:
$ set –o ignoreeof
之后,用户只能用logout或exit命令退出shell。
noclobber
noclobber变量可以在重定向输出时保护已存在的文件,防止被意外地覆盖。在下例中,用户设置noclobber为有效,在重定向时,用户试图去覆盖已经存在的文件myfile,此时系统将返回一个错误信息。
[例]
$ set –o noclobber
$ cat preface>myfile
bash: myfile: cannot overwrite existing file
$
noglob
设置noglob变量后,shell将不扩展文件名中一些特殊的字符或字符串。如字符*、?、[ ]等将不再作为通配符。如果用户希望列出结尾为?的文件名answer?,可通过如下步骤:首先,用户使noglob变量为无效,然后再列出文件名。可以看到,目前命令行上的问号?被认为是文件名中的一个字符,而不再被看作通配符。
$ set –o noglob
$ ls answer?
answer?
子shell与export命令
用户登录到Linux系统后,系统将启动一个用户shell。在这个shell中,可以使用shell命令或声明变量,也可以创建并运行shell脚本程序。运行shell脚本程序时,系统将创建一个子shell。此时,系统中将有两个shell,一个是登录时系统启动的shell,另一个是系统为运行脚本程序创建的shell。当一个脚本程序运行完毕,它的脚本shell将终止,可以返回到执行该脚本之前的shell。从这种意义上来说,用户可以有许多shell,每个shell都是由某个shell(称为父shell)派生的。
在子shell中定义的变量只在该子shell内有效。如果在一个shell脚本程序中定义了一个变量,当该脚本程序运行时,这个定义的变量只是该脚本程序内的一个局部变量,其他的shell不能引用它,要使某个变量的值可以在其他shell中被改变,可以使用export命令对已定义的变量进行输出。export命令将使系统在创建每一个新的shell时定义这个变量的一个拷贝。这个过程称之为变量输出。
[例]在本例中,变量myfile是在dispfile脚本程序中定义的。然后用export命令将变量myfile输出至任何子shell,例如当执行printfile脚本程序时产生的子shell。
dispfile脚本程序清单:
/**************begin dispfile**************/
myfile=”List”
export myfile
echo “Displaying $myfile”
pr –t –n $myfile
printfile
/**************end dispfile***************/
printfile脚本程序清单:
/**************begin printfile**************/
echo “Printing $myfile”
lpr $myfile&
/**************end printfile**************/
$dispfile
Displaying List
1 screen
2 modem
3 paper
Printing List
$
定制Bash
在本节中已经介绍了很多定制Bash的方法,但是迄今为止,这些方法都只是对当前Bash对话有用。只要用户退出登录,所做的一切改变都会丢失。所以应该在Bash的初始化文件中做永久性的修改。
用户可以将每次启动Bash所需要执行的命令放入初始化文件中,最常见的命令就是alias命令和变量定义两种。系统中的每个用户在其主目录中都有一个.bash_profile文件,Bash每次启动时都将读取该文件,其中包含的所有命令都将被执行。
下面便是默认.bash_profile文件的代码:
#.bash_profile
#Get the aliases and functions
if [-f ~/.bashrc ];then
.~/.bashrc
fi
#User specific environment and startup programs
PATH=$PATH:$HOME/bin
ENV=$HOME/.bashrc
USERNAME=””
Export USERNAME ENV PATH
屏幕文本编辑器Vi
本章介绍Linux上最常用的文本编辑器Vi。文本编辑器是所有计算机系统中最常使用的一种工具。用户在使用计算机的时候,往往需要建立自己的文件,无论是一般的文本文件、数据文件,还是编写的源程序文件,这些工作都离不开编辑器。
Linux系统提供了一个完整的编辑器家族系列,如Ed、Ex、Vi和Emacs等,按功能它们可以分为两大类:行编辑器(Ed、Ex)和全屏幕编辑器(Vi、Emacs)。行编辑器每次只能对一行进行操作,使用起来很不方便。而全屏幕编辑器可以对整个屏幕进行编辑,用户编辑的文件直接显示在屏幕上,修改的结果可以立即看出来,克服了行编辑的那种不直观的操作方式,便于用户学习和使用,具有强大的功能。
Vi是Linux系统的第一个全屏幕交互式编辑程序,它从诞生至今一直得到广大用户的青睐,历经数十年仍然是人们主要使用的文本编辑工具,足见其生命力之强,而强大的生命力是其强大的功能带来的。
本章中,我们将循序渐进地介绍如何使用Vi来建立、编辑、显示以及处理文件。(注:文中的大写字母为[shift]键+相应的小写字母的组合)
Vi简介
Vi是“Visual interface”的简称,它在Linux上的地位就仿佛Edit程序在DOS上一样。它可以执行输出、删除、查找、替换、块操作等众多文本操作,而且用户可以根据自己的需要对其进行定制,这是其他编辑程序所没有的。
Vi不是一个排版程序,它不象Word或WPS那样可以对字体、格式、段落等其他属性进行编排,它只是一个文本编辑程序。
Vi没有菜单,只有命令,且命令繁多。Vi有三种基本工作模式:命令行模式、文本输入模式和末行模式。
命令行模式
任何时候,不管用户处于何种模式,只要按一下键,即可使Vi进入命令行模式;我们在shell环境(提示符为$)下输入启动Vi命令,进入编辑器时,也是处于该模式下。
在该模式下,用户可以输入各种合法的Vi命令,用于管理自己的文档。此时从键盘上输入的任何字符都被当做编辑命令来解释,若输入的字符是合法的Vi命令,则Vi在接受用户命令之后完成相应的动作。但需注意的是,所输入的命令并不在屏幕上显示出来。若输入的字符不是Vi的合法命令,Vi会响铃报警。
文本输入模式
在命令模式下输入插入命令i、附加命令a 、打开命令o、修改命令c、取代命令r或替换命令s都可以进入文本输入模式。在该模式下,用户输入的任何字符都被Vi当做文件内容保存起来,并将其显示在屏幕上。在文本输入过程中,若想回到命令模式下,按键即可。
末行模式
末行模式也称ex转义模式。
Vi和Ex编辑器的功能是相同的,二者主要区别是用户界面。在Vi中,命令通常是单个键,例如i、a、o等;而在Ex中,命令是以按回车键结束的正文行。Vi有一个专门的“转义”命令,可访问很多面向行的Ex命令。在命令模式下,用户按“:”键即可进入末行模式下,此时Vi会在显示窗口的最后一行(通常也是屏幕的最后一行)显示一个“:”作为末行模式的提示符,等待用户输入命令。多数文件管理命令都是在此模式下执行的(如把编辑缓冲区的内容写到文件中等)。末行命令执行完后,Vi自动回到命令模式。例如:
:1,$s / A / a / g
则从文件第一行至文件尾将大写A全部替换成小写a。
若在末行模式下输入命令过程中改变了主意,可按键,或用退格键将输入的命令全部删除之后,再按一下退格键,即可使Vi回到命令模式下。
Vi编辑器的三种工作模式之间的转换如图11-1所示。
如果要从命令模式转换到编辑模式,可以键入命令a或者i;如果需要从文本模式返回,则按Esc键即可。在命令模式下输入“:”即可切换到末行模式,然后输入命令。
第二十五课 Vi的进入与退出 2000年/6月/13日
Vi 的进入
用户登录到系统中之后,系统给出提示符“$”。在提示符后键入Vi和想要编辑(或建立)的文件名,便可进入Vi。
[例1] 键入命令:
$ vi example.c
屏幕显示如下:
~
~
~
~
~
~
~
~
~
~
~
~
~
“ example.c” [New File]
如果只键入Vi,而不带文件名,也可以进入Vi。之后在光标处键入文件内容,退出Vi时,只需在退出命令后输入文件名即可。
进入Vi之后,首先进入的就是命令模式,也就是说等待命令输入而不是文本输入。这时输入的字母都将作为命令来解释。光标停在屏幕第一行首位上(用表示),其余各行行首均有一个“~”符号,表示该行为空行。最后一行也称状态行,显示出当前正在编辑的文件名以及其状态。如本例是[New File],表示example.c是一个新建的文件。如果example.c文件已在系统中存在,那么输入上述命令后,则在屏幕上显示出该文件的内容,并且光标停在第一行的首位,在状态行显示出该文件的文件名、行数和字符数。
[例2] 键入命令:
$ vi example.c
然后键入:
#include
main ( )
{ int k ;
for ( k=0 ; k<3 ; k++) add( );
}
add( )
{ static int x=0;
x++ ;
printf(“x = %d/n”, x);
}
~
~
~
~
“ example.c” [ New File]
注意,在这里我们为了节省篇幅起见,屏幕只显示15行。事实上,初始的显示行数与用户所用终端有关,一般的CRT终端可显示25行。在窗口系统中,显示行数与运行Vi的那个窗口有关。然而我们可以对显示行数进行设置。例如,在能显示25行的CRT终端上,让Vi只显示15行。设置的方法将在本节后面介绍。
当用Vi建立一个新文件时,在进入Vi的命令中也可以不给出文件名,当编辑完文件需要保存数据时,再由用户指定文件名。
进入Vi时,用户不仅可以指定一个待编辑的文件名,而且还有许多附加操作。
如果希望在进入Vi之后,光标处于文件中特定的某行上,可在Vi后加上任选项+n,其中n为指定的行数。
[例3] 键入命令:
$ vi +5 example1.c
后,屏幕显示如下:
#include
main ( )
{ int k ;
for ( k=0 ; k<3 ; k++) add( );
}
add( )
{ static int x=0;
x++ ;
printf(“x = %d/n”, x);
}
~
~
~
~
~
“ example.c” 12 lines, 125 characters
光标将位于文件example1.c中的第5行上。
如果希望在进入Vi之后光标处于文件最末行,则只需把命令中附加项“+”后面的数字n省略掉即可。
在进入Vi时,除了可以指定一个光标起始行号之外,还可以在命令中指定一个模式串,此时在进入Vi后,光标就处于文件中第一个与指定模式串相匹配的那行上。
[例4] 键入命令:
$ vi +/int example1.c
屏幕显示如下:
#include
main ( )
{ int k ;
for ( k=0 ; k<3 ; k++) add( );
}
add( )
{ static int x=0;
x++ ;
printf(“x = %d/n”, x);
}
~
~
~
~
~
“ example.c” 12 lines, 125 characters
光标将位于文件example1.c中的第3行上。
使用Vi可以同时编辑多个文件,只要在进入Vi的命令中写入所要操作的文件即可,还可以使用通配符。
[例5] 键入命令:
$ vi *.cat
就可以编辑所有后缀为cat的文件了。当然,您还可以使用shell中内置的模式匹配来装载文件,这样会更富技巧性。一旦您在命令行中包含了所有的待编辑文件名,就可以在Vi中方便地移来移去。
退出Vi
当编辑完文件,准备退出Vi返回到shell时,可以使用以下几种方法之一。
在命令模式中,连按两次大写字母Z,若当前编辑的文件曾被修改过,则Vi保存该文件后退出,返回到shell;若当前编辑的文件没被修改过,则Vi直接退出, 返回到shell。
在末行模式下,输入命令
:w
Vi保存当前编辑文件,但并不退出,而是继续等待用户输入命令。在使用w命令时,可以再给编辑文件起一个新的文件名。
[例6]
:w newfile
此时Vi将把当前文件的内容保存到指定的newfile中,而原有文件保持不变。若newfile是一个已存在的文件,则Vi在显示窗口的状态行给出提示信息:
File exists (use ! to override)
此时,若用户真的希望用文件的当前内容替换newfile中原有内容,可使用命令
:w! newfile
否则可选择另外的文件名来保存当前文件。
在末行模式下,输入命令
:q
系统退出Vi返回到shell。若在用此命令退出Vi时,编辑文件没有被保存,则Vi在显示窗口的最末行显示如下信息:
No write since last change (use ! to overrides)
提示用户该文件被修改后没有保存,然后Vi并不退出,继续等待用户命令。若用户就是不想保存被修改后的文件而要强行退出Vi时,可使用命令
:q!
Vi放弃所作修改而直接退到shell下。
在末行模式下,输入命令
:wq
Vi将先保存文件,然后退出Vi返回到shell。
在末行模式下,输入命令
:x
该命令的功能同命令模式下的ZZ命令功能相同。
_____________________________________
请弟兄们发帖时要写个好标题,多谢!
签名不支持html和bbcode,请弟兄为了版面的整洁,请更改签名档,谢谢!
请各版版主及初学Linux的弟兄,请在您的签名写上机器的配置,以及您所用的系统(包装版本号,内核),谢谢。
Slackintosh 10.1+kernel-2.6.11.8+xfce-4.2.1.1
=====================================
帮助他人,快乐自己!
北南南北
查看公开信息
发送悄悄话给北南南北
查找北南南北发表的所有帖子
添加 北南南北 到好友列表
北南南北
资 料:管理员
注册日期: Apr 2002
帖子: 23,043
精华: 467
第 2 帖 发帖时间: 02-08-22, 01:20
Vi中的行号
Vi中的许多命令都要用到行号及行数等数值。若编辑的文件较大时,自己去数是非常不方便的。为此Vi提供了给文本加行号的功能。这些行号显示在屏幕的左边,而相应行的内容则显示在行号之后。
使用的命令为:在末行方式下输入命令:
:set number
需要说明的是,这里加的行号只是显示给用户看的,它们并不是文件内容的一部分。
在一个较大的文件中,用户可能需要了解光标当前行是哪一行,在文件中处于什么位置,可在命令模式下用组合键<Ctrl+g>,此时Vi会在显示窗口的最后一行显示出相应信息。该命令可以在任何时候使用。
[例7]
#include <stdio.h>
main ( )
{ int k ;
for ( k=0 ; k<3 ; k++) add( );
}
add( )
{ static int x=0;
x++ ;
printf(“x = %d/n”, x);
}
~
~
~
~
~
“ example.c” [Modified] lines 4 of 10 --40%-- col 11
在末行方式下,我们可以输入命令nu(单词number的缩写)来获得光标当前行的行号与该行内容。
光标移动操作
全屏幕文本编辑器中,光标的移动操作无疑是最经常使用的操作了。用户只有熟练地使用移动光标的这些命令,才能迅速准确地到达所期望的位置处进行编辑。
Vi中的光标移动既可以在命令模式下,也可以在文本输入模式下,但操作的方法不尽相同。
在文本输入模式下,可直接使用键盘上的四个方向键移动光标。
在命令模式下,有很多移动光标的方法。不但可以使用四个方向键来移动光标,还可以用h、j、k、l这四个键代替四个方向键来移动光标,这样可以避免由于不同机器上的不同键盘定义所带来的矛盾,而且使用熟练后可以手不离开字母键盘位置就能完成所有操作,从而提高工作效率。另外还可以用<Spacebar>、<Backspace>、<Ctrl+n>和<ctrl+p>四个键或组合键移动光标。且以上这三种键在实现功能上是等价的。除此之外,还有一些移动光标的命令。下面对它们的工作方式介绍如下:
<Spacebar>、? (均称为右向键)
右向键的作用是将光标向右移动一个位置。若在向右键前先输入一个数字n,那么光标就向右移动n个位置。例如5l表示光标向右移动5个位置。需要注意的是,光标移动不能超过当前行的末尾。若给定的n超过光标当前位置至行尾的字符个数,如果用右向键,光标只能移到行尾;如果用<Spacebar>,光标移到下面一行或几行的适当位置。
h、<Backspace>、? (向左键)
执行一次向左键,光标向左移动一个位置。同向右键一样,也可以在向左键的前面输入一个数字n,那么光标就向左移动n个位置。需要注意的是,如果用左向键,光标左移不能超出该行的开头;如果用<Backspace>,光标移到上面一行或几行的适当位置。
j、<Ctrl+n>、ˉ (向下键)
执行一次向下键光标向下移动一个位置(即一行),但光标所在的列不变。当这些命令前面加上数字n,则光标下移n行。
Vi除了可以用向下键将光标下移外,还可以用<Enter>键和“+”键将光标下移一行或n行(不包括本行在内),但此时光标下移之后将位于该行的第一个字符处。例如:
3j 光标下移3行,且光标所在列的位置不变。
3+或3<Enter> 光标下移3行,且光标位于该行的行首。
k、<Ctrl+p>、- (向上键)
执行一次向上键光标向上移动一个位置(即一行),但光标所在的列不变。同样在这些命令前面加上数字n,则光标上移n行。
若希望光标上移之后,光标位于该行的行首,则可以使用命令“- ”。
L (移至行首)
L 命令是将光标移到当前行的开头,即将光标移至当前行的第一个非空白处(非制表符或非空格符)。
$(移至行尾)
该命令将光标移到当前行的行尾,停在最后一个字符上。若在$命令之前加上一个数字n,则光标下移n-1行并到达行尾。
[行号] G(移至指定行)
该命令将光标移至指定行号所指定的行的行首。这种移动称为绝对定位移动。
[例8]
#include <stdio.h>
main ( )
{ int k ;
for ( k=0 ; k<3 ; k++) add( );
}
add( )
{ static int x=0;
x++ ;
printf(“x = %d/n”, x);
}
~
~
~
~
~
“ example.c” 12 lines, 125 characters
键入命令:6G后,屏幕显示如下:
#include <stdio.h>
main ( )
{ int k ;
for ( k=0 ; k<3 ; k++) add( );
}
add( )
{ static int x=0;
x++ ;
printf(“x = %d/n”, x);
}
~
~
~
~
~
“ example.c” 12 lines, 125 characters
光标移到了第6行的行首。
若省略行号,则光标移至该文件的最后一行的行首,即无论该文件有多少屏,都跳至最后一行。
第二十七课 vi命令 2000年/6月/26日
在屏幕上移动
Vi提供了三个关于光标在全屏幕上移动并且文件本身不发生滚动的命令。它们分别是H、M和L命令。
1. H命令
该命令将光标移至屏幕首行的行首(即左上角),也就是当前屏幕的第一行,而不是整个文件的第一行。利用此命令可以快速将光标移至屏幕顶部。若在H命令之前加上数字n,则将光标移至第n行的行首。
[例9] 屏幕显示如下内容:
#include <stdio.h>
main ( )
{ int k ;
for ( k=0 ; k<3 ; k++) add( ); }
add( )
{ static int x=0;
x++ ;
printf(“x=%d/n”, x);
}
~
~
~
~
~
“ example.c” [ New File]
在命令模式下输入4H命令后,光标移到以for开头的这一行的字母f上。
值得一提的是,使用命令dH将会删除从光标当前所在行至所显示屏幕首行的全部内容。
2. M命令
该命令将光标移至屏幕显示文件的中间行的行首。即如果当前屏幕已经充满,则移动到整个屏幕的中间行;如果并未充满,则移动到文本的那些行的中间行。利用此命令可以快速地将光标从屏幕的任意位置移至屏幕显示文件的中间行的行首。例如,在上面屏幕显示的情况下(不论光标在屏幕的何处),在命令模式下,输入命令M之后,光标都将移到add这一行的字母a上。
同样值得一提的是,使用命令dM将会删除从光标当前所在行至屏幕显示文件的中间行的全部内容。
3. L命令
当文件显示内容超过一屏时,该命令将光标移至屏幕上的最底行的行首;当文件显示内容不足一屏时,该命令将光标移至文件的最后一行的行首。可见,利用此命令可以快速准确地将光标移至屏幕底部或文件的最后一行。若在L命令之前加上数字n,则将光标移至从屏幕底部算起第n行的行首。例如,在上面屏幕显示的情况下(不论光标在屏幕的何处),在命令模式下,输入命令3L之后,光标都将移到x++这一行的字母x上。
同样值得一提的是,使用命令dL将会删除从光标当前行至屏幕底行的全部内容。
按字移动光标
首先介绍一下Vi中“字”的概念。在Vi中“字”有两种含义。一种是广义的字,它可以是两个空格之间的任何内容。
[例10] 在文件example.c 中的第4行:
{int k;
它只有2个字,一个是{int ,另一个是k;
Vi中另一种字是狭义上的字,在此种意义之下,英文单词、标点符号和非字母字符(如!、@、#、$、%、^、&、*、(、)、-、+、{、}、[、]、~、|、/、<、>、/等)均被当成是一个字。因此,上面那一行中就包括{、int、k、;这4个字。
Vi中使用大写命令一般就是指将字作为广义来对待,使用小写命令就是作为狭义对待。
搞清楚Vi中字的含义后,我们就可以介绍按字移动光标的命令了。
Vi 一共提供了三组关于按字移动光标的命令,分别是:
1. w和W命令
将光标右移至下一个字的字首;
[例11] 屏幕上显示如下:
printf(“Hello Mr.Huang!/n”);
现在使用w命令,把光标移到下一个字(狭义)的字首“(”上:
printf(“Hello Mr.Huang!/n”);
下面使用W命令,将把光标移到下一个字(广义)的字首“M”上:
printf(“Hello Mr.Huang!/n”);
2. e和E命令
如果光标起始位置处于字内(即非字尾处),则该命令将把光标移到本字字尾;如果光标起始位置处于字尾,则该命令将把光标移动到下一个字的字尾。
3. b和B
如果光标处于所在字内(即非字首),则该命令将把光标移至本字字首;如果光标处于所在字字首,则该命令将把光标移到上一个字的字首。
[例12] 屏幕显示如下:
printf(“Hello Mr.Huang!/n”);
现在使用b命令,由于光标处于该字中间,所以光标移动到本字字首“H”处:
printf(“Hello Mr.Huang!/n”);
如果使用B命令,则如下所示:
printf(“Hello Mr.Huang!/n”);
按句移动光标
在Vi中,一个句子被定义为是以逗号(,)、句号(.)、问号(?)和感叹号(!)结尾,且其后面跟着至少两个以上(含两个)空格或一个换行符的字符序列。
Vi提供了关于按句移动光标的两个命令,分别为:
1. ( 命令
将光标移至上一个句子的开头。
2. ) 命令
该命令将光标移至下一个句子的开头。
按段移动光标
在Vi中,一个段被定义为是以一个空白行开始和结束的片段。Vi提供了关于按段移动光标的两个命令,分别为:
1. { 命令
该命令将光标向前移至上一个段的开头;
2. } 命令
该命令将光标向后移至下一个段的开头。
屏幕滚动
屏幕命令是以屏幕为单位移动光标的,常用于文件的滚屏和分页。需要注意的是,屏幕命令不是光标移动命令,不能作为文本限定符用于删除命令中。
在命令模式下和文本输入模式下均可以使用屏幕滚动命令。
1. 滚屏命令
关于滚屏命令有两个:
· < Ctrl+u > 将屏幕向前(文件头方向)翻滚半屏;
· < Ctrl+d > 将屏幕向后(文件尾方向)翻滚半屏。
可以在这两个命令之前加上一个数字n,则屏幕向前或向后翻滚n行。并且这个值被系统记住,以后再用< Ctrl+u >和< Ctrl+d >命令滚屏时,还滚相应的行数。
2. 分页命令
关于分页命令也有两个:
· < Ctrl+f > 将屏幕向文件尾方向翻滚一整屏(即一页);
· < Ctrl+b > 将屏幕向文件首方向翻滚一整屏(即一页)。
同样也可以在这两个命令之前加上一个数字n,则屏幕向前或向后移动n页。
3. 状态命令< Ctrl+G >
命令显示在vi状态行上的vi状态信息,包括正在编辑的文件名、是否修改过、当前行号、文件的行数以及光标之前的行占整个文件的百分比。
4. 屏幕调零命令
Vi 提供了三个有关屏幕调零的命令。它们的格式分别为:
· [行号] z [行数] <回车>
· [行号] z [行数] .
· [行号] z [行数] _
若省略了行号和行数,这三个命令分别为将光标所在的当前行作为屏幕的首行、中间行和最末行重新显示;若给出行号,那么该行号所对应的行就作为当前行显示在屏幕的首行、中间行和最末行;若给出行数,则它规定了在屏幕上显示的行数。
[例13]
8z16<回车> :将文件中的第8行作为屏幕显示的首行,并一共显示16行。
15z . :将文件中的第15行作为屏幕显示的中间行,显示行数为整屏。
15z 5_ :将文件中的第15行作为屏幕显示的最末行,显示行数为5行。
文本插入操作
在命令模式下用户输入的任何字符都被Vi当作命令加以解释执行,如果用户要将输入的字符当作是文本内容时,则首先应将Vi的工作模式从命令模式切换到文本输入模式。切换的方式是使用下面的命令。
插入(Insert)命令
Vi提供了两个插入命令:i和 I。
1. i命令
插入文本从光标所在位置前开始,并且插入过程中可以使用<Backspace>键删除错误的输入。此时Vi处于插入状态,屏幕最下行显示“--INSERT--”(插入)字样。
[例14] 有一正在编辑的文件,如下所示:
Welcome to vi world!Come on!
~
~
光标位于第一个“!”上,需在其前面插入:
This is an example!
使用i命令,并输入相应文本后,屏幕显示如下:
Welcome to vi world This is an example!!Come on!
~
~
由此例可以看到,光标本来是在第一个“!”处,但是由于是从光标所在位置前开始插入,所以这个“!”就被挤到了新插入的文本之后。
2. I命令
该命令是将光标移到当前行的行首,然后在其前插入文本。
_____________________________________
请弟兄们发帖时要写个好标题,多谢!
签名不支持html和bbcode,请弟兄为了版面的整洁,请更改签名档,谢谢!
请各版版主及初学Linux的弟兄,请在您的签名写上机器的配置,以及您所用的系统(包装版本号,内核),谢谢。
Slackintosh 10.1+kernel-2.6.11.8+xfce-4.2.1.1
=====================================
帮助他人,快乐自己!
北南南北
查看公开信息
发送悄悄话给北南南北
查找北南南北发表的所有帖子
添加 北南南北 到好友列表
北南南北
资 料:管理员
注册日期: Apr 2002
帖子: 23,043
精华: 467
第 3 帖 发帖时间: 02-08-22, 01:21
vi命令
在屏幕上移动
Vi提供了三个关于光标在全屏幕上移动并且文件本身不发生滚动的命令。它们分别是H、M和L命令。
1. H命令
该命令将光标移至屏幕首行的行首(即左上角),也就是当前屏幕的第一行,而不是整个文件的第一行。利用此命令可以快速将光标移至屏幕顶部。若在H命令之前加上数字n,则将光标移至第n行的行首。
[例9] 屏幕显示如下内容:
#include <stdio.h>
main ( )
{ int k ;
for ( k=0 ; k<3 ; k++) add( ); }
add( )
{ static int x=0;
x++ ;
printf(“x=%d/n”, x);
}
~
~
~
~
~
“ example.c” [ New File]
在命令模式下输入4H命令后,光标移到以for开头的这一行的字母f上。
值得一提的是,使用命令dH将会删除从光标当前所在行至所显示屏幕首行的全部内容。
2. M命令
该命令将光标移至屏幕显示文件的中间行的行首。即如果当前屏幕已经充满,则移动到整个屏幕的中间行;如果并未充满,则移动到文本的那些行的中间行。利用此命令可以快速地将光标从屏幕的任意位置移至屏幕显示文件的中间行的行首。例如,在上面屏幕显示的情况下(不论光标在屏幕的何处),在命令模式下,输入命令M之后,光标都将移到add这一行的字母a上。
同样值得一提的是,使用命令dM将会删除从光标当前所在行至屏幕显示文件的中间行的全部内容。
3. L命令
当文件显示内容超过一屏时,该命令将光标移至屏幕上的最底行的行首;当文件显示内容不足一屏时,该命令将光标移至文件的最后一行的行首。可见,利用此命令可以快速准确地将光标移至屏幕底部或文件的最后一行。若在L命令之前加上数字n,则将光标移至从屏幕底部算起第n行的行首。例如,在上面屏幕显示的情况下(不论光标在屏幕的何处),在命令模式下,输入命令3L之后,光标都将移到x++这一行的字母x上。
同样值得一提的是,使用命令dL将会删除从光标当前行至屏幕底行的全部内容。
按字移动光标
首先介绍一下Vi中“字”的概念。在Vi中“字”有两种含义。一种是广义的字,它可以是两个空格之间的任何内容。
[例10] 在文件example.c 中的第4行:
{int k;
它只有2个字,一个是{int ,另一个是k;
Vi中另一种字是狭义上的字,在此种意义之下,英文单词、标点符号和非字母字符(如!、@、#、$、%、^、&、*、(、)、-、+、{、}、[、]、~、|、/、<、>、/等)均被当成是一个字。因此,上面那一行中就包括{、int、k、;这4个字。
Vi中使用大写命令一般就是指将字作为广义来对待,使用小写命令就是作为狭义对待。
搞清楚Vi中字的含义后,我们就可以介绍按字移动光标的命令了。
Vi 一共提供了三组关于按字移动光标的命令,分别是:
1. w和W命令
将光标右移至下一个字的字首;
[例11] 屏幕上显示如下:
printf(“Hello Mr.Huang!/n”);
现在使用w命令,把光标移到下一个字(狭义)的字首“(”上:
printf(“Hello Mr.Huang!/n”);
下面使用W命令,将把光标移到下一个字(广义)的字首“M”上:
printf(“Hello Mr.Huang!/n”);
2. e和E命令
如果光标起始位置处于字内(即非字尾处),则该命令将把光标移到本字字尾;如果光标起始位置处于字尾,则该命令将把光标移动到下一个字的字尾。
3. b和B
如果光标处于所在字内(即非字首),则该命令将把光标移至本字字首;如果光标处于所在字字首,则该命令将把光标移到上一个字的字首。
[例12] 屏幕显示如下:
printf(“Hello Mr.Huang!/n”);
现在使用b命令,由于光标处于该字中间,所以光标移动到本字字首“H”处:
printf(“Hello Mr.Huang!/n”);
如果使用B命令,则如下所示:
printf(“Hello Mr.Huang!/n”);
按句移动光标
在Vi中,一个句子被定义为是以逗号(,)、句号(.)、问号(?)和感叹号(!)结尾,且其后面跟着至少两个以上(含两个)空格或一个换行符的字符序列。
Vi提供了关于按句移动光标的两个命令,分别为:
1. ( 命令
将光标移至上一个句子的开头。
2. ) 命令
该命令将光标移至下一个句子的开头。
按段移动光标
在Vi中,一个段被定义为是以一个空白行开始和结束的片段。Vi提供了关于按段移动光标的两个命令,分别为:
1. { 命令
该命令将光标向前移至上一个段的开头;
2. } 命令
该命令将光标向后移至下一个段的开头。
屏幕滚动
屏幕命令是以屏幕为单位移动光标的,常用于文件的滚屏和分页。需要注意的是,屏幕命令不是光标移动命令,不能作为文本限定符用于删除命令中。
在命令模式下和文本输入模式下均可以使用屏幕滚动命令。
1. 滚屏命令
关于滚屏命令有两个:
· < Ctrl+u > 将屏幕向前(文件头方向)翻滚半屏;
· < Ctrl+d > 将屏幕向后(文件尾方向)翻滚半屏。
可以在这两个命令之前加上一个数字n,则屏幕向前或向后翻滚n行。并且这个值被系统记住,以后再用< Ctrl+u >和< Ctrl+d >命令滚屏时,还滚相应的行数。
2. 分页命令
关于分页命令也有两个:
· < Ctrl+f > 将屏幕向文件尾方向翻滚一整屏(即一页);
· < Ctrl+b > 将屏幕向文件首方向翻滚一整屏(即一页)。
同样也可以在这两个命令之前加上一个数字n,则屏幕向前或向后移动n页。
3. 状态命令< Ctrl+G >
命令显示在vi状态行上的vi状态信息,包括正在编辑的文件名、是否修改过、当前行号、文件的行数以及光标之前的行占整个文件的百分比。
4. 屏幕调零命令
Vi 提供了三个有关屏幕调零的命令。它们的格式分别为:
· [行号] z [行数] <回车>
· [行号] z [行数] .
· [行号] z [行数] _
若省略了行号和行数,这三个命令分别为将光标所在的当前行作为屏幕的首行、中间行和最末行重新显示;若给出行号,那么该行号所对应的行就作为当前行显示在屏幕的首行、中间行和最末行;若给出行数,则它规定了在屏幕上显示的行数。
[例13]
8z16<回车> :将文件中的第8行作为屏幕显示的首行,并一共显示16行。
15z . :将文件中的第15行作为屏幕显示的中间行,显示行数为整屏。
15z 5_ :将文件中的第15行作为屏幕显示的最末行,显示行数为5行。
文本插入操作
在命令模式下用户输入的任何字符都被Vi当作命令加以解释执行,如果用户要将输入的字符当作是文本内容时,则首先应将Vi的工作模式从命令模式切换到文本输入模式。切换的方式是使用下面的命令。
插入(Insert)命令
Vi提供了两个插入命令:i和 I。
1. i命令
插入文本从光标所在位置前开始,并且插入过程中可以使用<Backspace>键删除错误的输入。此时Vi处于插入状态,屏幕最下行显示“--INSERT--”(插入)字样。
[例14] 有一正在编辑的文件,如下所示:
Welcome to vi world!Come on!
~
~
光标位于第一个“!”上,需在其前面插入:
This is an example!
使用i命令,并输入相应文本后,屏幕显示如下:
Welcome to vi world This is an example!!Come on!
~
~
由此例可以看到,光标本来是在第一个“!”处,但是由于是从光标所在位置前开始插入,所以这个“!”就被挤到了新插入的文本之后。
2. I命令
该命令是将光标移到当前行的行首,然后在其前插入文本。
}
第二十九课 vi命令 2000年/7月/10日
附加(append)命令
Vi提供了两个附加插入命令:a和A。
1. a命令
该命令用于在光标当前所在位置之后追加新文本。新输入的文本放在光标之后,在光标后的原文本将相应地向后移动。光标可在一行的任何位置。
[例15] 以例14原始情况为例,使用a命令,并输入相应文本,屏幕显示如下:
Welcome to vi world!This is an example!Come on!
~
~
本例中光标后的文本“Come on!”被新输入的文本挤到了后面。
2. A命令
该命令与a命令不同的是,A命令将把光标挪到所在行的行尾,从那里开始插入新文本。当输入A命令后,光标自动移到该行的行尾。
a和A命令是把文本插入到行尾的唯一方法。
打开(open)命令
不论是Insert命令也好,还是append命令也好,所插入的内容都是从当前行中的某个位置开始的。若我们希望在某行之前或某行之后插入一些新行,则应使用open命令。
Vi提供了两个打开命令:o和O。
1. o命令
该命令将在光标所在行的下面新开一行,并将光标置于该行的行首,等待输入文本。要注意,当使用<Backspace>删除字符时只能删除从插入模式开始的位置以后的字符,对于以前的字符不起作用。而且还可以在文本输入方式下输入一些控制字符,例如,Ctrl+l即是插入分页符,显示为^L。
[例16] 以例14的原始情况为例,只是这次要在当前行下面一行输入文本。使用o命令,并输入相应文本,屏幕显示如下:
Welcome to vi world!Come on!
This is an example!
~
~
新输入的文本出现在原来文本所在行的下一行。
2. O命令
和o命令相反,O命令是在光标所在行的上面插入一行,并将光标置于该行的行首,等待输入文本。
[例17] 与例14的原始情况相同,要在当前行的上面一行输入文本。使用O命令并输入文本后,屏幕显示如下:
This is an example!
Welcome to vi world!Come on!
~
~
文本插入到了当前行之上。
11.3.4 文本修改
在命令模式下可以使用Vi提供的各种有关命令对文本进行修改,包括对文本内容的删除、复制、取代和替换等。
文本删除
在编辑文本时,经常需要删除一些不需要的文本,我们可以用<Backspace>键将输错或不需要的文本删除,但此时有一个限制就是当删到行头之后,再想删上面那行的内容是不可能的。
在命令模式下,Vi提供了许多删除命令。这些命令大多是以d开头的。常用的有:
1. 删除单个字符
x: 删除光标处的字符。若在x之前加上一个数字n,则删除从光标所在位置开始向右的n个字符。
X:删除光标前面的那个字符。若在X之前加上一个数字n,则删除从光标前面那个字符开始向左的n个字符。
显然这两个命令是删除少量字符的快捷方法。
2. 删除多个字符
dd:删除光标所在的整行。在dd前可加上一个数字n,表示删除当前行及其后n-1行的内容。
D或d$:两命令功能一样,都是删除从光标所在处开始到行尾的内容。
d0:删除从光标前一个字符开始到行首的内容。
dw:删除一个单词。若光标处在某个词的中间,则从光标所在位置开始删至词尾。同dd命令一样,可在dw之前加一个数字n,表示删除n个指定的单词。
如果用户不小心进行了误删除操作,也不要紧,Vi提供了恢复误操作的命令,并且可以将恢复的内容移动,放在文本的任何地方。恢复命令用2 np,其中n为寄存器号。这是因为Vi内部有9个用于维护删除操作的寄存器,分别用数字1,2,? ,9表示,它们分别保存以往用dd命令删除的内容。这些寄存器组成一个队列,例如最近一次使用dd命令删除的内容被放到寄存器1中;当下次再使用dd命令删除文本内容时,Vi将把寄存器1的内容转存到寄存器2中,而寄存器1中又将是最近一次dd命令删除的内容。以此类推,Vi可以保存有最近九次用dd命令删除的内容,而前面的用dd命令删除的内容则被抛弃。
[例18] 假设当前编辑文件为xu.c
/* this is a example */
#include <stdio.h>
void main( )
{
int i , j ;
printf( “ please input a number : / n ” );
scanf ( “ % d ” , &i ) ;
j = i + 100 ;
printf ( “ /n j = % d /n ” , j ) ;
return ;
}
我们对其进行如下操作:
1. 将光标移至文件第一行,按dd命令,此时文件第一行的内容被删除,且被删除的内容保存在寄存器1中;
2. 按5j使光标下移至第一个printf语句行;
3. 按dd命令将该行删除,此时寄存器1中将保存刚刚被删除的内容:
printf (“ please input a number :/ n ” );
而寄存器1原有的内容:
/* this is a example */
则被保存到寄存器2中;
在最末行模式下,也可以对文件内容进行删除,但它只能删除整行,一次可将某个指定范围内(起始行号,终止行号)的所有行全部删除。需要注意的是,用此种方法进行删除时,Vi并不把所删内容放入寄存器中,因而当发生误删除操作时,不能用2 np命令恢复,只能用u命令进行有限的恢复。
最后提一下,如何在文本输入方式时将所输入文本删除。用户使用<Ctrl+u>组合键即可,此时光标将返回插入开始的位置,并且Vi仍处于文本输入方式。
取消上一命令(Undo)
取消上一命令(Undo),也称复原命令,是非常有用的命令,它可以取消前一次的误操作或不合适的操作对文件造成的影响,使之回复到这种误操作或不合适操作被执行之前的状态。
取消上一命令有两种形式,在命令模式下键入字符u和U。它们的功能都是取消刚才输入的命令,恢复到原来的情况。小写u和大写U在具体细节上有所不同,二者的区别在于,大写U命令的功能是恢复到误操作命令前的情况,即如果插入命令后使用U命令,就删除刚刚插入的内容;如果删除命令后使用U命令,就相当于在光标处又插入刚刚删除的内容。这里把所有修改文本的命令都视为插入命令。也就是说,U命令只能取消前一步操作,如果用U命令撤消了前一步操作,当再按U键时,并不是撤消再前一步的操作,而是撤消了刚才U命令执行的操作,也就是又恢复到第一次使用U命令之前的状态,结果是什么都没做。而小写u命令的功能是把当前行恢复成被编辑前的状态,而不管此行被编辑了多少次。
[例19] 原来屏幕显示内容为:
#include <stdio.h>
main ( )
{
}
在命令模式下输入命令o,插入一新行,输入需要插入的内容后再按<Esc>回到命令模式,屏幕显示内容为:
#include <stdio.h>
main ( )
{
printf ( “ How do you do ! ” ) ;
}
若想取消这一插入操作,请按命令U后,屏幕恢复到原来显示的情况。
注意:对于取消命令仍可以再使用取消命令。这时会产生一种“负负得正”的效果,文件状态将恢复到第一次执行取消命令之前的状态,如同没做任何操作一般。例如在上例中,再使用一次命令U,屏幕将显示的内容仍为插入后的内容。
重复命令(Redo)
重复命令也是一个非常常用的命令。在文本编辑中经常会碰到需要机械地重复一些操作,这时就需要用到重复命令。它可以让用户方便地再执行一次前面刚完成的某个复杂的命令。
重复命令只能在命令模式下工作,在该模式下按“.”键既可。执行一个重复命令时,其结果是依赖于光标当前位置的。
[例20] 屏幕显示内容为:
#include <stdio.h>
main ( )
{
}
输入命令o,并输入一行内容后,再< Esc >返回到命令模式下,屏幕显示内容为:
#include <stdio.h>
main ( )
{
printf ( “ How do you do ! ” ) ;
}
此时输入命令“.”,屏幕显示内容为:
#include <stdio.h>
main ( )
{
printf ( “ How do you do ! ” ) ;
printf ( “ How do you do ! ” ) ;