第 3 章 基本的bash shell命令

第 3 章 基本的bash shell命令

本章内容

  • 使用shell

  • bash手册

  • 浏览文件系统

  • 文件和目录列表

  • 管理文件和目录

  • 查看文件内容

大多数Linux发行版的默认shell都是GNU bash shell1。本章将介绍bash shell的一些基本特性,例如bash手册、tab键自动补全以及显示文件内容,带你逐步了解怎样用bash shell提供的基本命令来操作Linux文件和目录。如果你已经熟悉了Linux环境中的这些基本操作,可以直接跳过本章,从第4章开始了解更多的高级命令。

1在6.10之后的大部分Ubuntu版本上,默认的shell是bash。

3.1 启动shell

GNU bash shell能提供对Linux系统的交互式访问。它是作为普通程序运行的,通常是在用户登录终端时启动。登录时系统启动的shell依赖于用户账户的配置。

/etc/passwd文件包含了所有系统用户账户列表以及每个用户的基本配置信息。以下是从/etc/passwd文件中取出的样例条目:

christine:x:501:501:Christine Bresnahan:/home/christine:/bin/bash

每个条目有七个字段,字段之间用冒号分隔。系统使用字段中的数据来赋予用户账户某些特定特性。其中的大多数条目将在第7章有更加详细的介绍。现在先将注意力放在最后一个字段上,该字段指定了用户使用的shell程序。

说明 尽管本书的重点放在了GNU bash shell,但是也会谈及其他一些shell。第23章中讲解了如何使用如dash和tcsh之类的shell。

在前面的/etc/passwd样例条目中,用户christine使用/bin/bash作为自己的默认shell程序。这意味着当christine登录Linux系统后,bash shell会自动启动。

尽管bash shell会在登录时自动启动,但是,是否会出现shell命令行界面(CLI)则依赖于所使用的登录方式。如果采用虚拟控制台终端登录,CLI提示符会自动出现,你可以输入shell命令。但如果是通过图形化桌面环境登录Linux系统,你就需要启动一个图形化终端仿真器来访问shell CLI提示符。

3.2 shell提示符

一旦启动了终端仿真软件包或者登录Linux虚拟控制台,你就会看到shell CLI提示符。提示符就是进入shell世界的大门,是你输入shell命令的地方。

默认bash shell提示符是美元符号($),这个符号表明shell在等待用户输入。不同的Linux发行版采用不同格式的提示符。在Ubuntu Linux系统上,shell提示符看起来是这样的:

christine@server01:~$

在CentOS系统上是这样的:

[christine@server01 ~]$

除了作为shell的入口,提示符还能够提供其他的辅助信息。在上面的两个例子中,提示符中显示了当前用户ID名christine。另外还包括系统名server01。在本章的后续部分,你会学习到更多可以在提示符中显示的内容。

窍门 如果你还是CLI新手,请记住,在输入shell命令之后,需要按回车键才能让shell执行你输入的命令。

shell提示符并非一成不变。你可根据自己的需要改变它。第6章讲到了如何修改shell CLI提示符。

可以把shell CLI提示符想象成一名助手,它帮助你使用Linux系统,给你有益的提示,告诉你什么时候shell可以接受新的命令。shell中另一个大有帮助的东西是bash手册。

3.3 bash手册

大多数Linux发行版自带用以查找shell命令及其他GNU工具信息的在线手册。熟悉手册对使用各种Linux工具大有裨益,尤其是在你要弄清各种命令行参数的时候。

man命令用来访问存储在Linux系统上的手册页面。在想要查找的工具的名称前面输入man命令,就可以找到那个工具相应的手册条目。图3-1展示了查找xterm命令的手册页面的例子。输入命令man xterm就可以进入该页面。

{%}

图 3-1 xterm命令的手册页面

注意图3-1中xterm命令的DESCRIPTION段落。这些段落排列的并不紧密,字里行间全是技术行话。bash手册并不是按部就班的学习指南,而是作为快速参考来使用的。

窍门 如果你是新接触bash shell,可能一开始会觉得手册页并不太有用。但是,如果养成了阅读手册的习惯,尤其是阅读第一段或是DESCRIPTION部分的前两段,最终你会学到各种技术行话,手册页也会变得越来越有用。

当使用man命令查看命令手册页的时候,这些手册页是由分页程序(pager)来显示的。分页程序是一种实用工具,能够逐页显示文本。可以通过点击空格键进行翻页,或是使用回车键逐行查看。另外还可以使用箭头键向前向后滚动手册页的内容(假设你用的终端仿真软件包支持箭头键功能)。

读完了手册页,可以点击q键退出。退出手册页之后,你会重新获得shell CLI提示符,这表示shell正在等待接受下一条命令。

窍门 bash手册甚至包含了一份有关其自身的参考信息。输入man man来查看与手册页相关的手册页。

手册页将与命令相关的信息分成了不同的节。每一节惯用的命名标准如表3-1所示。

表 3-1 Linux手册页惯用的节名

描述

Name

显示命令名和一段简短的描述

Synopsis

命令的语法

Configuration

命令配置信息

Description

命令的一般性描述

Options

命令选项描述

Exit Status

命令的退出状态指示

Return Value

命令的返回值

Errors

命令的错误消息

Environment

描述所使用的环境变量

Files

命令用到的文件

Versions

命令的版本信息

Conforming To

命名所遵从的标准

Notes

其他有帮助的资料

Bugs

提供提交bug的途径

Example

展示命令的用法

Authors

命令开发人员的信息

Copyright

命令源代码的版权状况

See Also

与该命令类似的其他命令

并不是每一个命令的手册页都包含表3-1中列出的所有节。还有一些命令的节名并没有在上面的节名惯用标准中列出。

窍门 如果不记得命令名怎么办?可以使用关键字搜索手册页。语法是:man -k 关键字。例如,要查找与终端相关的命令,可以输入man -k terminal

除了对节按照惯例进行命名,手册页还有对应的内容区域。每个内容区域都分配了一个数字,从1开始,一直到9,如表3-2所示。

表 3-2 Linux手册页的内容区域

区域号

所涵盖的内容

1

可执行程序或shell命令

2

系统调用

3

库调用

4

特殊文件

5

文件格式与约定

6

游戏

7

概览、约定及杂项

8

超级用户和系统管理员命令

9

内核例程

man工具通常提供的是命令所对应的最低编号的内容。例如,在图3-1中,我们输入的是命令man xterm,请注意,在现实内容的左上角和右上角,单词XTERM后的括号中有一个数字:(1)。这表示所显示的手册页来自内容区域1(可执行程序或shell命令)。

一个命令偶尔会在多个内容区域都有对应的手册页。比如说,有个叫作hostname的命令。手册页中既包括该命令的相关信息,也包括对系统主机名的概述。要想查看所需要的页面,可以输入man section# topic。对手册页中的第1部分而言,就是输入man 1 hostname。对于手册页中的第7部分,就是输入man 7 hostname

你也可以只看各部分内容的简介:输入man 1 intro阅读第1部分,输入man 2 intro阅读第2部分,输入man 3 intro阅读第3部分,等等。

手册页不是唯一的参考资料。还有另一种叫作info页面的信息。可以输入info info来了解info页面的相关内容。

另外,大多数命令都可以接受-help--help选项。例如你可以输入hostname -help来查看帮助。关于帮助的更多信息,可以输入help help。(看出这里面的门道没?)

显然有不少有用的资源可供参考。不过,很多基本的shell概念还是需要详细的解释。在下一节中,我们要讲讲如何浏览Linux文件系统。

3.4 浏览文件系统

