shell的使用
shell是对用户提出的运行程序的请求进行解释的程序。对大多数UNIX用户而言,shell是系统中最重要的程序。除了使用文本编辑器以外,用户大部分时间都在shell中工作。一旦学会使用shell,就可以不必求助于传统语言编程,而解决很多复杂的问题。
当系统出现提示符$,你可键入命令并得到执行,此时并不是内核在与你对话,而是与一个称为命令解释器或外壳shell的对话。它有三个主要优点:
- 文件名简写
- 输入输出重定向
- 环境个性化
文件名简写
假如一本书中的每章拆分成节,建成如下文件: ch1.1 ch1.2 ch1.3 … 如果打印整本书,那么该怎么办呢?可以执行
$ pr ch1.1 ch1.2 ch1.3 ...
但这样很快就使人厌烦,而且容易出现错误。这就是要使用文件名简写的原因。如果键入:
$ pr ch*
shell认为*的含义是“任何字符串”,所以ch*是一个匹配当前目录中得所有以ch开头的文件的一个模式。关键之处在于,文件名简写并不是pr命令的特性,而是shell的一项服务。所以你可以用它为任何命令生成文件名序列。
*不是shell提供的唯一匹配模式,尽管它被频繁的使用。模式[…]匹配括号内的任何字符。
$ pr ch [12346789] * # 打印1、2、3、4、6、7、8、9章,但没有第5章
$ pr ch [1-46-9] # 同上
?模式匹配任何单个字符:
$ ls ? # 列出单个字符的文件
$ ls ch?.1 # 列出ch1.1、ch2.1、ch3.1等等,但没有ch10.1
注意模式只匹配已存在的文件。不能用模式建立新文件。
模式字符如*之类既可用于单个文件名也用于路径名。
$ usr/mary/* # 匹配mary目录下所有文件
如果想让模式字符作为普通字符使用,可以再特殊字符前加上一个反斜杠:
$ ls \?
I/O重定向
命令多数可在终端上产生输出,如编辑器,也从终端上取其输入。而终端可以被一个文件所替代供输入或输出,举例来说,
$ ls
在你的终端上列出文件名。但是如果
$ ls > filelist
那么同样的文件名清单会放在filelist文件中,符号>含义为“把输出写到如下文件中,而不是在终端上”。
另一个例子是通过把cat的输出都写进一个文件的途径,可以把若干个文件组合成一个文件:
$ cat f1 f2 f3 > temp
符号»的操作与>类似,但它的含义是“添加在某文件的尾部”。也就是说,
$ cat f1 f2 f3 >> temp
把f1,f2,以及f3的文件内容复制到temp文件原有文件的结尾之后,而不是重写原有的内容。
相似的,<的含义是程序从文件中取输入,而不是从终端上取。这样,就可以在文件let中准备一封信函,然后用下列方法发送给若干人
$ mail mary joe tom bob < let
管道
上一节中所有例子都依赖于相同的技巧:把一个程序的输出,通过一个临时文件送到另一个文件的输入,而该临时文件并没有其他的作用。实际上,使用这样的一个文件是很笨拙的。这导致了UNIX系统基础性的贡献之一——管道的想法。管道是不使用临时文件而把一个程序的输出直接连接到另一个程序的输入的途径,管道线是通过管道对两个或两个以上的程序的连接。
$ who | sort # 打印已排序的用户名单
$ who | wc -l # 统计用户数
$ ls | wc -l # 统计文件
$ ls | pr -3 # 3列式文件名列表
$ who | grep mary # 寻找特定用户
任何从终端读取的程序都可改写由管道读取,任何写到终端上的程序都可以改为写向管道。
在管道线中可以有任意多个程序:
$ who | grep mary | wc -l
此行命令统计Mary登录的次数。 管道线上的程序实际上是同时运行,而不是一个接一个地运行,这意味着管道线中得程序是交互式的,内核对调度和同步进行处理,以使它们全部运行。
进程
让我们来看看同时运行多个程序的情况,例如,可以在一个命令行中运行用分号分隔的两个命令,shell会识别分号病把命令分成两个命令:
$ date; who
在shell返回提示符之前,两个命令都执行了(顺序地). 也可以同时运行多个程序,例如,需要做一些费时的工作,如计算书本中的字数,但在进行其他工作之前不想等待wc完成工作。那么可以这样做:
$ wc ch* >wc .out &
6944 # 进程标识符
$
命令行结尾的&字符通知shell“开始该命令的运行,然后立即从终端取下一个命令”,也就是说,不等该命令完成,就取下一个命令。
如果管道线被&初始化了,那么其中的进程都会立即开始——$适用于整个管道线,然而只打印一个进程标识符,它对应于最后一个进程。
可以用shell打印的进程标识符来停止被&初始化的进程:
$ kill 6944
如果忘记了进程标识符,可以用命令ps显示正在运行的一切内容。如果着急的话,kill 0会终止除了所登录的shell之外的全部进程。如果想知道别的用户在干什么,ps -a会展示当前运行的所有进程。
有时一个进程花费的时间是如此之长,以至于可以在这个进程运行时,关闭终端然后回家,而不是等待它完成。但是在关闭终端或断开连接时,即使使用了&,进程通常也会被终止,命令nohup(no hangup)用来处理这种情形。如果执行如下操作
$ nohup 命令 &
那么在用户退出登录后,命令仍继续运行。命令产生的任何输出会保存在名为nohup.out的文件之中。
如果进程耗费大量的处理器资源,比较合适的是赋予该进程低于正常的优先级,这可以通过另一个名为nice的程序来完成:
$ nice 耗费大的命令 &
nohup自动调用nice,用户一旦退出了登录,便可以以较长的时间来执行该命令。
最后,可以直接通知系统,在一清早别人还在睡觉没有进行计算的时候,启动用户的进程,该命令名为at(1):
$ at 时间
你打算运行的命令
ctl-d
$
以下是一种典型的使用方法,命令当然可以来自文件:
$ at 3am < file
时间time可以是24小时制,如2130;或12小时制如930pm
命令行结构
最简单的命令就是一个字(word),通常是一个可执行的文件名。
mbp:blog zhoukuo$ who
zhoukuo console Aug 23 21:25
zhoukuo ttys000 Aug 23 21:25
一条命令通常以换行结束,但有时分号;也可用作命令结束符:
mbp:blog zhoukuo$ date; who
2016年 8月23日 星期二 22时34分26秒 CST
zhoukuo console Aug 23 21:25
zhoukuo ttys000 Aug 23 21:25
可以将date;who的输出送到一个管道:
mbp:blog zhoukuo$ (date;who)|wc
3 15 112
date和who的输出被串连成单个数据流,送入一个管道。