Top

D3:学习Shell之三

目录

使用命令

本章介绍的命令包括:

命令到底是什么?

命令可以是以下四种不同的东西:
  1. 一个可执行程序
  2. 就像我们在/usr/bin中看到的所有文件一样。
    在这一类中,程序可以是编译的二进制文件,例如用C或C++编写的程序,或者用脚本语言编写的程序,例如shell、Perl、Python、Ruby等。
  3. 一个内置于shell本身的命令
  4. bash支持许多内部称为shell builtins的命令。例如cd命令是一个shell内置命令。
    使用builtins命令可以查看所有内置命令。
  5. 一个shell函数
  6. shell函数是集成到environment中的微型shell脚本。
  7. 一个别名
  8. 可以用别名定义自己的命令。

识别命令

Linux提供了两种方法来确定命令属于以上四种中的哪一种。

type——显示命令的类型

type命令是一个shell内置命令,显示shell将执行的命令所属的类型。使用格式为:
type command
例如:
[me@linuxbox ~]$ type type
type is a shell builtin
[me@linuxbox ~]$ type ls
ls is aliased to 'ls --color=tty'
[me@linuxbox ~]$ type cp
cp is /bin/cp

which——显示可执行文件的位置

有时,系统上安装的可执行程序有多个版本。使用which命令可以确定可执行文件的确切位置。
[me@linuxbox ~]$ which ls
/bin/ls
which只适用于可执行程序,不能识别内置程序或别名。(这一点似乎跟FreeBSD不同,FreeBSD下which命令可以识别到内置命令、别名

获取命令的文档

help——获取shell内建帮助

bash有一个内置的帮助工具,可用于每个shell内置程序。
要使用它,键入“help”,后面跟shell内置程序的名称。下面是个例子:
[me@linuxbox ~]$ help cd
cd: cd [-L|[-P [-e]] [-@]] [dir]
  Change the shell working directory.
  
  Change the current directory to DIR. The default DIR is the
  value of the HOME shell variable.
  
  The variable CDPATH defines the search path for the directory
  containing DIR. Alternative directory names in CDPATH are
  separated by a colon (:). A null directory name is the same as
  the current directory. If DIR begins with a slash (/), then
  CDPATH is not used.
  
  If the directory is not found, and the shell option `cdable_vars'
  is set, the word is assumed to be a variable name. If that
  variable has a value, its value is used for DIR.
  
  Options:
   -L force symbolic links to be followed: resolve symbolic
      links in DIR after processing instances of `..'
   -P use the physical directory structure without following
      symbolic links: resolve symbolic links in DIR before
      processing instances of `..'
   -e if the -P option is supplied, and the current working
      directory cannot be determined successfully, exit with
      a non-zero status
   -@ on systems that support it, present a file with extended
      attributes as a directory containing the file attributes
      
   The default is to follow symbolic links, as if `-L' were
  specified. `..' is processed by removing the immediately previous
  pathname component back to a slash or the beginning of DIR.
  
  Exit Status:
  Returns 0 if the directory is changed, and if $PWD is set
  successfully when -P is used; non-zero otherwise.	

--help——显示使用信息

许多可执行程序支持“--help”选项,该选项显示命令支持的语法和选项的描述。比如:
[me@linuxbox ~]$ mkdir --help
Usage: mkdir [OPTION] DIRECTORY...
Create the DIRECTORY(ies), if they do not already exist.

  -Z, --context=CONTEXT (SELinux) set security context to CONTEXT
Mandatory arguments to long options are mandatory for short options
too.
  -m, --mode=MODE   set file mode (as in chmod), not a=rwx – umask
  -p, --parents     no error if existing, make parent directories as
                    needed
  -v, --verbose     print a message for each created directory
      --help        display this help and exit
      --version     output version information and exit
Report bugs to .	
有些程序并不支持“--help”选项,不管它,先试试再说。通常它会反馈一个错误信息,可能里面会有一些有用的信息。

man——显示程序的手册页

大多数用于命令行的可执行程序都会提供一份正式的文档,称为手册或手册页,使用man命令可以查看它们:
man program
手册页的格式有所不同,但通常包含以下内容: 手册页通常不包含示例,只作为参考,而不是教程。
多数Linux系统中,man使用less显示手册页,所以less的所有命令都可以用在显示的手册页上。

man显示的手册分为几个部分,不仅包括用户命令,还包括系统管理命令、编程接口、文件格式等。如下表所示:
章节 内容
1 用户命令
2 内核系统调用的编程接口
3 C库的编程接口
4 设备节点和驱动程序等特殊文件
5 文件格式
6 游戏和娱乐,如屏幕保护程序
7 混杂的
8 系统管理命令
有时候我们需要参考手册的特定部分,以找到实际需要的内容。如果不指定章节号,系统会匹配第一个实例,可能是在第一节中。使用以下格式指定章节号:
man section search_term
实例:
[me@linuxbox ~]$ man 5 passwd
以上将显示描述/etc/passwd文件格式的手册页。

apropos——显示相关命令

可以根据搜索词在手册页列表中搜索可能的匹配项。这很粗糙,但有时很有用。
输出结果中第一个字段是手册页的名称,然后括号里是章节号,最后是简要说明。

man -k search_termapropos search_term功能相同。

whatis——显示单行手册页说明

whatis程序显示与指定关键字匹配的手册页的名称和单行说明:
[me@linuxbox ~]$ whatis ls
ls (1) - list directory contents
FreeBSD中输出结果有差异

info——显示命令的信息

FreeBSD中、debian没有此命令

系统上安装的很多软件包的文档文件位于/usr/share/doc目录中。
其中大部分是以纯文本格式存储,可以用less命令查看。
有一些文件是HTML格式的,可以通过web浏览器查看。
还有一些是以.gz扩展名结尾的文件,这些是被gzip压缩过的,gzip包包含一个特殊版本的zless命令,它可以显示gzip压缩文件的内容。

使用alias创建自己的命令

使用分号分隔,可以在一行中放置多个命令:
[me@linuxbox ~]$ cd /usr; ls;cd -
bin games include lib local sbin share src
/home/me
[me@linuxbox ~]$

使用以下命令创建一个别名:
[me@linuxbox ~]$ alias foo='cd /usr; ls; cd-'
注意,alias命令的格式是:
alias name='string'
以上在debian上测试成功,但在FreeBSD上无效。
FreeBSD中用户默认的shell是tcsh,切换成sh就可以了。而tcsh的alias是在.cshrc中设置的。

同样,使用type foo命令查看它:
[me@linuxbox ~]$ type foo
foo is aliased to 'cd /usr; ls; cd -'
要取消别名,可以使用unalias命令:
[me@linuxbox ~]$ unalias foo
[me@linuxbox ~]$ type foo
bash: type: foo: not found
在命令行定义的别名,当shell会话结束后将失效。永久别名需要在环境变量中设置。

重定向

I/O重定向可以将命令的输入和输出重定向到文件,也可以将多个命令连接到强大的命令管道中。
本章介绍的命令有:

标准输入、输出和错误

大多数程序都会产生某种输出,这些输出通常包括: 与Unix主题“一切都是文件”保持一致,像ls这样的程序实际上将其结果发送到一个名为标准输出(standard output,stdout)的特殊文件,并将其状态消息发送到另一个名为标准错误(standard error,stderr)的特殊文件。
默认情况下,标准输出和标准错误都链接到屏幕,而不是保存到磁盘文件中。
此外,许多程序从名为标准输入(standard input,stdin)的设备获取输入,默认情况下,此设备连接到键盘。
I/O重定向允许我们改变输出的位置和输入的来源。

重定向标准输出

使用>符号对I/O输出重定向。例如:
[me@linuxbox ~]$ ls -l /usr/bin > ls-output.txt
将把运行结果发送到ls-output.txt文件中。
在FreeBSD中,如果在alias中定义了ls的颜色,输出结果中有颜色的项目会变得不可识别。而文件的类型也会变成ASCII text, with escape sequences。 如果前面命令执行出错,则重定向输出的文件为空。也就是说,ls命令不会把它的错误信息发送到标准输出中,而是发送到标准错误中。由于我们只是重定向了标准输出,而没有重定向标准错误,所以错误信息依然会显示在屏幕上。

使用>>符号可以向文件中追加内容,而不是覆盖掉原有的内容。

重定向标准错误

在Linux中,前三个文件流称为标准输入、标准输出、标准错误,在shell中将它们分别作为文件描述符0、1、2来引用,所以,可以用以下方式重定向标准错误:
[me@linuxbox ~]$ ls -l /bin/usr 2> ls-error.txt
但在FreeBSD的tcsh中这种方法无效,需要切换到sh或bash中。

将标准输出和标准错误重定向到一个文件

传统方法:
[me@linuxbox ~]$ ls -l /bin/usr > ls-output.txt 2>&1
这实际上是执行了两个重定向。注意,重定向的顺序非常重要,标准错误的重定向必须始终在标准输出的重定向后发生,否则无法工作。

而最新的bash提供了另一种更精简的方法,用于执行以下组合重定向:
[me@linuxbox ~]$ ls -l /bin/usr &> ls-output.txt
以上命令在tcsh和sh下都不能正确运行,只有bash可以。

处理不需要的输出

有时候“沉默是金”(silence is golden),我们不需要从命令输出,只是想让它运行而已。此时可以将命令的输出重定向到一个空设备:
[me@linuxbox ~]$ ls -l /bin/usr 2> /dev/null

重定向标准输入

cat——连接文件

cat命令读取一个或多个文件,并将其复制到标准输出。多数情况下,我们可以将cat命令相像成DOS下的type命令。我们可以使用它来不分页地显示文件地内容。
例如:
[me@linuxbox ~]$ cat ls-output.txt
cat通常用于显示短文本文件。但也可以接受多个文件作为参数,将它们连接在一起。例如:
cat movie.mpeg.0* > movie.mpeg
通配符总是按排序顺序展开的。

单独使用cat命令而不带任何参数的话,它会等待从标准输入读取数据,并回显。直到按Ctrl-d告诉cat命令:end of file(EOF)。
而使用以下命令将等待键盘输入,并把输入的内容保存到文件中:
[me@linuxbox ~]$ cat > lazy_dog.txt
The quick brown fox jumped over the lazy dog.
使用<重定向操作符,可以将标准输入的源从键盘改为文件,结果与传递单个文件名参数相同。

管道(pipelines)

命令从标准输入读取数据并发送到标准输出的能力,被称为管道的shell功能所利用。使用管道操作符|(垂直条,vertical bar),一个命令的标准输出可以通过管道传递到另一个的命令的标准输入。
例如:
[me@linuxbox ~]$ ls -l /usr/bin | less
这可以使得输出结果分页显示。

>和|的区别:简单来说,重定向运算符将命令与文件连接,而管道运算符将一个命令的输出与第二个命令的输入连接。

过滤器

管道通常用于对数据执行复杂的操作。可以将多个命令放在一个管道中。这种方式使用的命令通常被称为过滤器。
过滤器接收输入,以某种方式进行更改,然后输出。
[me@linuxbox ~]$ ls /bin /usr/bin | sort | less
以上将/bin和/usr/bin中的所有可执行程序组合成一个列表,按顺序排序,并输出结果列表。

uniq——报告或省略重复的行

uniq命令通常与sort命令结合使用。
uniq从标准输入或单个文件名参数接受数据的排序列表,并在默认情况下从列表中删除任何重复项。
因此,为了确保我们的列表没有重复项(即,在/bin和/usr/bin目录中出现的任何同名程序),我们将把uniq添加到我们的管道中:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | less
在本例中,我们使用uniq从sort命令的输出中删除任何重复项。
如果我们想看到重复列表,我们可以在uniq中添加“-d”选项,如下所示:(此处存疑)
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq -d | less

wc——列出每个文件的换行、字和字节计数

wc(word count)命令用于显示文件中包含的行数、字数和字节数。
[me@linuxbox ~]$ wc ls-output.txt
7902 64566 503634 ls-output.txt
与以前的命令一样,如果在没有命令行参数的情况下执行,wc会接收标准输入。
-l选项将其输出限制为仅报告行。
将其添加到管道中使用方便的计数方法。
要查看排序列表中的项目数,可以执行以下操作:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | wc -l
2728

grep——列出与范式匹配的行

grep是一个功能强大的程序,用于查找文件中的文本模式。其用法如下:
grep pattern [file...]
grep在文本中遇到一个pattern时,它会列出包含此范式的行。
例子:
[me@linuxbox ~]$ ls /bin /usr/bin | sort | uniq | grep zip
bunzip2
bzip2
gunzip
gzip
unzip
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit	
grep有几个方便的选项:

head/tail——输出文件头/尾部分

[me@linuxbox ~]$ head -n 5 ls-output.txt
[me@linuxbox ~]$ tail -n 5 ls-output.txt
如果不加-n选项,默认显示十行。
对于tail还有个更常用的选项-f,一直显示,直到按Ctrl-D退出,此功能可用来监控某文件的变化,例如日志。

也可以用在管道中:
[me@linuxbox ~]$ ls /usr/bin | tail -n 5

tee——从stdin读取并输出到stdout和文件

为了与我们的管道隐喻保持一致,Linux提供了一个名为tee的命令,该命令在管道上创建一个“tee”管件。
tee程序读取标准输入并将其复制到标准输出(允许数据沿着管道继续)和一个或多个文件。这对于在处理的中间阶段捕获管道的内容非常有用。
这里我们重复前面的一个例子,这次包括在grep过滤管道内容之前将整个目录列表捕获到ls.txt文件:
[me@linuxbox ~]$ ls /usr/bin | tee ls.txt | grep zip
bunzip2
bzip2
gunzip
gzip
unzip
zip
zipcloak
zipgrep
zipinfo
zipnote
zipsplit