当登录系统并获得shell命令提示符后,你通常位于自己的主目录中。一般情况下,你会想去逛逛主目录之外的其他地方。本节将告诉你如何使用shell命令来实现这个目标。在开始前,先了解一下Linux文件系统,为下一步作铺垫。

3.4.1 Linux文件系统

如果你刚接触Linux系统,可能就很难弄清楚Linux如何引用文件和目录,对已经习惯Microsoft Windows操作系统方式的人来说更是如此。在继续探索Linux系统之前,先了解一下它的布局是有好处的。

你将注意到的第一个不同点是,Linux在路径名中不使用驱动器盘符。在Windows中,PC上安装的物理驱动器决定了文件的路径名。Windows会为每个物理磁盘驱动器分配一个盘符,每个驱动器都会有自己的目录结构,以便访问存储其中的文件。

举个例子,在Windows中经常看到这样的文件路径:

C:\Users\Rich\Documents\test.doc

这种Windows文件路径表明了文件test.doc究竟位于哪个磁盘分区中。如果你将test.doc保存在闪存上,该闪存由J来标识,那么文件的路径就是J:\test.doc。该路径表明文件位于J盘的根目录下。

Linux则采用了一种不同的方式。Linux将文件存储在单个目录结构中,这个目录被称为虚拟目录(virtual directory)。虚拟目录将安装在PC上的所有存储设备的文件路径纳入单个目录结构中。

Linux虚拟目录结构只包含一个称为(root)目录的基础目录。根目录下的目录和文件会按照访问它们的目录路径一一列出,这点跟Windows类似。

窍门 你将会发现Linux使用正斜线(/)而不是反斜线(\)在文件路径中划分目录。在Linux中,反斜线用来标识转义字符,要是用在文件路径中的话会导致各种各样的问题。如果你之前用的是Windows环境,就需要一点时间来适应。

在Linux中,你会看到下面这种路径:

/home/Rich/Documents/test.doc

这表明文件test.doc位于Documents目录,Documents又位于rich目录中,rich则在home目录中。要注意的是,路径本身并没有提供任何有关文件究竟存放在哪个物理磁盘上的信息。

Linux虚拟目录中比较复杂的部分是它如何协调管理各个存储设备。在Linux PC上安装的第一块硬盘称为根驱动器。根驱动器包含了虚拟目录的核心,其他目录都是从那里开始构建的。

Linux会在根驱动器上创建一些特别的目录,我们称之为挂载点(mount point)。挂载点是虚拟目录中用于分配额外存储设备的目录。虚拟目录会让文件和目录出现在这些挂载点目录中,然而实际上它们却存储在另外一个驱动器中。

通常系统文件会存储在根驱动器中,而用户文件则存储在另一驱动器中,如图3-2所示。

{%}

图 3-2 Linux文件结构

图3-2展示了计算机中的两块硬盘。一块硬盘和虚拟目录的根目录(由正斜线/表示)关联起来。剩下的硬盘就可以挂载到虚拟目录结构中的任何地方。在这个例子中,第二块硬盘被挂载到了/home位置,用户目录都位于这个位置。

Linux文件系统结构是从Unix文件结构演进过来的。在Linux文件系统中,通用的目录名用于表示一些常见的功能。表3-3列出了一些较常见的Linux顶层虚拟目录名及其内容。

表 3-3 常见Linux目录名称

目录

用途

/

虚拟目录的根目录。通常不会在这里存储文件

/bin

二进制目录,存放许多用户级的GNU工具

/boot

启动目录,存放启动文件

/dev

设备目录,Linux在这里创建设备节点

/etc

系统配置文件目录

/home

主目录,Linux在这里创建用户目录

/lib

库目录,存放系统和应用程序的库文件

/media

媒体目录,可移动媒体设备的常用挂载点

/mnt

挂载目录,另一个可移动媒体设备的常用挂载点

/opt

可选目录,常用于存放第三方软件包和数据文件

/proc

进程目录,存放现有硬件及当前进程的相关信息

/root

root用户的主目录

/sbin

系统二进制目录,存放许多GNU管理员级工具

/run

运行目录,存放系统运作时的运行时数据

/srv

服务目录,存放本地服务的相关文件

/sys

系统目录,存放系统硬件信息的相关文件

/tmp

临时目录,可以在该目录中创建和删除临时工作文件

/usr

用户二进制目录,大量用户级的GNU工具和数据文件都存储在这里

/var

可变目录,用以存放经常变化的文件,比如日志文件

常见的目录名均基于文件系统层级标准(filesystem hierarchy standard,FHS)。很多Linux发行版都遵循了FHS。这样一来,你就能够在任何兼容FHS的Linux系统中轻而易举地查找文件。

说明 FHS偶尔会进行更新。你可能会发现有些Linux发行版仍在使用旧的FHS标准,而另外一些则只实现了部分当前标准。要想保持与FHS标准同步,请访问其官方主页:http://www.pathname.com/fhs

在登录系统并获得一个shell CLI提示符后,会话将从主目录开始。主目录是分配给用户账户的一个特有目录。用户账户在创建之后,系统通常会为其分配一个特有的目录(参见第7章)。

可以使用图形界面在虚拟目录中跳转。要想在CLI提示符下切换虚拟目录,需要使用cd命令。

3.4.2 遍历目录

在Linux文件系统上,可以使用切换目录命令cd将shell会话切换到另一个目录。cd命令的格式非常简单:

cd destination

cd命令可接受单个参数destination,用以指定想切换到的目录名。如果没有为cd命令指定目标路径,它将切换到用户主目录。

destination参数可以用两种方式表示:一种是使用绝对文件路径,另一种是使用相对文件路径。

接下来将分别阐述这两种方法。这两者之间的不同对于理解文件系统遍历非常重要。

1. 绝对文件路径

用户可在虚拟目录中采用绝对文件路径引用目录名。绝对文件路径定义了在虚拟目录结构中该目录的确切位置,以虚拟目录的根目录开始,相当于目录的全名。

绝对文件路径总是以正斜线(/)作为起始,指明虚拟文件系统的根目录。因此,如果要指向usr目录所包含的bin目录下的用户二进制文件,可以使用如下绝对文件路径:

/usr/bin

使用绝对文件路径可以清晰表明用户想切换到的确切位置。要用绝对文件路径来切换到文件系统中的某个特定位置,只需在cd命令后指定全路径名:

christine@server01:~$ cd /usr/bin
christine@server01:/usr/bin$

注意,在上面的例子中,提示符中一开始有一个波浪号(~)。在切换到另一个目录之后,这个波浪号被/usr/bin替代了。CLI提示符正是用它来帮助你跟踪当前所在虚拟目录结构中的位置。波浪号表明shell会话位于你的主目录中。在切换出主目录之后,如果提示符已经进行了相关配置的话,绝对文件路径就会显示在提示符中。

说明 如果你的shell CLI提示符中并没有显示shell会话的当前位置,那是因为它并没有进行相关的配置。如果你希望修改CLI提示符的话,第6章会告诉你如何更改配置。

如果没有配置好提示符来显示当前shell会话的绝对文件路径,也可以使用shell命令来显示所处的位置。pwd命令可以显示出shell会话的当前目录,这个目录被称为当前工作目录pwd命令的用法如下:

christine@server01:/usr/bin$ pwd
/usr/bin
christine@server01:/usr/bin$

窍门 在切换到新的当前工作目录时使用pwd命令,是很好的习惯。因为很多shell命令都是在当前工作目录中操作的,在发出命令之前,你应该始终确保自己处在正确的目录之中。

可以使用绝对文件路径切换到Linux虚拟目录结构中的任何一级:

christine@server01:/usr/bin$ cd /var/log
christine@server01:/var/log$
christine@server01:/var/log$ pwd
/var/log
christine@server01:/var/log$

还可以从Linux虚拟目录中的任何一级跳回主目录:

christine@server01:/var/log$ cd
christine@server01:~$
christine@server01:~$ pwd
/home/christine
christine@server01:~$

但是,如果你只是在自己的主目录中工作,经常使用绝对文件路径的话未免太过冗长。例如,若已经位于目录/home/christine,再输入下面这样的命令切换到Documents目录就有些繁琐了:

cd /home/christine/Documents

幸好还有一种简单的解决方法。

2. 相对文件路径

相对文件路径允许用户指定一个基于当前位置的目标文件路径。相对文件路径不以代表根目录的正斜线(/)开头,而是以目录名(如果用户准备切换到当前工作目录下的一个目录)或是一个特殊字符开始。假如你位于home目录中,并希望切换到Documents子目录,那你可以使用cd命令加上一个相对文件路径:

christine@server01:~$ pwd
/home/christine
christine@server01:~$
christine@server01:~$ cd Documents
christine@server01:~/Documents$ pwd
/home/christine/Documents
christine@server01:~/Documents$

上面的例子并没有使用正斜线(/),而是采用了相对文件路径将当前工作目录从/home/christine改为/home/christine/Documents,大大减少了输入内容。

另外,此例中还要注意的是,如果提示符经过配置可以显示出当前工作目录,它就会一直显示波浪号。这表明当前工作目录位于用户home目录之下。

窍门 如果你刚接触命令行和Linux目录结构,建议暂时先坚持使用绝对文件路径。等熟悉了目录布局之后,再使用相对文件路径。

可以在任何包含子目录的目录中使用带有相对文件路径的cd命令。也可以使用一个特殊字符来表示相对目录位置。

有两个特殊字符可用于相对文件路径中:

  • 单点符(.),表示当前目录;

  • 双点符(..),表示当前目录的父目录。

你可以使用单点符,不过对cd命令来说,这没有什么意义。在本章后面你会看到另一个命令如何有效地在相对文件路径中使用单点符。

双点符在目录层级中移动时非常便利。如果你处在在主目录下的Documents目录中,需要切换到主目录下的Downloads目录,可以这么做:

christine@server01:~/Documents$ pwd
/home/christine/Documents
christine@server01:~/Documents$ cd ../Downloads
christine@server01:~/Downloads$ pwd
/home/christine/Downloads
christine@server01:~/Downloads$

双点符先将用户带到上一级目录,也就是用户的主目录,然后/Downloads这部分再将用户带到下一级目录,即Downloads目录。必要时用户也可用多个双点符来向上切换目录。假如现在位于主目录中(/home/christine),想切换到/etc目录,可以输入如下命令:

christine@server01:~$ cd ../../etc
christine@server01:/etc$ pwd
/etc
christine@server01:/etc$

当然,在上面这种情况下,采用相对路径其实比采用绝对路径输入的字符更多,用绝对路径的话,用户只需输入/etc。因此,只在必要的时候才使用相对文件路径。

说明 在shell CLI提示符中加入足够的信息非常方便,本节正是这么做的。不过出于清晰性的考虑,在书中余下的例子里,我们只使用一个简单的$提示符。

既然你已经知道如何遍历文件系统和验证当前工作目录,那就可以开始探索各种目录中究竟都有些什么东西了。下一节将学习如何查看目录中的文件。

3.5 文件和目录列表

要想知道系统中有哪些文件,可以使用列表命令(ls)。本节将描述ls命令和可用来格式化其输出信息的选项。

3.5.1 基本列表功能

ls命令最基本的形式会显示当前目录下的文件和目录:

$ ls
Desktop    Downloads         Music      Pictures  Templates  Videos
Documents  examples.desktop  my_script  Public    test_file
$

注意,ls命令输出的列表是按字母排序的(按列排序而不是按行排序)。如果用户用的是支持彩色的终端仿真器,ls命令还可以用不同的颜色来区分不同类型的文件。LS_COLORS环境变量控制着这个功能。(第6章中会讲到环境变量。)不同的Linux发行版根据各自终端仿真器的能力设置这个环境变量。

如果没安装彩色终端仿真器,可用带-F参数的ls命令轻松区分文件和目录。使用-F参数可以得到如下输出:

$ ls -F
Desktop/   Downloads/       Music/     Pictures/ Templates/ Videos/
Documents/ examples.desktop my_script* Public/   test_file
$

-F参数在目录名后加了正斜线(/),以方便用户在输出中分辨它们。类似地,它会在可执行文件(比如上面的my_script文件)的后面加个星号,以便用户找出可在系统上运行的文件。

基本的ls命令在某种意义上有点容易让人误解。它显示了当前目录下的文件和目录,但并没有将全部都显示出来。Linux经常采用隐藏文件来保存配置信息。在Linux上,隐藏文件通常是文件名以点号开始的文件。这些文件并没有在默认的ls命令输出中显示出来,因此我们称其为隐藏文件。

要把隐藏文件和普通文件及目录一起显示出来,就得用到-a参数。下面是一个带有-a参数的ls命令的例子:

$ ls -a
.              .compiz    examples.desktop  Music      test_file
..             .config    .gconf            my_script  Videos
.bash_history  Desktop    .gstreamer-0.10   Pictures   .Xauthority
.bash_logout   .dmrc      .ICEauthority     .profile   .xsession-errors
.bashrc        Documents  .local            Public     .xsession-errors.old
.cache         Downloads  .mozilla          Templates
$

所有以点号开头的隐藏文件现在都显示出来了。注意,有三个以.bash开始的文件。它们是bash shell环境所使用的隐藏文件,在第6章会对其进行详细的讲解。

-R参数是ls命令可用的另一个参数,叫作递归选项。它列出了当前目录下包含的子目录中的文件。如果目录很多,这个输出就会很长。以下是-R参数输出的简单例子:

$ ls -F -R
.:
Desktop/   Downloads/       Music/     Pictures/ Templates/ Videos/
Documents/ examples.desktop my_script* Public/   test_file

./Desktop:

./Documents:

./Downloads:

./Music:
ILoveLinux.mp3*

./Pictures:

./Public:

./Templates:

./Videos:
$

注意,首先-R参数显示了当前目录下的内容,也就是之前例子中用户home目录下的那些文件。另外,它还显示出了用户home目录下所有子目录及其内容。只有Music子目录中包含了一个可执行文件ILoveLinux.mp3。

窍门 选项并不一定要像例子中那样分开输入:ls -F -R。它们可以进行如下合并:ls -FR

在上一个例子中,子目录中没再包含子目录。如果有更多的子目录,-R参数会继续进行遍历。正如你所看到的,如果目录结构很庞大,输出内容会变得很长。

3.5.2 显示长列表

在基本的输出列表中,ls命令并未输出太多每个文件的相关信息。要显示附加信息,另一个常用的参数是-l-l参数会产生长列表格式的输出,包含了目录中每个文件的更多相关信息。

$ ls -l
total 48
drwxr-xr-x 2 christine christine 4096 Apr 22 20:37 Desktop
drwxr-xr-x 2 christine christine 4096 Apr 22 20:37 Documents
drwxr-xr-x 2 christine christine 4096 Apr 22 20:37 Downloads
-rw-r--r-- 1 christine christine 8980 Apr 22 13:36 examples.desktop
-rw-rw-r-- 1 christine christine    0 May 21 13:44 fall
-rw-rw-r-- 1 christine christine    0 May 21 13:44 fell
-rw-rw-r-- 1 christine christine    0 May 21 13:44 fill
-rw-rw-r-- 1 christine christine    0 May 21 13:44 full
drwxr-xr-x 2 christine christine 4096 May 21 11:39 Music
-rw-rw-r-- 1 christine christine    0 May 21 13:25 my_file
-rw-rw-r-- 1 christine christine    0 May 21 13:25 my_scrapt
-rwxrw-r-- 1 christine christine   54 May 21 11:26 my_script
-rw-rw-r-- 1 christine christine    0 May 21 13:42 new_file
drwxr-xr-x 2 christine christine 4096 Apr 22 20:37 Pictures
drwxr-xr-x 2 christine christine 4096 Apr 22 20:37 Public
drwxr-xr-x 2 christine christine 4096 Apr 22 20:37 Templates
-rw-rw-r-- 1 christine christine    0 May 21 11:28 test_file
drwxr-xr-x 2 christine christine 4096 Apr 22 20:37 Videos
$

这种长列表格式的输出在每一行中列出了单个文件或目录。除了文件名,输出中还有其他有用信息。输出的第一行显示了在目录中包含的总块数。在此之后,每一行都包含了关于文件(或目录)的下述信息:

  • 文件类型,比如目录(d)、文件(-)、字符型文件(c)或块设备(b);

  • 文件的权限(参见第6章);

  • 文件的硬链接总数;

  • 文件属主的用户名;

  • 文件属组的组名;

  • 文件的大小(以字节为单位);

  • 文件的上次修改时间;

  • 文件名或目录名。

-l参数是一个强大的工具。有了它,你几乎可以看到系统上任何文件或目录的大部分信息。

在进行文件管理时,ls命令的很多参数都能派上用场。如果在shell提示符中输入man ls,就能看到可用来修改ls命令输出的参数有好几页。

别忘了可以将多个参数结合起来使用。你不时地会发现一些参数组合不仅能够显示出所需的内容,而且还容易记忆,例如ls -alF

3.5.3 过滤输出列表

由前面的例子可知,默认情况下,ls命令会输出目录下的所有非隐藏文件。有时这个输出会显得过多,当你只需要查看单个少数文件信息时更是如此。

幸而ls命令还支持在命令行中定义过滤器。它会用过滤器来决定应该在输出中显示哪些文件或目录。

这个过滤器就是一个进行简单文本匹配的字符串。可以在要用的命令行参数之后添加这个过滤器:

$ ls -l my_script
-rwxrw-r-- 1 christine christine 54 May 21 11:26 my_script
$

当用户指定特定文件的名称作为过滤器时,ls命令只会显示该文件的信息。有时你可能不知道要找的那个文件的确切名称。ls命令能够识别标准通配符,并在过滤器中用它们进行模式匹配:

  • 问号(?)代表一个字符;

  • 星号(*)代表零个或多个字符。

问号可用于过滤器字符串中替代任意位置的单个字符。例如:

$ ls -l my_scr?pt
-rw-rw-r-- 1 christine christine  0 May 21 13:25 my_scrapt
-rwxrw-r-- 1 christine christine 54 May 21 11:26 my_script
$

其中,过滤器my_scr?pt与目录中的两个文件匹配。类似地,星号可匹配零个或多个字符。

$ ls -l my*
-rw-rw-r-- 1 christine christine  0 May 21 13:25 my_file
-rw-rw-r-- 1 christine christine  0 May 21 13:25 my_scrapt
-rwxrw-r-- 1 christine christine 54 May 21 11:26 my_script
$

使用星号找到了三个名字以my开头的文件。和问号一样,你可以把星号放在过滤器中的任意位置。

$ ls -l my_s*t
-rw-rw-r-- 1 christine christine  0 May 21 13:25 my_scrapt
-rwxrw-r-- 1 christine christine 54 May 21 11:26 my_script
$

在过滤器中使用星号和问号被称为文件扩展匹配(file globbing),指的是使用通配符进行模式匹配的过程。通配符正式的名称叫作元字符通配符(metacharacter wildcards)。除了星号和问号之外,还有更多的元字符通配符可用于文件扩展匹配。可以使用中括号。

$ ls -l my_scr[ai]pt
-rw-rw-r-- 1 christine christine  0 May 21 13:25 my_scrapt
-rwxrw-r-- 1 christine christine 54 May 21 11:26 my_script
$

在这个例子中,我们使用了中括号以及在特定位置上可能出现的两种字符:ai。中括号表示一个字符位置并给出多个可能的选择。可以像上面的例子那样将待选的字符列出来,也可以指定字符范围,例如字母范围[a - i]

$ ls -l f[a-i]ll
-rw-rw-r-- 1 christine christine 0 May 21 13:44 fall
-rw-rw-r-- 1 christine christine 0 May 21 13:44 fell
-rw-rw-r-- 1 christine christine 0 May 21 13:44 fill
$

另外,可以使用感叹号(!)将不需要的内容排除在外。

$ ls -l f[!a]ll
-rw-rw-r-- 1 christine christine 0 May 21 13:44 fell
-rw-rw-r-- 1 christine christine 0 May 21 13:44 fill
-rw-rw-r-- 1 christine christine 0 May 21 13:44 full
$

在进行文件搜索时,文件扩展匹配是一个功能强大的特性。它也可以用于ls以外的其他shell命令。本章随后的部分会有到更多相关的例子。

3.6 处理文件

shell提供了很多在Linux文件系统上操作文件的命令。本节将带你逐步了解文件处理所需要的一些基本的shell命令。

3.6.1 创建文件

你总会时不时地遇到要创建空文件的情况。例如,有时应用程序希望在它们写入数据之前,某个日志文件已经存在。这时,可用touch命令轻松创建空文件。

$ touch test_one
$ ls -l test_one
-rw-rw-r-- 1 christine christine 0 May 21 14:17 test_one
$

touch命令创建了你指定的新文件,并将你的用户名作为文件的属主。注意,文件的大小是零,因为touch命令只创建了一个空文件。

touch命令还可用来改变文件的修改时间。这个操作并不需要改变文件的内容。

$ ls -l test_one
-rw-rw-r-- 1 christine christine 0 May 21 14:17 test_one
$ touch test_one
$ ls -l test_one
-rw-rw-r-- 1 christine christine 0 May 21 14:35 test_one
$

test_one文件的修改时间现在已经从最初的时间14:17更新到了14:35。如果只想改变访问时间,可用-a参数。

$ ls -l test_one
-rw-rw-r-- 1 christine christine 0 May 21 14:35 test_one
$ touch -a test_one
$ ls -l test_one
-rw-rw-r-- 1 christine christine 0 May 21 14:35 test_one
$ ls -l --time=atime test_one
-rw-rw-r-- 1 christine christine 0 May 21 14:55 test_one
$

在上面的例子中,要注意的是,如果只使用ls -l命令,并不会显示访问时间。这是因为默认显示的是修改时间。要想查看文件的访问时间,需要加入另外一个参数:--time=atime。有了这个参数,就能够显示出已经更改过的文件访问时间。

创建空文件和更改文件时间戳算不上你在Linux系统中的日常工作。不过复制文件可是在使用shell时经常要干的活儿。

3.6.2 复制文件

对系统管理员来说,在文件系统中将文件和目录从一个位置复制到另一个位置可谓家常便饭。cp命令可以完成这个任务。

在最基本的用法里,cp命令需要两个参数——源对象和目标对象:

cp source destination

sourcedestination参数都是文件名时,cp命令将源文件复制成一个新文件,并且以destination命名。新文件就像全新的文件一样,有新的修改时间。

$ cp test_one  test_two
$ ls -l test_*
-rw-rw-r-- 1 christine christine 0 May 21 14:35 test_one
-rw-rw-r-- 1 christine christine 0 May 21 15:15 test_two
$

新文件test_two和文件test_one的修改时间并不一样。如果目标文件已经存在,cp命令可能并不会提醒这一点。最好是加上-i选项,强制shell询问是否需要覆盖已有文件。

$ ls -l test_*
-rw-rw-r-- 1 christine christine 0 May 21 14:35 test_one
-rw-rw-r-- 1 christine christine 0 May 21 15:15 test_two
$
$ cp -i test_one  test_two
cp: overwrite 'test_two'? n
$

如果不回答y,文件复制将不会继续。也可以将文件复制到现有目录中。

$ cp -i test_one  /home/christine/Documents/
$
$ ls -l /home/christine/Documents
total 0
-rw-rw-r-- 1 christine christine 0 May 21 15:25 test_one
$

新文件现就在目录Documents中了,和源文件同名。

说明 之前的例子在目标目录名尾部加上了一个正斜线(/),这表明Documents是目录而非文件。这有助于明确目的,而且在复制单个文件时非常重要。如果没有使用正斜线,子目录/home/christine/Documents又不存在,就会有麻烦。在这种情况下,试图将一个文件复制到Documents子目录反而会创建一个名为Documents的文件,连错误消息都不会显示!

上一个例子采用了绝对路径,不过也可以使用相对路径。

$ cp -i test_one  Documents/
cp: overwrite 'Documents/test_one'? y
$
$ ls -l Documents
total 0
-rw-rw-r-- 1 christine christine 0 May 21 15:28 test_one
$

本章在前面介绍了特殊符号可以用在相对文件路径中。其中的单点符(.)就很适合用于cp命令。记住,单点符表示当前工作目录。如果需要将一个带有很长的源对象名的文件复制到当前工作目录中时,单点符能够简化该任务。

$ cp -i /etc/NetworkManager/NetworkManager.conf  .
$
$ ls -l NetworkManager.conf
-rw-r--r-- 1 christine christine 76 May 21 15:55 NetworkManager.conf
$

想找到那个单点符可真是不容易!仔细看的话,你会发现它在第一行命令的末尾。如果你的源对象名很长,使用单点符要比输入完整的目标对象名省事得多。

窍门 cp命令的参数要比这里叙述的多得多。别忘了用man cp,你可以看到cp命令所有的可用参数。

cp命令的-R参数威力强大。可以用它在一条命令中递归地复制整个目录的内容。

$ ls -Fd *Scripts
Scripts/
$ ls -l Scripts/
total 25
-rwxrw-r-- 1 christine christine 929 Apr  2 08:23 file_mod.sh
-rwxrw-r-- 1 christine christine 254 Jan  2 14:18 SGID_search.sh
-rwxrw-r-- 1 christine christine 243 Jan  2 13:42 SUID_search.sh
$
$ cp -R Scripts/  Mod_Scripts
$ ls -Fd *Scripts
Mod_Scripts/  Scripts/
$ ls -l Mod_Scripts
total 25
-rwxrw-r-- 1 christine christine 929 May 21 16:16 file_mod.sh
-rwxrw-r-- 1 christine christine 254 May 21 16:16 SGID_search.sh
-rwxrw-r-- 1 christine christine 243 May 21 16:16 SUID_search.sh
$

在执行cp -R命令之前,目录Mod_Scripts并不存在。它是随着cp -R命令被创建的,整个Scripts目录中的内容都被复制到其中。注意,在新的Mod_Scripts目录中,所有的文件都有对应的新日期。Mod_Scripts目录现在已经成为了Scripts目录的完整副本。

说明 在上面的例子中,ls命令加入了-Fd选项。之前你已经见过-F选项了,不过-d选项可能还是第一次碰到。后者只列出目录本身的信息,不列出其中的内容。

也可以在cp命令中使用通配符。

$ cp *script  Mod_Scripts/
$ ls -l Mod_Scripts
total 26
-rwxrw-r-- 1 christine christine 929 May 21 16:16 file_mod.sh
-rwxrw-r-- 1 christine christine 54  May 21 16:27 my_script
-rwxrw-r-- 1 christine christine 254 May 21 16:16 SGID_search.sh
-rwxrw-r-- 1 christine christine 243 May 21 16:16 SUID_search.sh
$

该命令将所有以script结尾的文件复制到Mod_Scripts目录中。在这里,只需要复制一个文件:my_script。

在复制文件的时候,除了单点符和通配符之外,另一个shell特性也能派上用场。那就是制表键自动补全。

3.6.3 制表键自动补全

在使用命令行时,很容易输错命令、目录名或文件名。实际上,对长目录名或文件名来说,输错的几率还是蛮高的。

这正是制表键自动补全挺身而出的时候。制表键自动补全允许你在输入文件名或目录名时按一下制表键,让shell帮忙将内容补充完整。

$ ls really*
really_ridiculously_long_file_name
$
$ cp really_ridiculously_long_file_name  Mod_Scripts/
ls -l Mod_Scripts
total 26
-rwxrw-r-- 1 christine christine 929 May 21 16:16 file_mod.sh
-rwxrw-r-- 1 christine christine 54  May 21 16:27 my_script
-rw-rw-r-- 1 christine christine  0  May 21 17:08
really_ridiculously_long_file_name
-rwxrw-r-- 1 christine christine 254 May 21 16:16 SGID_search.sh
-rwxrw-r-- 1 christine christine 243 May 21 16:16 SUID_search.sh
$

在上面的例子中,我们输入了命令cp really,然后按制表键,shell就将剩下的文件名自动补充完整了!当然了,目标目录还是得输入的,不过仍然可以利用命令补全来避免输入错误。

使用制表键自动补全的的技巧在于要给shell足够的文件名信息,使其能够将需要文件同其他文件区分开。假如有另一个文件名也是以really开头,那么就算按了制表键,也无法完成文件名的自动补全。这时候你会听到嘟的一声。要是再按一下制表键,shell就会列出所有以really开头的文件名。这个特性可以让你观察究竟应该输入哪些内容才能完成自动补全。

3.6.4 链接文件

链接文件是Linux文件系统的一个优势。如需要在系统上维护同一文件的两份或多份副本,除了保存多份单独的物理文件副本之外,还可以采用保存一份物理文件副本和多个虚拟副本的方法。这种虚拟的副本就称为链接。链接是目录中指向文件真实位置的占位符。在Linux中有两种不同类型的文件链接:

  • 符号链接

  • 硬链接

符号链接就是一个实实在在的文件,它指向存放在虚拟目录结构中某个地方的另一个文件。这两个通过符号链接在一起的文件,彼此的内容并不相同。

要为一个文件创建符号链接,原始文件必须事先存在。然后可以使用ln命令以及-s选项来创建符号链接。

$ ls -l data_file
-rw-rw-r-- 1 christine christine 1092 May 21 17:27 data_file
$
$ ln -s data_file  sl_data_file
$
$ ls -l *data_file
-rw-rw-r-- 1 christine christine 1092 May 21 17:27 data_file
lrwxrwxrwx 1 christine christine    9 May 21 17:29 sl_data_file -> data_file
$

在上面的例子中,注意符号链接的名字sl_data_file位于ln命令中的第二个参数位置上。显示在长列表中符号文件名后的->符号表明该文件是链接到文件data_file上的一个符号链接。

另外还要注意的是,符号链接的文件大小与数据文件的文件大小。符号链接sl_data_file只有9个字节,而data_file有1092个字节。这是因为sl_data_file仅仅只是指向data_file而已。它们的内容并不相同,是两个完全不同的文件。

另一种证明链接文件是独立文件的方法是查看inode编号。文件或目录的inode编号是一个用于标识的唯一数字,这个数字由内核分配给文件系统中的每一个对象。要查看文件或目录的inode编号,可以给ls命令加入-i参数。

$ ls -i *data_file
296890 data_file  296891 sl_data_file
$

从这个例子中可以看出数据文件的inode编号是296890,而sl_data_file的inode编号则是296891。所以说它们是不同的文件。

硬链接会创建独立的虚拟文件,其中包含了原始文件的信息及位置。但是它们从根本上而言是同一个文件。引用硬链接文件等同于引用了源文件。要创建硬链接,原始文件也必须事先存在,只不过这次使用ln命令时不再需要加入额外的参数了。

$ ls -l code_file
-rw-rw-r-- 1 christine christine 189 May 21 17:56 code_file
$
$ ln code_file  hl_code_file
$
$ ls -li *code_file
296892 -rw-rw-r-- 2 christine christine 189 May 21 17:56
code_file
296892 -rw-rw-r-- 2 christine christine 189 May 21 17:56
hl_code_file
$

在上面的例子中,我们使用ls -li命令显示了*code_files的inode编号以及长列表。注意,带有硬链接的文件共享inode编号。这是因为它们终归是同一个文件。还要注意的是,链接计数(列表中第三项)显示这两个文件都有两个链接。另外,它们的文件大小也一模一样。

说明 只能对处于同一存储媒体的文件创建硬链接。要想在不同存储媒体的文件之间创建链接,只能使用符号链接。

复制链接文件的时候一定要小心。如果使用cp命令复制一个文件,而该文件又已经被链接到了另一个源文件上,那么你得到的其实是源文件的一个副本。这很容易让人犯晕。用不着复制链接文件,可以创建原始文件的另一个链接。同一个文件拥有多个链接,这完全没有问题。但是,千万别创建软链接文件的软链接。这会形成混乱的链接链,不仅容易断裂,还会造成各种麻烦。

你可能觉得符号链接和硬链接的概念不好理解。幸好下一节中的文件重命名容易明白得多。

3.6.5 重命名文件

在Linux中,重命名文件称为移动(moving)。mv命令可以将文件和目录移动到另一个位置或重新命名。

$ ls -li f?ll
296730 -rw-rw-r-- 1 christine christine 0 May 21 13:44 fall
296717 -rw-rw-r-- 1 christine christine 0 May 21 13:44 fell
294561 -rw-rw-r-- 1 christine christine 0 May 21 13:44 fill
296742 -rw-rw-r-- 1 christine christine 0 May 21 13:44 full
$
$ mv fall  fzll
$
$ ls -li f?ll
296717 -rw-rw-r-- 1 christine christine 0 May 21 13:44 fell
294561 -rw-rw-r-- 1 christine christine 0 May 21 13:44 fill
296742 -rw-rw-r-- 1 christine christine 0 May 21 13:44 full
296730 -rw-rw-r-- 1 christine christine 0 May 21 13:44 fzll
$

注意,移动文件会将文件名从fall更改为fzll,但inode编号和时间戳保持不变。这是因为mv只影响文件名。

也可以使用mv来移动文件的位置。

$ ls -li /home/christine/fzll
296730 -rw-rw-r-- 1 christine christine 0 May 21 13:44
/home/christine/fzll
$
$ ls -li /home/christine/Pictures/
total 0
$ mv fzll  Pictures/
$
$ ls -li /home/christine/Pictures/
total 0
296730 -rw-rw-r-- 1 christine christine 0 May 21 13:44 fzll
$
$ ls -li /home/christine/fzll
ls: cannot access /home/christine/fzll: No such file or directory
$

在上例中,我们使用mv命令把文件fzll从/home/christine移动到了/home/christine/Pictures。和刚才一样,这个操作并没有改变文件的inode编号或时间戳。

窍门 和cp命令类似,也可以在mv命令中使用-i参数。这样在命令试图覆盖已有的文件时,你就会得到提示。

唯一变化的就是文件的位置。/home/christine目录下不再有文件fzll,因为它已经离开了原先的位置,这就是mv命令所做的事情。

也可以使用mv命令移动文件位置并修改文件名称,这些操作只需一步就能完成。

$ ls -li Pictures/fzll
296730 -rw-rw-r-- 1 christine christine 0 May 21 13:44
Pictures/fzll
$
$ mv /home/christine/Pictures/fzll  /home/christine/fall
$
$ ls -li /home/christine/fall
296730 -rw-rw-r-- 1 christine christine 0 May 21 13:44
/home/christine/fall
$
$ ls -li /home/christine/Pictures/fzll
ls: cannot access /home/christine/Pictures/fzll:
No such file or directory

在这个例子中,我们将文件fzll从子目录Pictures中移动到了主目录/home/christine,并将名字改为fall。文件的时间戳和inode编号都没有改变。改变的只有位置和名称。

也可以使用mv命令移动整个目录及其内容。

$ ls -li Mod_Scripts
total 26
296886 -rwxrw-r-- 1 christine christine 929 May 21 16:16
file_mod.sh
296887 -rwxrw-r-- 1 christine christine  54 May 21 16:27
my_script
296885 -rwxrw-r-- 1 christine christine 254 May 21 16:16
SGID_search.sh
296884 -rwxrw-r-- 1 christine christine 243 May 21 16:16
SUID_search.sh
$
$ mv Mod_Scripts  Old_Scripts
$
$ ls -li Mod_Scripts
ls: cannot access Mod_Scripts: No such file or directory
$
$ ls -li Old_Scripts
total 26
296886 -rwxrw-r-- 1 christine christine 929 May 21 16:16
file_mod.sh
296887 -rwxrw-r-- 1 christine christine  54 May 21 16:27
my_script
296885 -rwxrw-r-- 1 christine christine 254 May 21 16:16
SGID_search.sh
296884 -rwxrw-r-- 1 christine christine 243 May 21 16:16
SUID_search.sh
$

目录内容没有变化。只有目录名发生了改变。

在知道了如何使用mv命令进行重命名……不对……移动文件之后,你应该发现这其实非常容易的。另一个简单但可能有危险的任务是删除文件。

3.6.6 删除文件

迟早有一天,你得删除已有的文件。不管是清理文件系统还是删除某个软件包,总有要删除文件的时候。

在Linux中,删除(deleting)叫作移除(removing)2。bash shell中删除文件的命令是rmrm命令的基本格式非常简单。

2这里原文可理解为删除的功能实际上是移除(remove)命令rm完成的,在本书中,我们依然用“删除”这个大家已经习惯的叫法。

$ rm -i fall
rm: remove regular empty file 'fall'? y
$
$ ls -l fall
ls: cannot access fall: No such file or directory
$

注意,-i命令参数提示你是不是要真的删除该文件。bash shell中没有回收站或垃圾箱,文件一旦删除,就无法再找回。因此,在使用rm命令时,要养成总是加入-i参数的好习惯。

也可以使用通配符删除成组的文件。别忘了使用-i选项保护好自己的文件。

$ rm -i f?ll
rm: remove regular empty file 'fell'? y
rm: remove regular empty file 'fill'? y
rm: remove regular empty file 'full'? y
$
$ ls -l f?ll
ls: cannot access f?ll: No such file or directory
$

rm命令的另外一个特性是,如果要删除很多文件且不受提示符的打扰,可以用-f参数强制删除。小心为妙!

3.7 处理目录

在Linux中,有些命令(比如cp命令)对文件和目录都有效,而有些只对目录有效。创建新目录需要使用本节讲到的一个特殊命令。删除目录也很有意思,本节也会讲到。

3.7.1 创建目录

在Linux中创建目录很简单,用mkdir命令即可:

$ mkdir New_Dir
$ ls -ld New_Dir
drwxrwxr-x 2 christine christine 4096 May 22 09:48 New_Dir
$

系统创建了一个名为New_Dir的新目录。注意,新目录长列表是以d开头的。这表示New_Dir并不是文件,而是一个目录。

可以根据需要批量地创建目录和子目录。但是,如果你想单单靠mkdir命令来实现,就会得到下面的错误消息:

$ mkdir New_Dir/Sub_Dir/Under_Dir
mkdir: cannot create directory 'New_Dir/Sub_Dir/Under_Dir':
No such file or directory
$

要想同时创建多个目录和子目录,需要加入-p参数:

$ mkdir -p New_Dir/Sub_Dir/Under_Dir
$
$ ls -R New_Dir
New_Dir:
Sub_Dir

New_Dir/Sub_Dir:
Under_Dir

New_Dir/Sub_Dir/Under_Dir:
$

mkdir命令的-p参数可以根据需要创建缺失的父目录。父目录是包含目录树中下一级目录的目录。

当然,完事之后,你得知道怎么样删除目录,尤其是在把目录建错地方的时候。

3.7.2 删除目录

删除目录之所以很棘手,是有原因的。删除目录时,很有可能会发生一些不好的事情。shell会尽可能防止我们捅娄子。删除目录的基本命令是rmdir

$ touch New_Dir/my_file
$ ls -li New_Dir/
total 0
294561 -rw-rw-r-- 1 christine christine 0 May 22 09:52 my_file
$
$ rmdir New_Dir
rmdir: failed to remove 'New_Dir': Directory not empty
$

默认情况下,rmdir命令只删除空目录。因为我们在New_Dir目录下创建了一个文件my_file,所以rmdir命令拒绝删除目录。

要解决这一问题,得先把目录中的文件删掉,然后才能在空目录上使用rmdir命令。

$ rm -i New_Dir/my_file
rm: remove regular empty file 'New_Dir/my_file'? y
$
$ rmdir New_Dir
$
$ ls -ld New_Dir
ls: cannot access New_Dir: No such file or directory

rmdir并没有-i选项来询问是否要删除目录。这也是为什么说rmdir只能删除空目录还是有好处的原因。

也可以在整个非空目录上使用rm命令。使用-r选项使得命令可以向下进入目录,删除其中的文件,然后再删除目录本身。

$ ls -l My_Dir
total 0
-rw-rw-r-- 1 christine christine 0 May 22 10:02 another_file
$
$ rm -ri My_Dir
rm: descend into directory 'My_Dir'? y
rm: remove regular empty file 'My_Dir/another_file'? y
rm: remove directory 'My_Dir'? y
$
$ ls -l My_Dir
ls: cannot access My_Dir: No such file or directory
$

这种方法同样可以向下进入多个子目录,当需要删除大量目录和文件时,这一点尤为有效。

$ ls -FR Small_Dir
Small_Dir:
a_file  b_file  c_file  Teeny_Dir/  Tiny_Dir/

Small_Dir/Teeny_Dir:
e_file

Small_Dir/Tiny_Dir:
d_file
$
$ rm -ir Small_Dir
rm: descend into directory 'Small_Dir'? y
rm: remove regular empty file 'Small_Dir/a_file'? y
rm: descend into directory 'Small_Dir/Tiny_Dir'? y
rm: remove regular empty file 'Small_Dir/Tiny_Dir/d_file'? y
rm: remove directory 'Small_Dir/Tiny_Dir'? y
rm: descend into directory 'Small_Dir/Teeny_Dir'? y
rm: remove regular empty file 'Small_Dir/Teeny_Dir/e_file'? y
rm: remove directory 'Small_Dir/Teeny_Dir'? y
rm: remove regular empty file 'Small_Dir/c_file'? y
rm: remove regular empty file 'Small_Dir/b_file'? y
rm: remove directory 'Small_Dir'? y
$
$ ls -FR Small_Dir
ls: cannot access Small_Dir: No such file or directory
$

这种方法虽然可行,但很难用。注意,你依然要确认每个文件是否要被删除。如果该目录有很多个文件和子目录,这将非常琐碎。

说明 对rm命令而言,-r参数和-R参数的效果是一样的。-R参数同样可以递归地删除目录中的文件。shell命令很少会就相同的功能采用不同大小写的参数。

一口气删除目录及其所有内容的终极大法就是使用带有-r参数和-f参数的rm命令。

$ tree Small_Dir
Small_Dir
├── a_file
├── b_file
├── c_file
├── Teeny_Dir
│   └── e_file
└── Tiny_Dir
    └── d_file

2 directories, 5 files
$
$ rm -rf Small_Dir
$
$ tree Small_Dir
Small_Dir [error opening dir]

0 directories, 0 files
$

rm -rf命令既没有警告信息,也没有声音提示。这肯定是一个危险的工具,尤其是在拥有超级用户权限的时候。务必谨慎使用,请再三检查你所要进行的操作是否符合预期。

说明 在上面的例子中,我们使用了tree工具。它能够以一种美观的方式展示目录、子目录及其中的文件。如果需要了解目录结构,尤其是在删除目录之前,这款工具正好能派上用场。不过它可能并没有默认安装在你所使用的Linux发行版中。请参阅第9章,学习如何安装软件。

在前面几节中,你看到了如何管理文件和目录。到此为止,除了如何查看文件内容,我们已经讲述了你所需要的有关文件的全部知识。

3.8 查看文件内容

Linux中有几个命令可以查看文件的内容,而不需要调用其他文本编辑器(参见第10章)。本节将演示一些可以帮助查看文件内容的命令。

3.8.1 查看文件类型

在显示文件内容之前,应该先了解一下文件的类型。如果打开了一个二进制文件,你会在屏幕上看到各种乱码,甚至会把你的终端仿真器挂起。

file命令是一个随手可得的便捷工具。它能够探测文件的内部,并决定文件是什么类型的:

$ file my_file
my_file: ASCII text
$

上面例子中的文件是一个text(文本)文件。file命令不仅能确定文件中包含的文本信息,还能确定该文本文件的字符编码,ASCII。

下面例子中的文件就是一个目录。因此,以后可以使用file命令作为另一种区分目录的方法:

$ file New_Dir
New_Dir: directory
$

第三个file命令的例子中展示了一个类型为符号链接的文件。注意,file命令甚至能够告诉你它链接到了哪个文件上:

$ file sl_data_file
sl_data_file: symbolic link to 'data_file'
$

下面的例子展示了file命令对脚本文件的返回结果。尽管这个文件是ASCII text,但因为它是一个脚本文件,所以可以在系统上执行(运行):

$ file my_script
my_script: Bourne-Again shell script, ASCII text executable
$

最后一个例子是二进制可执行能够确定该程序编译时所面向的平台以及需要何种类型的库。如果你有从未知源处获得程序。file命令的二进制文件,这会是个非常有用的特性:

$ file /bin/ls
/bin/ls: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV),
dynamically linked (uses shared libs), for GNU/Linux 2.6.24,
[...]
$

现在你已经学会了如何快速查看文件类型,接着就可以开始学习文件的显示与浏览了。

3.8.2 查看整个文件

如果手头有一个很大的文本文件,你可能会想看看里面是什么内容。在Linux上有3个不同的命令可以完成这个任务。

1. cat命令

cat命令是显示文本文件中所有数据的得力工具。

$ cat test1
hello

This is a test file.


That we'll use to       test the cat command.
$

没什么特别的,就是文本文件的内容而已。这里还有一些可以和cat命令一起用的参数,可能对你有所帮助。

-n参数会给所有的行加上行号。

$ cat -n test1
     1  hello
     2
     3  This is a test file.
     4
     5
     6  That we'll use to       test the cat command.
$

这个功能在检查脚本时很有用。如果只想给有文本的行加上行号,可以用-b参数。

$ cat -b test1
     1  hello

     2  This is a test file.


     3  That we'll use to       test the cat command.
$

最后,如果不想让制表符出现,可以用-T参数。

$ cat -T test1
hello

This is a test file.


That we'll use to^Itest the cat command.
$

-T参数会用^I字符组合去替换文中的所有制表符。

对大型文件来说,cat命令有点繁琐。文件的文本会在显示器上一晃而过。好在有一个简单办法可以解决这个问题。

2. more命令

cat命令的主要缺陷是:一旦运行,你就无法控制后面的操作。为了解决这个问题,开发人员编写了more命令。more命令会显示文本文件的内容,但会在显示每页数据之后停下来。我们输入命令more /etc/bash.bashrc生成如图3-3中所显示的内容。

{%}

图 3-3 使用more命令显示文本文件

注意图3-3中屏幕的底部,more命令显示了一个标签,其表明你仍然在more程序中以及你现在在这个文本文件中的位置。这是more命令的提示符。

more命令是分页工具。在本章前面的内容里,当使用man命令时,分页工具会显示所选的bash手册页面。和在手册页中前后移动一样,你可以通过按空格键或回车键以逐行向前的方式浏览文本文件。浏览完之后,按q键退出。

more命令只支持文本文件中的基本移动。如果要更多高级功能,可以试试less命令。

3. less命令

从名字上看,它并不像more命令那样高级。但是,less命令的命名实际上是个文字游戏(从俗语“less is more”得来),它实为more命令的升级版。它提供了一些极为实用的特性,能够实现在文本文件中前后翻动,而且还有一些高级搜索功能。

less命令的操作和more命令基本一样,一次显示一屏的文件文本。除了支持和more命令相同的命令集,它还包括更多的选项。

窍门 要想查看less命令所有的可用选项,可以输入man less浏览对应的手册页。也可以这样查看more命令选项的参考资料。

其中一组特性就是less命令能够识别上下键以及上下翻页键(假设你的终端配置正确)。在查看文件内容时,这给了你全面的控制权。

3.8.3 查看部分文件

通常你要查看的数据要么在文本文件的开头,要么在文本文件的末尾。如果这些数据是在大型文件的起始部分,那你就得等catmore加载完整个文件之后才能看到。如果数据是在文件的末尾(比如日志文件),那可能需要翻过成千上万行的文本才能到最后的内容。好在Linux有解决这两个问题的专用命令。

1. tail命令

tail命令会显示文件最后几行的内容(文件的“尾部”)。默认情况下,它会显示文件的末尾10行。

出于演示的目的,我们创建了一个包含20行文本的文本文件。使用cat命令显示该文件的全部内容如下:

$ cat log_file
line1
line2
line3
line4
line5
Hello World - line 6
line7
line8
line9
line10
line11
Hello again - line 12
line13
line14
line15
Sweet - line16
line17
line18
line19
Last line - line20
$

现在你已经看到了整个文件,可以再看看使用tail命令浏览文件最后10行的效果:

$ tail log_file
line11
Hello again - line 12
line13
line14
line15
Sweet - line16
line17
line18
line19
Last line - line20
$

可以向tail命令中加入-n参数来修改所显示的行数。在下面的例子中,通过加入-n 2使tail命令只显示文件的最后两行:

$ tail -n 2 log_file
line19
Last line - line20
$

-f参数是tail命令的一个突出特性。它允许你在其他进程使用该文件时查看文件的内容。tail命令会保持活动状态,并不断显示添加到文件中的内容。这是实时监测系统日志的绝妙方式。

2. head命令

head命令,顾名思义,会显示文件开头那些行的内容。默认情况下,它会显示文件前10行的文本:

$ head log_file
line1
line2
line3
line4
line5
Hello World - line 6
line7
line8
line9
line10
$

类似于tail命令,它也支持-n参数,这样就可以指定想要显示的内容了。这两个命令都允许你在破折号后面输入想要显示的行数:

$ head -5 log_file
line1
line2
line3
line4
line5
$

文件的开头通常不会改变,因此head命令不像tail命令那样支持-f参数特性。head命令是一种查看文件起始部分内容的便捷方法。

3.9 小结

本章涵盖了在shell提示符下操作Linux文件系统的基础知识。一开始我们讨论了bash shell,之后介绍了怎样和shell交互。命令行界面(CLI)采用提示符来表明你可以输入命令。bash shell提供了很多可用以创建和操作文件的工具。在开始操作文件之前,很有必要先了解一下Linux怎么存储文件。本章讨论了Linux虚拟目录的基础知识,然后展示了Linux如何引用存储设备。在描述了Linux文件系统之后,还带你逐步了解了如何使用cd命令在虚拟目录里切换目录。

在介绍如何进入指定目录后,我们又演示了怎样用ls命令列出目录中的文件和子目录。ls命令有很多参数可用来定制输出内容。可以通过ls命令获得有关文件和目录的信息。

touch命令非常有用,可以创建空文件和变更已有文件的访问时间或修改时间。本章还介绍了如何使用cp命令将已有文件复制到其他位置。另外还逐步介绍了如何链接文件,给出了一种简单的方法可以实现在两个位置上拥有同一个文件且不用生成单独的副本。ln命令提供了这种链接功能。

接着我们讲了怎样用mv命令重命名文件(在Linux中称为移动文件),以及如何用rm命令删除文件(在Linux中称为移除文件),还介绍了怎样用mkdirrmdir命令对目录执行相同的任务。

最后,本章以如何查看文件的内容作结。catmoreless命令可以非常方便地查看文件全部内容,而且tailhead命令还可查看文件中的一小部分内容。

下章将继续讨论bash shell的命令,并了解更多管理Linux系统时经常用到的高级系统管理命令。

目录

  • 版权声明
  • 引言
  • 致谢
  • 第一部分 Linux 命令行
  • 第 1 章 初识Linux shell
  • 第 2 章 走进shell
  • 第 3 章 基本的bash shell命令
  • 第 4 章 更多的bash shell命令
  • 第 5 章 理解shell
  • 第 6 章 使用Linux环境变量
  • 第 7 章 理解Linux文件权限
  • 第 8 章 管理文件系统
  • 第 9 章 安装软件程序
  • 第 10 章 使用编辑器
  • 第二部分 shell脚本编程基础
  • 第 11 章 构建基本脚本
  • 第 12 章 使用结构化命令
  • 第 13 章 更多的结构化命令
  • 第 14 章 处理用户输入
  • 第 15 章 呈现数据
  • 第 16 章 控制脚本
  • 第三部分 高级shell脚本编程
  • 第 17 章 创建函数
  • 第 18 章 图形化桌面环境中的脚本编程
  • 第 19 章 初识sed和gawk
  • 第 20 章 正则表达式
  • 第 21 章 sed进阶
  • 第 22 章 gawk进阶
  • 第 23 章 使用其他shell
  • 第四部分 创建实用的脚本
  • 第 24 章 编写简单的脚本实用工具
  • 第 25 章 创建与数据库、Web及电子邮件相关的脚本
  • 第 26 章 一些小有意思的脚本
  • 附录 A bash命令快速指南
  • 附录 B sed和gawk快速指南