# 前言

对于普通的PC使用者来说,学会使用Windows操作系统已经足够了。但是,对于一个软件开发者来说,仅仅会使用Windows操作系统是不行的,还需要学会使用Linux操作系统。《Linux命令行大全》正是一本能够帮助初学者系统了解Linux操作系统基本操作的书籍,因此我决定仔细阅读一下。为了方便以后查阅相关知识点,我决定将所学知识记录下来。和《Linux命令行大全》一书一样,笔者并不打算告诉你如何安装Linux操作系统,安装Linux操作系统的详细步骤可以在网络上方便地找到,在此,就不再赘述了。大多数Linux书籍都会告诉你使用Vmware或其它虚拟机安装Linux操作系统。在这里,笔者直接使用阿里云的ECS服务器Centos 6.8,这是Linux的一种发行版本,在互联网行业中得到广泛使用。一般情况下,我们都不会直接操作Linux操作系统,更普遍的情况是,我们会通过Xshell等终端远程连接、访问并操作Linux操作系统。

Xshell简介

Xshell是一个强大的安全终端模拟软件,它支持SSH1, SSH2, 以及Microsoft Windows平台的TELNET协议,可以用来连接并操作远端服务器。Xshell提供了个人和家庭使用的免费版本,而且其安装也是相当简单的,读者可以自行搜索Xshell下载并安装。

当我们准备好Linux操作系统,并通过Xshell连接到远程服务器并登录后,就可以进行相关操作了。

# 第一章 初探Linux操作系统

既然是初探,就应该循序渐进,而不是揠苗助长。学习Linux系统,其实主要学习的是命令行命令。因此,我们先从简单的Linux命令入手。

# date-显示当前系统日期和时间

首先,我们学习如何显示当前系统的时间和日期,这个命令很简单,只需要在终端上输入date命令并回车即可。

date 

此时,Xshell界面会返回当前日期和时间

Wed Feb 20 11:26:30 CST 2019

# cal-显示当前系统的日历

接下来,我们再敲一个cal命令,这个命令用来显示当前系统的日历,默认情况下,该命令的结果将返回当前月的日历。和上面类似,我们在终端直接输入cal命令并回车就行了。

cal

此时,我们将在终端看到一个显示当前月的日历。

February 2019   
Su Mo Tu We Th Fr Sa
                1  2
 3  4  5  6  7  8  9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28

通过以上两个例子,我们初步感受了Linux命令行的使用。下面,我们学习一下查看磁盘驱动器可用空间以及Linux可用内存的命令。

# df-查看磁盘空间

查看磁盘驱动器可用空间的命令比较简单,直接输入df命令并回车即可。

df

这样,我们可以得到如下信息

Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/vda1       41151808 2001384  37053376   6% /
tmpfs             509988       0    509988   0% /dev/shm

# free-查看Linux可用内存

然后,我们再学习查看Linux可用内存的命令,这个命令和前面一样简单,直接在终端输入free命令回车即可。

free

这样,我们得到如下结果

             total       used       free     shared    buffers     cached
Mem:       1019980     920564      99416        160     143624     681376
-/+ buffers/cache:      95564     924416
Swap:            0          0          0

当我们完成所有操作后,我们可以在终端输入exit命令断开本机与远程Linux的连接。

exit

# 第二章 认识Linux文件系统树

在上一节中,我们初步体验了在Xshell终端中输入命令操作Linux,在本节中,我们开始学习Linux文件系统树。和Windows相同,Linux也是以称之为分层目录结构的方式来组织文件的。这也就意味着文件是在树形结构的目录中组织的,在该树形结构目录中可能包含有文件和其他目录。文件系统的第一个目录称为根目录,它包含了文件和子目录,子目录包含了更多的文件和子目录,就这样一直重复下去,最终构成了Linux文件系统树。

Windows和类Unix系统文件系统树的区别

需要注意的是,虽然Windows和Linux组织文件的方式相同,但在Windows系统中,每个存储设备都有一个独立的文件系统树 ,而在Linux这些类Unix系统中,无论存在多少驱动器和存储设备,通常都只有一个文件系统树,类Unix系统会根据系统管理员的设置,将设备挂载到文件系统树的不同位置。

# pwd-显示当前工作目录

和Windows一样,当我们处在某个目录中,我们可以看到该目录所包含的文件、去往上一级目录的路径,以及下一级的子目录。此时我们所处的目录称为当前工作目录。正如GPS导航系统可以显示我们所处的经纬度信息一样,我们也可以让Linux告诉我们当前工作目录的路径,使用pwd命令可以显示当前工作目录。

pwd

通过这个命令,我们可以知道当前工作目录的路径。既然可以知道当前工作目录,我们也就可以知道当前目录下的文件和子目录。当我们第一次登陆系统时,当前工作目录会被设置成主目录。每个用户都会有一个主目录,对于普通用户来说,主目录是唯一一个允许用户进行写操作的地方。

# ls-列出目录内容

在Linux中,我们可以使用ls命令列出当前目录的文件和子目录

ls

当然,ls命令还有其它用法,在后面的内容中将会更加详细地介绍。

# cd-更改当前工作目录

绝大多数情况下,我们都需要更改当前工作目录,此时,我们需要使用cd命令切换工作目录。一般情况下,我们输入cd命令后还需要指定具体的目标工作目录的路径,所谓路径指的是沿着分枝到达目标目录的路由。

cd target

和Windows类似,Linux的路径也分为绝对路径和相对路径

  • 绝对路径:绝对路径从根目录开始,其后跟着一个又一个文件树分枝,直到到达目标目录或文件。对于绝对路径来说,其显著特征是以前导斜杠/开头。

例如,在Linux系统中,有一个目录,大多数系统程序都安装到这个目录里,这个目录是/usr/bin,这也就意味着在根目录下有一个目录usr,在目录usr下存在bin目录,现在我们切换过去

cd /usr/bin

此时,我们使用pwd命令显示当前工作目录

pwd

可以看到,当前工作目录已经是/usr/bin,我们使用ls查看当前工作目录下的文件及子目录,可以看到数量是非常多的。

  • 相对路径:和绝对路径从根目录开始,到目标目录或文件结束不同,相对路径则是从工作目录开始的。我们可以使用一些特殊符号来表示文件系统树中的相对位置,这些符号是...。符号.表示工作目录,符号..表示工作目录的父目录。

若我们想更改当前工作目录\usr\bin\usr,即当前目录的父目录,可以有两种方式。

  • 绝对路径方式
cd /usr
  • 相对路径方式
cd ..

无论哪种方式,我们都可以切换到\usr目录。当然,我们也可以从\usr目录切换到\usr\bin目录。同样地,我们也有两种方式。

  • 绝对路径方式
cd /usr/bin
  • 相对路径方式
cd ./bin

在相对路径方式下,我们还可以省略./,因为其是隐含的。即

  • 隐含相对路径方式
cd bin

一般而言,若是没有指定目录,则默认为当前工作目录

# cd命令常用快捷方式

cd命令提供了几个可以快速切换工作目录的方法

快捷方式 结果
cd 将工作目录切换到主目录
cd - 将工作目录切换到先前的工作目录
cd~username 将工作目录切换为username的主目录

# 文件名命名规则说明

  1. 在Linux中,以.开头的文件是隐藏的,这仅仅说明ls命令不会列出该文件,除非使用ls -a命令,在创建用户账号时,主目录会放置一些隐藏文件,用来配置账号信息。此外,一些应用程序也会将它们的配置文件和设置文件以隐藏文件的形式放在主目录下。
  2. Linux文件名与命令都是区分字母大小写的。例如:File1和file1是不一样的。
  3. Linux没有扩展名的概念,我们可以按照自己的喜好随意给文件命名。文件的内容或用途由其它方式决定。虽然如此,一些应用程序仍然使用扩展名区分文件内容和用途。
  4. Linux支持长文件名,但在文件名中不要嵌入空格,以免给自己带来不必要的麻烦。

# Linux命令选项和参数

在Linux中,大部分命令都遵循以下格式

commond -options arguments

即通常情况下,一个命令会带有一个或多个选项,带有不同选项的命令其功能也会有所不同,此外,命令后面还会跟有一个或多个参数,这些参数是命令作用的对象。大部分命令的选项是在单个字符前加上连字符-,但是很多命令,包括GNU里面的命令,也支持在单字前加上两个连字符--的长选项,而且很多命令也允许多个短选项串在一起使用。 下面,我们通过ls命令说明上述描述。

# 第三章 Linux系统

# 深入了解ls命令

前面说到,ls命令的作用是列出目录内容,鉴于 ls命令是用户最常用的命令之一,它能查看目录内容,确定各种重要文件和目录的属性,我们有必要详细了解一下ls丰富的用法。

  1. 若我们直接查看当前工作目录下的文件和子目录,我们可以直接使用不带参的ls命令,即

    ls
    

    这样,我们就可以获取当前工作目录的文件和子目录信息了

    bin  etc  games  include  java  lib  lib64  libexec  local  sbin  share  src  tmp
    
  2. 若我们想要查看指定目录的信息,我们可以直接指定目录

    ls  /usr
    

    当然我们也可以一次性指定多个目录,同时查看多个目录下的文件和子目录

    ls ~ /usr
    

    其中,~指的是当前账户的主目录,现在,我使用的是root账号,执行这条命令,可以得到如下结果

    /root:
    
    /usr:
    bin  etc  games  include  java  lib  lib64  libexec  local  sbin  share  src  tmp
    

    可以看到,在当前账户的主目录下,没有任何文件和子目录,而在\usr目录下则存在多个子目录。

  3. 若我们想要展示更多的信息并按照文件修改时间排序,我们可以使用选项l,t,选项l产生长格式输出,t选项表示以文件修改的时间顺序先后将结果输出

    ls -lt /usr
    

    这样,我们就按长格式输出/usr目录下按照文件修改的时间排序的文件和子目录信息。

    total 72
    dr-xr-xr-x.  2 root root  4096 Aug  8  2018 sbin
    drwxr-xr-x   3 root root  4096 Jul 25  2018 java
    dr-xr-xr-x. 28 root root 12288 Aug 24  2017 lib64
    dr-xr-xr-x.  2 root root 20480 Aug 24  2017 bin
    dr-xr-xr-x. 12 root root  4096 Aug 24  2017 lib
    drwxr-xr-x. 13 root root  4096 Aug 24  2017 local
    drwxr-xr-x. 65 root root  4096 Aug 24  2017 share
    drwxr-xr-x. 10 root root  4096 Aug 24  2017 libexec
    drwxr-xr-x. 35 root root  4096 Aug 24  2017 include
    drwxr-xr-x.  4 root root  4096 Aug 24  2017 src
    lrwxrwxrwx.  1 root root    10 Aug 24  2017 tmp -> ../var/tmp
    drwxr-xr-x.  2 root root  4096 Sep 23  2011 etc
    drwxr-xr-x.  2 root root  4096 Sep 23  2011 games
    

    若我们想按照相反顺序输出,则加上长选项--reverse即可,即

    ls -lt --reverse /usr
    

    可以预料,输出结果和原结果排序正好相反

    total 72
    drwxr-xr-x.  2 root root  4096 Sep 23  2011 games
    drwxr-xr-x.  2 root root  4096 Sep 23  2011 etc
    lrwxrwxrwx.  1 root root    10 Aug 24  2017 tmp -> ../var/tmp
    drwxr-xr-x.  4 root root  4096 Aug 24  2017 src
    drwxr-xr-x. 35 root root  4096 Aug 24  2017 include
    drwxr-xr-x. 10 root root  4096 Aug 24  2017 libexec
    drwxr-xr-x. 65 root root  4096 Aug 24  2017 share
    drwxr-xr-x. 13 root root  4096 Aug 24  2017 local
    dr-xr-xr-x. 12 root root  4096 Aug 24  2017 lib
    dr-xr-xr-x.  2 root root 20480 Aug 24  2017 bin
    dr-xr-xr-x. 28 root root 12288 Aug 24  2017 lib64
    drwxr-xr-x   3 root root  4096 Jul 25  2018 java
    dr-xr-xr-x.  2 root root  4096 Aug  8  2018 sbin
    

对于ls命令,Linux提供了相当多的选项,常用选项罗列如下

  1. ls命令常用选项及含义
选项 长选项 含义
-a --all 列出所有文件,包括以.开头的隐藏文件,
这些文件在不加该选项时是不显示的
-d --directory 通常情况下,ls命令会罗列指定目录下的文件和子目录,
若想要查看目录本身的信息,需要使用该选项。若与l
项相结合,可以罗列出目录本身的详细信息
-F --classify 该选项会在每个所列出的名字后面加上类型指示符,
若是一个目录,则会加上一个斜杠
-h --human-readable 若使用该选项,当信息以长格式列出时,Linux将以人类可读的方式
而不是字节数显示文件大小
-l 使用长格式显示结果
-r --reverse 以相反的顺序显示结果,通常情况下,ls命令按照字母升序
排列显示结果
-S 按文件大小对结果排序
-t 按修改时间排序
  1. 了解ls命令长格式信息含义

我们随意选取一条长格式的输出结果

dr-xr-xr-x. 12 root root  4096 Aug 24  2017 lib

我们将结果进行拆分,查看这些字段的含义

字段 含义
dr-xr-xr-x 这表示的是用户对文件的访问权限;
第一个字符表示文件的类型。
在不同的类型中,开头的-表示该文件是一个普通文件,d表示目录,l表示链接文件。
紧接着的三个字符表示文件所有者的访问权限,
再紧接着的三个字符表示文件所属组中成员的访问权限,
最后三个字符表示其他所有人的访问权限
12 文件硬链接数目
root 文件所有者的用户名称
root 文件所属用户组名称
4096 以字节数表示的文件大小
Aug 24 2017 上次修改文件的日期和时间,即最近改动文件时间
lib 文件名

# file-命令确定文件类型

先前讲过,Linux并不能通过后缀名确定文件类型,因此,我们需要使用其它命令来确定文件类型,Linux提供了file命令查看文件类型,其命令格式为:

file filename

我们查看一下目录\usr\include下的poll.h文件类型

file poll.h

可以看到,这是一个ASCII C文本文件,也就是C语言编写的源文件

poll.h: ASCII C program text

# less-使用命令查看文本内容

在Linux中,很多文件都以文本文件的形式存储,不可避免地,我们需要经常查看这类格式的文件。因此,我们有必要学习如何查看文本文件。

在该系统中,Linux提供了各种各样的命令帮助我们查看文本内容,我们学习less命令,其命令格式为:

less filename

一旦运行该命令,less命令将允许我们前后滚动文件,这样我们就能查看内容了,现在我们查看一下/etc/passwd文件内容。

less /etc/passwd

若我们查看完成,可以按q退出程序。下面列出less命令常用的键盘命令。

命令 功能
Page Upb 后翻一页
Page DownSpace 前翻一页
向上箭头 向上一行
向下箭头 向下一行
G 跳到文本文件末尾
g 跳到文本文件开头
/charaters 向前查找指定的字符串
n 向前查找指定的字符串,该字符串是之前指定查找的
h 显示帮助屏幕
q 退出less

# Linux系统重要目录

在Linux中,存在一些比较重要的目录,这些目录存储了比较重要的程序或文件,我们需要对其有一定的了解。

目录 内容
/ 根目录
/bin 包含系统启动和运行必须的二进制文件
/sbin 该目录放置"系统"二进制文件,这些文件执行重要的系统任务
/boot 包含Linux内核,最初的RAM磁盘映像(系统启动时会用到),以及自动加载程序
/lib 包含核心系统程序使用的共享库文件
/dev 包含设备节点的特殊目录
/etc 包含所有系统层面的配置文件,同时也包含一系列shell脚本,系统启动时,这些脚本都会打开相应的系统服务
/home 通常情况下,每个用户都会在/home目录下有属于自己的一个目录,普通用户只能在自己的主目录中创建文件
/opt 主要用来安装其他可选软件,一般用来安装可能安装在系统内的商业软件
/usr 包含普通用户使用的所有程序和相关文件
/usr/sbin 系统管理程序
/var/log 该目录包含的日志文件极其重要,记录了各种系统活动
/tmp 供用户存放各类程序创建的临时文件,在系统重启后,会清空该目录
/var 可能改变的数据会存储在该目录中,如各种数据库、假脱机文件、用户邮件
/root root账户的主目录

# 第四章 操作目录和文件

在Windows里,我们通常使用图形界面提供的功能来对目录和文件进行操作,在Linux中,我们应当尝试使用命令操作目录和文件,因为在实际开发中,我们使用的服务器一般是没有图形界面的。

在学习如何使用命令操作目录和文件之前,我们先学习一下通配符。通配符是一些特殊字符,它允许用户根据字符模式选择文件名,通过通配符,使得为文件名构建复杂的筛选标准成为可能。

  1. 常用的通配符
通配符 匹配项
* 匹配任意多个字符,包括0个或1个
? 匹配任意一个字符,不包括0个
[characters] 匹配任意一个属于字符集的字符
[!characters] 匹配任意一个不属于字符集的字符
[[:class:]] 匹配任意一个属于指定字符类的字符
  1. 常用的字符类
字符类 匹配项
[:alnum:] 匹配任意一个字母或数字
[:alpha:] 匹配任意一个字母
[:digit:] 匹配任意一个数字
[:lower:] 匹配任意一个小写字母
[:upper:] 匹配任意一个大写字母
  1. 通配符和常用字符类使用示例
模式 匹配项
* 所有文件
g* 以g开头的任意文件
b*.txt 以b开头,中间有任意多个字符,以.txt结尾的文件
Data??? 以Data开头,后面跟任意三个字符的文件
[![:digit:]]* 不以数字开头的任意文件

# mkdir-创建目录

现在,我们先学习第一个命令,创建目录的mkdir命令,格式如下:

mkdir directory...

...表示可以同时创建多个目录,directory代表具体的目录名称。可以看到,我们可以同时创建一个或多个目录。

  1. 创建单个目录的命令格式
mkdir directory1
  1. 创建多个目录的命令格式
mkdir directory1 directory2 directory3

创建多个目录时,目录之间以空格作为间隔。下面,我们学习复制文件和目录的cp命令。

# cp-复制文件和目录

cp命令用来复制文件和目录,需要注意的是,cp命令有两种用法。

  1. 将单个文件或目录item1复制到文件或目录item2中,其命令格式如下:
cp item1 item2

该命令表示将单个文件或目录item1复制到文件或目录item2中。

  1. 若要将多个目录复制到同一文件夹则需要使用以下命令格式:
cp item... directory

当然,在实际使用过程中,cp命令并不会这么简单,Linux提供了多个选项供我们自定义复制。

选项 长选项 含义
-a --archive 复制文件和目录及其属性,包括所有权和权限。
通常来说,复制的文件具有用户所操作文件的默认属性
-i --interactive 在覆盖一个已存在的文件前,提示用户进行确认。
如果没有该选项,cp命令将执行直接覆盖操作
-r --recursive 递归复制目录及其内容,复制目录时需要这个选项
-u --update 当将文件从一个目录复制到另一个目录时,只会复制那些目标
文件中不存在的文件或目标文件相应文件的更新文件
-v --verbose 复制文件时,显示信息性消息

# mv-移动和重命名文件

mv命令可以执行文件移动和文件重命名操作,具体取决于如何使用它。 无论如何使用,操作完成后,原来的文件将不再存在,mv命令的使用方式和cp命令相似,都有两种使用方法。

  1. 将文件或目录item1移动或重命名为item2
mv item1 item2
  1. 将一个或多个文件或目录移动到另一个目录下
mv item... directory

mv命令和cp命令很多选项是共享的。

选项 长选项 含义
-i --interactive 覆盖一个文件之前,提示用户确认,
如果没有指定该选项,默认会覆盖文件
-u --update 将文件从一个目录复制到另外一个目录,只移动目标目录
不存在的文件或目标目录里相应文件的更新文件
-v --verbose 移动文件时显示信息性消息

下面是mv命令的一些使用示例。

  1. 将文件移到另一个文件
mv file1 file2

将file1移到file2,如果file2存在,则将会被file1的内容覆盖。如果file2不存在,则会创建file2,不管怎么样,file1都将不会再存在。

  1. 将文件移到另外一个文件,并在操作前给与提示
mv -i file1 file2

从最终结果来看,其和第一种是没有区别的。不同的是,若file2已经存在,覆盖之前Linux会通知用户确认。

  1. 将多个文件移到某个目录下
mv file1 file2 dir1

这个命令可以同时将file1和file2移动到目录dir1下,需要注意的是,该目录必须已经存在。

  1. 将目录移到另一个目录
mv dir1 dir2

该命令意思是将目录dir1的内容移动到目录dir2下,若目录dir2不存在,Linux就会创建目录dir2,最终结果是目录dir1的内容被移动到目录dir2,原有目录dir1将被删除。

# rm-删除文件或目录

在Linux中,我们使用rm命令移除(删除)文件和目录,其格式如下:

rm item...

其中,item是一个或多个文件或目录的名称,目录或文件之间使用空格分隔。

警告

Linux默认用户是明智的,并清楚自己在干什么,所以其并没有提供还原删除操作的命令。一旦使用rm命令,就意味着目录或文件被彻底删除了。因此,在进行该操作时,必须仔细检查。在使用rm命令搭配通配符删除文件或目录时,可以先使用ls命令测试通配符,确保不会出现误删除的情况。

和前面一样,rm命令的一些常用选项罗列如下:

选项 长选项 含义
-i --interactive 删除一个已经存在的文件之前,提示用户确认,
如果没有这个选项,rm命令会默认删除文件,
同意使用y,反对使用n
-r --recursive 递归地删除目录,也就是说,如果删除的目录有子目录的话
,也要将其删除。如果要删除一个目录,必须指定该选项
-f --force 忽略不存在的文件并无需确认,该选项会覆盖--iteractive选项
-v --verbose 删除文件时显示信息性消息

# ln-创建软硬链接

在Linux中,内核为每一个新创建的文件分配一个Inode(索引结点),每个文件都有一个惟一的inode号。文件属性保存在索引结点里,在访问文件时,索引结点被复制到内存中,从而实现文件的快速访问。

在Linux中,链接是一种在共享文件和访问它的用户的若干目录项之间建立联系的一种方法。我们可以使用ln命令创建链接, ln可以创建两种链接:硬链接和符号链接(也称为软链接)。

  • 硬链接硬链接是文件的别名。从技术上讲,他们共用一个inode(inode中包含了一个文件的所有必要的信息,说inode就是文件也是没有问题的)。 由于linux下的文件是通过索引节点(Inode)来识别文件,硬链接也可以认为是一个指向文件索引节点的指针,系统并不为它重新分配inode。

    每添加一个硬链接,文件的链接数就加1, 删除一个则链接数减1。

    对于硬连接来说,其有两大限制:

      1. 硬链接不能引用自身文件系统以外的文件,也就是说,链接不能引用与该链接不在同一磁盘分区的文件。
      
      2. 硬链接不能引用目录。
    

创建硬连接的ln命令格式如下:

ln filepath linkpath
  • 软链接: 软链接是一种特殊的文件类型,其中包含对另一个文件或目录以绝对或相对路径形式的引用,可以看做是对一个文件的间接指针,相当于windows下的快捷方式。

创建软链接的ln命令格式如下:

ln -s item linkpath

在这里,item既可以是文件也可以是目录,和创建硬链接的格式相比,创建软链接多了一个-s选项。

软链接与硬连接的区别:

1. 软链接没有任何文件系统的限制,任何用户可以创建指向文件或目录的软链接。甚至可以跨越不同机器、不同网络对文件进行链接。

2. 创建文件的软链接时,软链接会使用一个新的inode,所以软链接的inode号和文件的inode号不同(表明他们是两个不同的文件)

3. 删除软链接对原文件没有任何影响。

4. 软链接的inode里存放着指向文件的路径,删除源文件,软链接也就无法正常使用了,此时,这是一个坏链接。

# Linux操作实践

现在,我们进行一些实际操作,为方便操作,我们将目录切换到当前账号的主目录,输入cd命令,切换到主目录,并在当前目录下创建playground目录。

mkdir playground 

然后,我们切换工作目录到目录playground,在该目录下创建两个新的目录dir1dir2。前面我们提到mkdir命令可以接受多个参数,允许我们同时创建多个目录。

mkdir dir1 dir2

接下来,我们使用cp命令复制/etc目录下的passwd文件到当前工作目录。

cp /etc/passwd .

其中,.代表的是当前工作目录。此时,我们查看一下当前工作目录包含的文件和子目录。

ls -l

可以看到,当前工作目录下的详细信息一目了然。

total 12
drwxr-xr-x 2 root root 4096 Feb 25 15:49 dir1
drwxr-xr-x 2 root root 4096 Feb 25 15:49 dir2
-rw-r--r-- 1 root root  964 Feb 25 15:54 passwd

其中,目录dir1dir2是我们创建的,而文件passwd则是我们复制产生的。让我们使用-i选项,重复操作复制命令。

cp -i /etc/passwd .

此时,我们将获得警告信息,根据提示,我们输入y,完成复制,覆盖当前文件。若输入其它字符,则会使cp命令保留原有文件,不进行复制操作。

然后,我们使用mv命令修改passwd文件名为fun

mv passwd fun

我们继续操作,将fun文件移动到目录dir1

mv fun dir1

再将其从目录dir1移动到目录dir2

mv dir1/fun dir2

接着,我们将文件重新移动到当前工作目录下

mv dir2/fun .

我们再操作一下,将数据文件fun移动到dir1目录下

mv fun dir1

完成之后,我们再将dir1目录移动到dir2目录下,因为dir2目录已经存在,mv将正常移动,否则,dir1将重命名为dir2

mv dir1 dir2

为了确认操作是否已经成功,我们使用ls命令查看目录dir2/dir1

ls -l dir2/dir1

查看结果,我们已经操作成功了。

total 4
-rw-r--r-- 1 root root 964 Feb 25 16:03 fun

紧接着,我们将文件恢复原状,将数据文件fun重新移动回当前工作目录,即playground目录。

先将dir1目录移动回playground目录。

mv dir2/dir1 .

再将dir1目录中的fun文件移动回playground目录。

 mv dir1/fun . 

最后,我们尝试创建一些硬链接和软链接,先来创建三个硬链接。

ln fun fun-hard
ln fun dir1/fun-hard
ln fun dir2/fun-hard

查看当前工作目录

total 16
drwxr-xr-x 2 root root 4096 Feb 25 17:12 dir1
drwxr-xr-x 2 root root 4096 Feb 25 17:12 dir2
-rw-r--r-- 4 root root  964 Feb 25 16:03 fun
-rw-r--r-- 4 root root  964 Feb 25 16:03 fun-hard

可以注意到,文件funfun-hard的第二个字段都是4,这表示的是文件fun存在的硬链接数目。由于文件的文件名是由链接创建的,因此一个文件至少有一个链接。实际上,文件funfun-hard是同一个文件。 对于一个文件来说,其包含两部分:包含数据内容的数据部分和包含文件名的名称部分。创建硬链接实际上是创建了文件额外的名称,不同链接指向的是同一数据。Linux系统分配了一系列的盘块给所谓的索引节点,该节点随后与文件名称部分建立联系。因此,每个硬链接都是指向包含文件内容的具体节点

我们可以通过在ls上增加-i选项查看文件的索引节点,若两文件索引节点相同,则表示两文件是同一文件。执行以下命令。

ls  -li

查看结果,观察第一个字段,可以确定,文件funfun-hard是同一个文件。

total 16
1048614 drwxr-xr-x 2 root root 4096 Feb 25 17:12 dir1
1048615 drwxr-xr-x 2 root root 4096 Feb 25 17:12 dir2
1048616 -rw-r--r-- 4 root root  964 Feb 25 16:03 fun
1048616 -rw-r--r-- 4 root root  964 Feb 25 16:03 fun-hard

接下来,我们来创建软链接。

ln -s fun fun-sym
ln -s ../fun dir1/fun-sym
ln -s ../fun dir2/fun-sym

第一个命令,相当直接,通过在ln命令添加-s选项我们创建了软链接,至于第二、第三个命令同样也是创建软链接。我们查看一下dir1目录的文件和子目录。

total 4
-rw-r--r-- 4 root root 964 Feb 25 16:03 fun-hard
lrwxrwxrwx 1 root root   6 Feb 25 17:35 fun-sym -> ../fun

通过文件信息第一个字段的首字符,可以判断fun-sym的列表是一个链接文件,并且其指向../fun。相对于fun-sym文件来说,fun文件是其上级目录playground下的文件,因此,这个写法是正确的。同时注意到,软链接文件的长度是6,代表的是../fun字符串中字符的数目,而不是它所指向的文件的长度。

提示

创建软链接时,可以使用绝对路径,也可以使用相对路径。因为相对路径允许包含软链接的目录被重命名或移动,而且不会破坏链接。因此更适宜使用相对路径。

最后,我们来清理playground目录,我们先删除硬链接fun-hard

rm fun-hard

查看playground目录下的文件和目录信息

total 12
drwxr-xr-x 2 root root 4096 Feb 25 17:35 dir1
drwxr-xr-x 2 root root 4096 Feb 25 17:36 dir2
-rw-r--r-- 3 root root  964 Feb 25 16:03 fun
lrwxrwxrwx 1 root root    3 Feb 25 17:33 fun-sym -> fun

比较上面的结果,文件fun的链接数由4变成了3,硬链接数减少了1。我们再删除文件fun,此时符号链接还存在,只是其指向的文件已经不存在了,链接被破坏。我们删除链接。

rm fun-sym

最后一步,我们切换到主目录,使用rm命令的-r选项删除playground目录以及包括子目录在内的所有内容。

rm -r playground

到这里为止,我们初步了解了操作文件和目录的相关命令。

# 第五章 命令的使用

在上面的章节中,我们学习了多个命令。在本章节,我们将进一步了解命令,揭开命令神秘的面纱。

# 命令的含义

在Linux中,一条命令无外乎下面四种情况:

  • 可执行程序:可执行命令就像在\usr\bin目录里所看到的所有文件一样。在该程序类别中,程序可以编译成二进制文件,比如C 、C++语言编写的程序,也可以是shell、Perl、Python、Ruby等脚本语言编写的程序。
  • shell内置命令:bash支持许多在内部被称之为shell builtin的内置命令。例如:cd命令就是shell内置命令。
  • shell函数:shell函数是合并到环境变量中的小型shell脚本。
  • alias命令:我们可以在其它命令的基础之上定义自己的命令。

# type-显示命令的类型

type命令是一个shell内置命令,可根据指定的命令名显示shell将要执行的命令类型,其格式如下:

type commond

这里的commond是想要查看的命令名。我们先来查看一下type命令的类型。

type type 

可以看到,终端返回如下信息。

type is a shell builtin

这表明type命令是一个shell内置命令。我们再查看一下ls命令。

type ls

此时,终端返回如下信息

ls is aliased to `ls --color=auto'

我们注意到,ls命令其实是带有--color=auto选项的ls命令的别名。

# which-显示可执行程序的位置

有时候,系统中可能安装一个可执行程序的多个版本,这种情况在大型服务器中尤其常见。使用which命令可以确定一个给定可执行文件的准确位置。

我们查看一下ls命令可执行文件的准确位置。

which ls

执行命令,输出如下结果。

alias ls='ls --color=auto'
        /bin/ls

可以看到,使用ls命令实际执行的是bin目录下的ls程序。

TIP

which命令只适用于可执行程序,而不适合内置命令和命令别名(真正可执行程序的替代物),若试图在shell内置命令(例如:cd命令)中使用which命令,要么没有响应,要么返回错误信息。

下面,我们来验证一下这个说法。

which cd

此时,终端返回错误信息。

/usr/bin/which: no cd in (/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/java/jdk1.8.0_181/bin:/bin:/bin:/bin:/usr/local/bin:/bin:/root/bin)

在了解命令的含义后,我们学习每一类命令的使用文档。

# help-获取shell内置命令的帮助文档

bash为每一个shell内置命令提供了一个内置的帮助工具。其使用方式如下:

help commond

我们尝试一下

help cd 

此时,终端输出如下信息

	cd: cd [-L|-P] [dir]
	 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
        -P      use the physical directory structure without following symbolic
        links
    
    The default is to follow symbolic links, as if `-L' were specified.
    
    Exit Status:
    Returns 0 if the directory is changed; non-zero otherwise.

该命令语法描述说明,cd命令后可能跟一个-L-P参数,甚至可以跟参数dir

命令语法描述规则

命令语法描述中的方括号表示这是一个可选的选项,竖线符号代表的是两个互斥的选项。

# help选项-显示可执行命令的使用信息

很多可执行命令都支持--help选项,--help选项描述了命令支持的语法和选项。我们查看一下mkdir命令的语法和支持的选项。

mkdir --help 

此时,终端返回如下信息。

Usage: mkdir [OPTION]... DIRECTORY...
Create the DIRECTORY(ies), if they do not already exist.

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
  -Z, --context=CTX  set the SELinux security context of each created
                      directory to CTX
      When COREUTILS_CHILD_DEFAULT_ACLS environment variable is set, -p/--parents
      option respects default umask and ACLs, as it does in Red Hat Enterprise Linux 7 by default
            --help     display this help and exit
      --version  output version information and exit

Report mkdir bugs to bug-coreutils@gnu.org
GNU coreutils home page: <http://www.gnu.org/software/coreutils/>
General help using GNU software: <http://www.gnu.org/gethelp/>
For complete documentation, run: info coreutils 'mkdir invocation'

一些程序不支持--help选项,使用该选项可能会返回一条错误信息。

# man-显示程序的手册页

Linux提供了详细的称为mannual或man的手册供我们查询命令,我们可以通过man命令阅读它。man命令的格式如下所示:

man commond

这里的commond是需要查看的命令名称。

TIP

手册文档在格式上会有所不同,但是通常都包括标题、命令句法的摘要、命令用途的描述、命令选项列表以及每个命令选项的描述。但是,手册文档通常不包括实例,更多地是作为参考使用,而不是教程。

现在,我们尝试使用一下

man ls

执行命令,我们将得到命令名称,命令格式、命令选项及其选项描述等重要信息。

在大多数Linux系统中,man命令通过调用less命令来显示手册文档,所以,当显示手册文档时,可以使用熟悉的less命令。

man命令显示的手册文档不仅包括用户命令,也包括系统管理命令、程序接口、文件格式等。

部分 内容
1 用户命令
2 内核系统调用的程序接口
3 C库函数程序接口
4 特殊文件,如设备节点和驱动程序
5 文件格式
6 游戏和娱乐
7 其他杂项
8 系统管理命令

有时候我们需要查看手册文档的具体部分,以查找我们所需要的信息。尤其当我们所查找的一个文件格式同时也是一个命令名的时候,就尤为重要了。若我们没有指明要查找的编号,通常会获得第一次匹配的实例。我们可以使用如下格式的man命令通过数字指定范围查找相关信息:

man section search_term

例如,我们执行如下命令

man 5 passwd

该命令将会显示文件/ect/passwd的文件格式描述手册。

# apropos-搜索合适的命令

有时候,我们希望通过关键字搜索手册信息,那么我们可以用apropos命令,其格式如下所示:

apropos floppy

执行命令,显示如下信息

fdformat             (8)  - Low-level formats a floppy disk
floppy               (8)  - format floppy disks

其中,第一个字段是手册页的名称,第二个字段显示的是该信息所属手册的部分信息。注意,带有-k选项的man命令和apropos在功能上是一致的

# whatis-显示命令的简要描述

whatis命令可以帮助我们快速了解匹配具体关键字的手册页名字和一行描述。其格式如下:

whatis commond

现在,我们可以使用whatis命令查看ls命令的描述信息。

whatis ls

执行命令,我们得到以下信息

ls  (1)  - list directory contents

可以看到,输出简要指出了ls命令的作用是列出目录内容。若我们只想知道一个命令的作用,可以直接使用whatis命令即可。

# info-显示程序的info条目

GNU项目提供了info页面来代替手册文档。info页面使用了超链接,其文件是一个树形结构,分为各个单独的节点,每个节点包含一个主题。info文件包含的超链接可以实现节点间的跳转。通过前置星号可以识别超链接,将光标放在超链接上并按Enter即可激活它。它的格式如下所示:

info commond

在上面的格式中,commond是可选的。当我们使用info打开info页面时,可以使用以下命令进行控制。

命令 功能
? 显示命令帮助
Page Up 返回上一页
Page Down 翻到下一页
n 显示下一个节点
p 显示上一个节点
u 显示目前显示节点的父节点
Enter 进入光标所指的超链接
q 退出

# 定义和删除别名

# alias-查看与自定义命令别名

在前面的章节中,我们使用了多个命令来获取命令的信息。在本章节中,我们尝试使用alias命令自定义命令, 在学习自定义命令之前,我们学习一个命令行技巧:通过使用分号来分隔多条命令,使多条命令输入在一行中。其格式如下:

commond1;commond2;commond3...

我们尝试一下这个技巧

cd /usr;ls;cd -

执行命令,该命令成功执行并返回切换之前所在的工作目录。

现在,我们尝试将上述命令组合成一条命令,将其命名为test命令,为了保险起见,我们使用type命令测试一下test命令是否已经被使用了。

type test

执行命令

test is a shell builtin

可以看到,该条命令已经被占用了,因此,我们只能将组合命令定义为其它名字,比如foo

 alias foo='cd /usr;ls;cd -'

观察这个结构,我们得出了指定命令别名的一般格式

alias name ='string'

其中,alias是定义命令别名的关键字,name是别名的名称,后面紧接着一个等号(没有空格),等号后面是一个用单引号括起来的字符串,这个字符串代表了一个或多个命令的组合。

当然,若我们需要查看在环境中定义的所有别名,直接执行不带参数的alias命令即可。

alias cp='cp -i'
alias foo='cd /usr;ls;cd -'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

# unalias-删除命令别名

若我们在定义别名之后,想要删除定义的别名,可以使用unalias命令进行删除操作。其格式如下:

unalias commond

# 第六章 重定向

本章我们来讨论Linux最酷的功能—I/O重定向,I/O重定向是输入/输出的缩写。这个功能可以分为两部分。

  • 输入重定向:把命令行的输入重定向为从文件中获取内容
  • 输出重定向:把命令行的输出结果重定向到文件中。

如果我们将多个命令行关联起来,将形成非常强大的命令-管道。

# 标准输入、输出和标准错误

到目前为止,我们使用过的许多程序生成了多种不同的输出,这些输出包含两种类型。

  • 第一种类型是程序运行的结果,表示该程序生成的数据。
  • 第二种类型是状态和错误信息,表示程序当前的运行情况。

与Unix“一切都是文件”的思想一致,类似ls的程序实际上将它们的运行结果发送到一个称为标准输出的特殊文件中,它们的状态信息则发送到另一个称为标准错误的文件中。默认情况下,标准输出和标准错误都被链接到屏幕上,并且不会保存在磁盘文件中

另外,许多程序从一个称为标准输入的设备来得到输入。默认情况下,标准输入连接到键盘

I/O重定向功能可以可以改变输出内容发送的目的地,也可以改变输入内容的来源地。通常来说,输出内容显示在屏幕上,输入内容来自于键盘。

# I/O重定向-标准输出重定向

I/O重定向功能可以重新定义标准输出内容发送到哪里。使用重定向操作符">",后面接文件名,就可以把标准输出重定向到另一个文件中。

output > file

它主要的作用用于把命令的输出内容保存到一个文件中。我们尝试执行下面一条命令

ls -l /usr/bin > ls-output.txt

这里,我们将/usr/bin的长列表信息输出到ls-output.txt文件中。检查该命令被重定向的输出内容。

ls -l ls-output.txt

如果使用less命令查看这个文件,可以看到该文件确实包含了ls命令的执行结果。

若我们将目录换成一个不存在的目录,则屏幕上会显示错误信息,却不会输出到ls-output.txt文件中。因为ls命令并不会将它运行的错误信息输出到标准输出文件中。

ls -l /bin/usr > ls-output.txt

此时,我们再用ls命令查看该文件信息,发现该文件大小为0。这是因为当我们重定向标准输出时,目的文件通常会从文件开头部分重新改写。

  1. 清空文件内容或创建空文件

若我们需要清空文件内容或创建空文件,我们可以使用如下命名

> ls-output.txt

仅仅使用了重定向符,并在它之前不加任何命令,就可以删除一个已存在的文件内容或创建一个新文件。

  1. 重定向输出追加在已存在文件内容尾部

若我们不希望重定向输出覆盖已经存在的文件内容,则可以使用重定向符“>>”来实现

ls -l /usr/bin >> ls-output.txt

使用这个重定向符“>>”将输出内容添加在文件尾部。如果这个文件不存在,则将于操作符">"的作用一样创建这个文件。

# I/O重定向-标准错误重定向

标准错误重定向并不能用一个专用的重定向符来实现。要实现标准错误重定向,需要使用文件描述符。一个程序可以把生成的内容发送到任意文件流中,如果把这些文件流的前三个分别对应标准输入文件、标准输出文件、标准错误文件。那么shell将在内部用文件描述符分别索引它们为0、1、2。

shell提供了使用文件描述符来重定向文件的表示法。 因此,使用下面表示法来重定向标准错误输出。

 ls -l /bin/usr 2> ls-error.txt

查看文件ls-error.txt,可以看到该命令输出的错误信息。

注意:文件描述符2紧跟在重定向符之前

# 标准输出、标准错误重定向输出到同一个文件

在许多情况下,我们需要将一个命令的所有输出放到同一个文件中。此时,我们必须同时重定向标准输出和标准错误。有两种表示法可以使用。

  • 第一种表示法:
ls -l /bin/usr > ls-output.txt 2>&1

这是一种传统的表示法,使用这个方法,将执行两个重定向操作。手续将重定向标准输出到文件ls-output.txt文件中,然后使用2>&1把文件描述符2(标准错误)重定向到文件描述符1(标准输出)中。

  • 第二种表示法:

这种表示法提供了更为简洁的方法

ls -l /bin/usr &> ls-output.txt

在这个例子中,注意“&>”标记符就把标准输出和标准错误都重定向到了文件ls-output.txt中。

# 位桶-抑制或隐藏不想要的输出

若我们在命令执行后不希望得到输出,而是将输出丢弃,则可以把输出重定向到一个称为“/dev/null”的特殊文件来实现它。这个特殊文件称为“位桶”。

位桶

这个设备接受输入,但是不对输入进行任何处理。

以下命令用来抑制或隐藏一个文件的错误信息。

ls -l /bin/usr 2> /dev/null

# cat-合并、查看、创建文件以及重定向

  1. cat-读取或合并文件

对于cat命令来说,不同参数,产生的结果并不一样。

  1. cat命令读取文件

cat命令读取一个或多个文件,并把它们复制到标准输出文件中,格式如下:

cat [file...]

我们可以使用它显示文件而不需要分页, 通过以下命令,我们可以查看文件ls-output.txt

 cat ls-output.txt
  1. cat命令合并多个文件

由于cat可以接受多个文件作为参数,所以它可以用来将文件合并在一起。

例如,我们需要将多个movie.mpeg.01、movie.mpeg.02......合并为一个文件movie.mpeg。

则我们可以使用如下命令

cat movie.mpeg.* > movie.mpeg

通过这个命令,我们可以将多个文件合并为一个文件movie.mpeg。

  1. cat命令获取键盘输入

当然,我们可以使用不带参数的cat命令,从标准输入中读取内容。

cat

由于标准输入在默认情况下是连接到键盘,所以它实际上将等待着从键盘输入内容。下一步,我们可以使用组合键ctrl D,告知cat命令已经达到了标准输入的文件尾。

在缺少文件名参数的情况下,cat命令将把标准输入内容复制到标准输出文件,所以我们会看到文本行重复显示。

  1. cat命令创建新文件

若我们希望将键盘输入的信息输出重定向到文件中,则可以在cat命令后输入想要放到文件中的内容。当文本内容输入结束时,则按组合键ctrl D结束。

 cat > lady_dog.txt
the document for lady_dog.txt
  1. cat命令重定向输入源

现在,我们知道cat命令除了接受文件名参数之外,还可以重定向标准输入源,其格式如下

cat < lady_dog.txt

使用重定向符"<",我们将把标准输入的源从键盘变为文件lady_dog.txt。可以看到这个命令结果和只传递单个文件参数名的结果一样,这种方式并不常用。

# |-管道操作符 && 过滤器

命令从标准输入到读取数据,并将数据发送到标准输出的能力,是使用了名为管道的shell特性。使用管道操作符"|"(竖线)可以把一个命令的标准输出传送到另一个命令的标准输入中。 其命令格式如下:

commond1 | commond2

在前面提到的命令中,less命令可以接受标准输入。通过less命令可以分页显示任意命令的输入,并将它的结果发送到标准输出。

ls -l \usr\bin | less

管道功能常常用来对数据执行复杂的操作。可以将多个命令合并在一起构成一个管道,这种方式中用到的命令通常称为过滤器(filter)。 过滤器接受输入,按照某种方式对输入进行改变,然后再输出。

ls /bin /usr/bin | sort | less

该命令可以把/bin和/usr/bin目录下的所有可执行文件合成一个列表,并按照顺序排列。

# uniq-报告或忽略文件中重复的行

uniq命令经常和sort命令结合使用。uniq命令可以接受来自于标准输入或者一个单一文件名参数对应的已排好序的的数据列表。默认情况下,该命令删除列表中的所有重复行。 因此,在管道中添加uniq命令,可以确定所有的列表都没有重复行。

ls /bin /usr/bin | sort | uniq | less

若我们想要查看重复行的列表,可以在uniq命令后面添加-d选项。

ls /bin /usr/bin | sort | uniq -d | less

# wc-打印行数、字数和字节数

在Linux中,我们可以使用wc命令用来显示文件中包含的行数、字数和字节数。现在,我们查看文件ls-output.txt的行数、字数、字节数信息。

  1. 获取文件的行数、字数、字节数
wc ls-output.txt

执行这个命令,可以得到以下信息

 1  9 54 ls-output.txt

这三个数据分别代表行数、字数和字节数。

  1. 获取标准输入输出行数、字数、字节数

和前面的命令一样,若我们在执行命令时没有输入输出命令行参数,则它将接受标准输入内容。

wc
  1. 单独获取文件的行数

若我们只想获取文件的行数,则只需要带一个-l参数即可。

ls /bin /usr/bin | sort | uniq | wc -l

执行命令,输出行数数据

763

wc命令常用的参数选项

选项 意义
-c 统计字节数
-l 统计行数
-m 统计字符数,这个标志不能与 -c 标志一起使用。
-w 统计字数,一个字被定义为由空白、跳格或换行字符分隔的字符串。
-help 显示帮助信息

# grep-打印文本中的匹配行

grep是一个功能强大的程序,它用来在文件中查找匹配文本,其方式如下:

grep pattern [file...]

grep命令在文件中遇到“模式”的时候,将打印出包含该模式的行。

ls /bin /usr/bin | sort | uniq | grep zip

通过上面这条命令,我们可以从列出的程序中搜索出文件名中包含zip的所有文件,该搜索将获得系统中与文件压缩相关的程序。

grep

grep存在一对方便的选项,-i,该选项使得grep在搜索时忽略大小写,默认情况下,搜索是区分大小写的;-v,该选项只输出和模式不匹配的行。

# head/tail-打印文件的开头部分/结尾部分

有些时候,我们不需要命令输出所有的内容,可能只是需要开头几行或最后几行。默认情况下,head命令将输出文件的前10行,tail命令输出文件的后10行。可以用-n选项指定输出的行数。

  1. head/tail命令基本用法

首先,我们输出文件内容的前5行

 head -n 5 ls-output.txt

输出如下结果

total 60M
-rwxr-xr-x 1 root root     41K Oct 31  2018 [
-rwxr-xr-x 1 root root     29K Oct 30  2018 addr2line
-rwxr-xr-x 1 root root      29 Oct 31  2018 alias
lrwxrwxrwx 1 root root       6 Jan 29 04:54 apropos -> whatis

其次,我们输出文件内容的后5行

tail -n 5 ls-output.txt

输出如下结果

-rwxr-xr-x 1 root root    6.0K Apr 11  2018 zgrep
-rwxr-xr-x 1 root root    2.0K Apr 11  2018 zless
-rwxr-xr-x 1 root root    2.8K Apr 11  2018 zmore
-rwxr-xr-x 1 root root    5.3K Apr 11  2018 znew
lrwxrwxrwx 1 root root       6 Jan 29 04:52 zsoelim -> soelim

当然,我们也可将这两个命令用在管道中

ls /usr/bin | tail -n 5

输出如下结果

zgrep
zless
zmore
znew
zsoelim
  1. tail命令实时查看文件

值得注意的是,tail有一个选项-f可以实时查看文件,其命令格式如下:

tail -f fileName

它会把文件里的最尾部的内容显示在屏幕上,并且不断刷新,只要更新就可以看到最新的文件内容。当我们按ctrl+C时才会停止刷新。

# tee-从标准输入读取并输出到标准输出和文件

为了和我们的管道隐喻保持一致,Linux提供了一个称为tee的命令,就好像安装了一个“T”在管道上。tee程序读取标准输入,再把读到的内容复制到标准输出(允许数据可以继续传递到管道中)和一个或更多文件中去。

可用于在某个中间处理阶段来捕获一个管道中的内容时,会很有用。

ls /usr/bin | tee ls.txt | grep zip

输出结果如下

gpg-zip
gunzip
gzip

通过上面这个命令,我们使用tee命令获取了整个目录列表并输出到文件ls.txt中。

# 第七章 透过Shell看世界

在本章中,我们学习一个重要的命令echo,这个命令用来显示一行文本。

现在,我们来看看echo命令,echo命令是shell的一个内置命令,它执行的任务非常简单,即把文本参数内容打印到标准输出。

我们执行以下命令

echo this is a test

结果输出上面输入的字符串。

现在,我们执行命令

echo *

这时,我们看到命令执行的结果不是*,这是因为shell在执行echo命令前会把*字符扩展成其它内容。在按下Enter键的时候,shell会在执行命令前自动扩展命令行中所有符合条件的字符,因此,我们无法看到程序打印输出*字符,而是输出以下内容。

anaconda-ks.cfg lady_dog.txt ls-error.txt ls-output.txt ls.txt original-ks.cfg

对于Linux来说,Linux存在多种扩展。

# 路径名扩展

通过使用通配符来实现扩展的机制称为路径名扩展。我们来看下面这个命令,这个命令用于查看除主目录之外的目录。

echo /usr/*/share

结果输出如下

/usr/local/share

# 波浪线扩展

我们回顾前面对cd命令的介绍,你会发现波浪线(~)具有特殊的含义。如果把它(~)用在一个单词的开头,那么它将被扩展为指定用户的主目录;如果没有指定用户名,则扩展为当前用户的主目录。

echo ~

由于没有指定用户,而且当前时root账户,则打印出root账户的主目录/root

/root

若存在用户foo这个账号,则可以执行下面这个命令获得foo账号的主目录

echo ~foo

执行结果为/home/foo。

# 算术扩展

除了上面两种扩展外,shell还支持通过扩展来运行算术运算符,这允许我们将shell当作计算器来使用。

算术扩展使用如下格式

$((expression))

其中,expression代表的是指包含数值和算术运算符的算术表达式,并且算术扩展只支持整数,没有小数。因此,若我们需要执行2+2,则命令可以如下这样写。

 echo $((2+2))

不出所料,输出运算结果4

下面,我们罗列出echo支持的运算符种类。

运算符 描述
+ 算术加
- 算术减
* 算术乘
/ 除,由于只支持整数,所以结果也只会是整数
% 取余,即取余数
** 取幂

现在,我们看看5/2的结果

 echo Five divided by two equals $((5/2))

执行命令,结果输出2

# 花括号扩展

在shell中,存在一种特殊的扩展,通过花括号扩展,我们可以创建多种文本字符串。例如下面这个例子

echo Front-{A,B,C}-Back

通过这个例子,我们可以输出三个字符串,Front-A-Back、Front-B-Back和Front-C-Back。

用于花括号扩展的模式信息可以包含一个称为前导字符的开头部分和一个称为附言的结尾部分。当然,花括号表达式除了可以包含一系列逗号分隔的字符串外,也可以包含一系列整数或单个字符,但不能包含空白。

  1. 生成一系列整数
echo Number_{1..5}

输出结果如下

Number_1 Number_2 Number_3 Number_4 Number_5
  1. 生成一系列逆序排列的字母
echo {Z..A}

输出结果如下

Z Y X W V U T S R Q P O N M L K J I H G F E D C B A
  1. 批量生成多个目录
mkdir {2009..2011}-0{1..9} {2009..2011}-{10..12}

若没有错误,将如愿批量生成类似2009-01的多个目录。

# 参数扩展

在Linux中,参数扩展用在shell脚本中比直接用在命令行中更有用。例如:在Linux中,使用变量USER表示用户。为了显示变量USER的值,我们使用echo命令。

echo $USER

执行命令,输出用户名root

当然,USER变量只是众多可用变量中的一个,若要查看可用变量列表,则执行命令

printenv | less

输出的部分结果如下

SHELL=/bin/bash
TERM=xterm-256color
HISTSIZE=1000
WSLENV=
USER=root
NAME=LAPTOP-2ESIRNKO

对于其它扩展来说,若是输入了错误的模式,则不会发生扩展,而对于参数扩展则不同,若发生错误,则仍然会扩展,只是扩展的结果是一个空字符串。

# 命令替换

所谓的命令替换指的是,将一个命令的输出作为一个扩展模式使用,例如下面这个例子。

echo $(ls)

整个命令将列出ls命令执行的结果

anaconda-ks.cfg lady_dog.txt ls-error.txt ls-output.txt ls.txt original-ks.cfg

当然,我们也可以这样用

ls -l $(which cd)

这里,我们将which cd命令的运行结果作为ls命令的一个参数,这样我们在不知道cd命令完整路径的情况下就能获得cd命令程序对应的列表。

当然,我们也可以用于管道,下面的例子将输出file命令的参数列表

 file $(ls /usr/bin/* | grep zip)

结果我们得到了如下信息

/usr/bin/gpg-zip: POSIX shell script, ASCII text executable
/usr/bin/gunzip:  POSIX shell script, ASCII text executable
/usr/bin/gzip:    ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=526d77ff7164870f948d8f97aaf0a888cc561b30, stripped

在早期的shell命令中,我们还存在另外一种命令替换格式,它用反引号(即`)代替美元符号和括号

ls -l `which cd`

# 各种类型的引用

在讲引用之前,我们先来看这样一个例子

 echo The total is $100.00

在这个例子中,$1是一个未定义的变量,所以参数扩展将把$1的值替换为空字符串。shell提供了一种称为引用的机制,用来有选择性地避免不必要的扩展。

引用可以分为双引号、单引号、转义字符三种

  • 双引号:如果把文本放在双引号中,那么shell使用的所有特殊字符都将失去它们的特殊含义,而被看成普通字符。当然“$” 、""、“`”除外。这也就意味着单词分割、路径名扩展、波浪线扩展和花括号扩展都将失效,但是参数扩展、算术扩展和命令替换仍然有效。使用双引号能够处理文件名中包含空白的情况。

    由于参数扩展、算术扩展和命令替换在双引号内仍然有用,那么我们输入下面命令可以正常运行。

    echo "$USER $((2+2)) $(cal)"
    

    运行结果如下

    root 4       July 2019
    Su Mo Tu We Th Fr Sa
        1  2  3  4  5  6
     7  8  9 10 11 12 13
    14 15 16 17 18 19 20
    21 22 23 24 25 26 27
    28 29 30 31
    

    默认情况下,若没有双引号,单词分割会先查找是否存在空格、制表符以及换行

    echo this is a   test
    

    输出结果this is a test,但是如果使用了双引号,则会将这些符号当成参数的一部分

    this is a   test
    

    单词分割机制会把换行符当成界定符,在命令替换时有不同的效果

     echo "$(cal)"
    

    输出结果为

          July 2019
    Su Mo Tu We Th Fr Sa
        1  2  3  4  5  6
     7  8  9 10 11 12 13
    14 15 16 17 18 19 20
    21 22 23 24 25 26 27
    28 29 30 31
    

    而若是执行命令echo $(cal),则获得如下输出结果

    July 2019 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
    

    在第一个例子中,由于加了双引号,使得命令行被识别为命令后面只跟着一个参数,这个参数包含着嵌入空格和换行字符;而在第二个例子,没有加上引号的命令替换将导致命令行被识别为命令后面跟着38个参数。

  • 单引号:如果我们希望抑制所有的扩展,那么应该使用单引号。下面是使用单引号的情况

    echo '$USER $((2+2)) $(cal)'
    

    与双引号的运行结果不同,echo命令将其当作普通字符串输出

    $USER $((2+2)) $(cal)
    
  • 转义字符:有时候我们只想要引用单个字符,这种情况可以通过在该字符前加上反斜杠来实现。这里的反斜杠称为转义字符转义字符经常在双引号中用来有选择性地阻止扩展。

    echo "The balance for user $USER is:\$100.00"
    

    得到结果

    The balance for user root is:$100.00
    

    如果想要显示反斜杠字符,可以通过使用两个反斜杠“\”来实现。需要注意的是,单引号中的反斜杠将失去它的特殊意义,而只是被它当成一个普通字符。

    echo 'The balance for user $USER is:\$100.0'
    

    运行该命令,可以看到“\”只是被当成一个普通字符。

    The balance for user $USER is:\$100.0
    

# 第八章 高级键盘技巧

在本章,我们学习一些键盘快捷键,尽量减少键盘和鼠标之间的切换,提高工作效率。

# 光标移动快捷键

组合键 作用
Ctrl-A 移动光标到行首
Ctrl-E 移动光标到行尾
Ctrl-F 光标向前移动一个字符,相当于右箭头键
Ctrl-B 光标向后移动一个字符,相当于左箭头键
Alt-F 光标向前移动一个字
Alt-B 光标向后移动一个字
Ctrl-L 清屏并把光标移到左上角,clear命令与此效果相同

# 修改文本快捷键

组合键 作用
Ctrl-D 删除光标处的字符
Ctrl-T 光标处字符和前面的字符对调
Alt-T 光标处字和前面的字对调
Alt-L 把从光标处到字尾的字符转换为小写字母
Alt-U 把从光标处到字尾的字符转换为大写字母

# 剪切、粘贴文本快捷键

组合键 作用
Ctrl-K 剪切光标到行尾的文本
Ctrl-U 剪切光标到行首的文本
Alt-D 剪切从光标到当前词尾的文本
Alt-BackSpace 剪切从光标到词头的文本,如果光标在一个单词的开头,则剪切前一个单词
Ctrl-Y 把kill-ring缓冲区中的文本粘贴到光标位置

# Tab键-自动补齐

shell提供了一种称为“自动补齐”的机制为用户提供输入帮助。当用户输入命令时,可以按下Tab键,

  • 若符合条件的提示是唯一的,则shell会自动补齐。

  • 若是满足条件的提示存在多个,再按一次Tab键,shell将若列出所有可能的结果。

为了更好说明这个功能,我们查看一下主目录下的文件

total 68
-rw------- 1 root root  6921 Jan 29 05:02 anaconda-ks.cfg
-rw-r--r-- 1 root root    29 Jul 23 22:55 lady_dog.txt
-rw-r--r-- 1 root root    54 Jul 23 21:40 ls-error.txt
-rw-r--r-- 1 root root 41164 Jul 24 09:58 ls-output.txt
-rw-r--r-- 1 root root  6916 Jul 24 10:32 ls.txt
-rw------- 1 root root  6577 Jan 29 05:02 original-ks.cfg

若我们输入命令ls l,按下Tab键,自动补齐将不会生效,因为有多个满足以l开头的文件,我们再按一次Tab,将罗列出所有可能的结果。

lady_dog.txt   ls-error.txt   ls-output.txt  ls.txt

我们继续输入,知道满足条件的结果唯一时,自动补齐将生效。

因此,当我们输入命令时,若按Tab键后没有自动补齐,则可能的原因是满足条件的结果有多个,可以再按一下Tab键,shell将列出所有可能的结果。

自动补齐功能最常用于路径名补齐上,除此之外,自动补齐对变量、用户名、命令和主机名也起作用,主机名的自动补齐只对\etc\hosts目录下的主机名生效。

# history-搜索历史

在Linux Bash中,会保存使用过命令的历史记录。这些命令的历史纪录列表保存在用户主目录的.bash_history文件中。这些历史记录非常有用,可以大大减少用户敲打键盘的次数,通过向上方向指示键,可以重新调用先前输入的命令。

任何情况下,我们都可以通过如下命令查看历史记录的内容列表。

history | less

bash默认会保存用户最近使用过的500个命令。 其中,500是默认值。

  1. 使用grep命令搜索历史记录

若我们想要查询包含/usr/bin的命令,则可以结合前面的grep命令查询符合条件的历史记录。

history | grep /usr/bin

执行命令,获得如下记录

   20  ls -l /usr/bin > ls-output.txt
   27  ls -l /usr/bin > ls-output.txt
   40  ls -l /usr/bin >> ls-output.txt
   44  ls -l /usr/bin >> ls-output.txt
   50  ls -l /usr/bin > ls-output.txt 2>&1
   64  ls /bin /usr/bin | sort | less
   65  ls /bin /usr/bin
   66  ls -l /bin /usr/bin
   67  ls /bin /usr/bin | sort | uniq | less
   68  ls /bin /usr/bin | sort | uniq -d | less
   69  ls /bin /usr/bin | sort | uniq -d
   70  ls /bin /usr/bin | sort | uniq
   78  ls /bin /usr/bin | sort | uniq | wc -l
   80  ls /bin /usr/bin | sort | uniq | grep zip
   81  ls /bin /usr/bin | sort | uniq | grep -v zip
   82  ls /bin /usr/bin | sort | uniq | grep -iv zip
   83  ls /bin /usr/bin | sort | uniq | grep -iv zip | wc -l
   84  ls /bin /usr/bin | sort | uniq | grep -iv zip | head
   85  ls /bin /usr/bin | sort | uniq | grep -iv zip | head -n 30
   87  ls -lh /usr/bin > ls-output.txt
   92  ls /usr/bin | tail -n 5
   94  ls /usr/bin | tee ls.txt
   95  ls /usr/bin
   96  ls /usr/bin | tee ls.txt | grep zip
  121  file $(ls /usr/bin/* | grep zip)
  204  history | grep /usr/bin
  1. 执行特定行数的历史命令

这些记录最开始的数字代表了这个命令行在历史记录列表中所处的行号,我们可以通过使用名为历史记录扩展的扩展类型来立即使用它。例如我们想执行92行的命令,可以使用命令!92执行92行命令。

!92
  1. 使用快捷键搜索历史记录

bash支持以递增的方式搜索历史记录。也就是说,当搜索历史记录时,随着输入字符数的增加,bash也会相应地改变搜索范围。

下面是使用快捷键搜索历史记录的详细步骤

1. 首先,按下Ctrl-R键,接着输入要查找的内容,开始递增式搜索。

2. 然后,当搜索到符合条件的内容,可以按Enter键执行此命令,也可以按Ctrl-J将搜索
到的内容从历史记录列表复制到当前命令行。

3. 若需要查找下一个匹配项(向前搜索历史记录),再次按Ctrl-R键。

4. 若查询到符合的内容,执行2。

5. 若要退出搜索,则按Ctrl-G或Ctrl-C即可。
  1. 历史记录常用快捷键
组合键 作用
Ctrl-P 移动到前一条历史记录,相当于向上箭头键
Ctrl-N 移动到后一条历史记录,相当于向下箭头键
Ctrl-R 逆向递增搜索,从当前命令行向前递增搜索

# 历史记录扩展

shell提供了一种专门用来扩展历史记录项的方式-使用!字符,通过这种历史记录扩展方式,可以更方便地执行历史命令。

序列 行为
!! 重复执行最后一个执行地命令。按向上箭头键再按Enter键也可实现相同的功能
!number 重复历史记录中第number条命令
!String 重复最近以string开头的历史记录
!?String 重复最近包含String的历史记录

# 第九章 权限管理

传统的UNIX操作系统与那些传统的MS-DOS操作系统不同,区别在于它们不仅是多重任务处理系统,而且还是多用户系统。这意味着同一时间内可以有多个用户使用同一台计算机。不同的远程用户可以使用shell在同一时间登录同一台电脑。为了保证多用户实际可用,系统设计了一种方案来保护当前用户不受其它用户操作的影响。

因此,本章将介绍系统安全的基础知识以及相关命令的使用。

# 所有者、组成员和其他所有用户

为了讲述所有者、组成员和其他所有用户这三个概念,需要了解一下UNIX安全模型

在一个UNIX安全模型中,一个用户可以拥有文件和目录。

  • 当一个用户拥有一个文件和目录时,它将对该文件或目录的访问权限拥有控制权。
  • 对于一个用户来说,用户又归属于一个群组,该群组由一个或多个用户组成,组中用户对文件和目录的访问权限由拥有者授予。
  • 除了可以授予群组访问权限之外,文件所有者也可以授予所有用户一些访问权限。

# id-显示用户身份标识

在UNIX系统中,可以使用id命令获得用户身份标识的相关信息。

 id

执行命令,可以获得如下用户信息

uid=1000(shenzx) gid=1000(shenzx) groups=1000(shenzx)

查看id命令的输出结果。可以知道,在创建账户的时候

  • 用户将被分配一个称为用户ID或者uid的号码,而且用户ID与用户名一一映射。
  • 于此同时,用户会被分配一个有效的组ID或者gid,而且该用户也可以属于其它的群组。

类似于Linux中的很多情况,这些信息来自于一系列的文本文件。

  • 用户账号定义在文件\etc\passwd中,对于每一个账号,文件\etc\passwd定义了对应用户的用户名、uid、gid、账户的真实姓名、主目录以及登录shell信息。除了普通用户外,\etc\passwd和\etc\group还有定义超级用户以及起他不同种类的系统用户的账号信息。
  • 用户组定义在文件\etc\group文件中。
  • 在创建用户账号和群组时,这些文件随着\etc\shadow的变动而修改,文件中保存了用户的密码信息。

在Linux中,普通用户会被分配给和账号同名的群组,这使得权限分配更加容易。

# 读取、写入和执行权限

对文件和目录的访问权限是按照读访问、写访问以及执行访问来定义的。

ls -l ls-output.txt

查看运行结果

-rw-r--r-- 1 root root 42955 Jul 26 18:19 ls-output.txt

列在输出结果中的前10个字符表示的是文件属性,其中第一个字符表示文件类型。按照文件的类型分类,可以分为以下几种文件类型。

属性 文件类型
- 普通文件
d 目录文件
l 符号链接。对于符号链接文件来说,剩下的文件属性始终是rwxrwxrwx
它是一个伪属性值,符号链接执行的文件的属性才是真正的文件属性
c 字符设备文件,该文件类型表示以字节流形式处理数据的设备,如终端或调制解调器
b 块设备文件,该文件类型表示以数据块方式处理数据的设备,如硬盘驱动或光盘驱动

文件中剩下的9个字符称为文件模式,分别代表文件所有者、文件所属群组以及其他所有用户对该文件的读取、写入和执行权限。

分别设置r、w、x的模式属性将会对文件和目录带来不同的影响,具体影响看下表。

属性 文件 目录
r 允许打开和读取文件 如果目录还设置了执行权限,则允许使用ls命令列出目录下的文件信息
w 可以使用编辑器修改文件内容,但需要配置r权限一起使用;如果还设置了执行权限,则目录中的文件可以被创建、删除以及重命名 可以创建、删除目录里的文件,也可以删除当前目录
x 允许把文件当作程序一样来执行。用脚本语言写的程序必须被设置为已读,以便能够执行 可以使用cd命令切换此目录为工作目录,但需配合r权限一起使用

# chmod-更改文件模式(权限)

我们可以使用chmod命令来更改文件或目录的文件模式,需要注意的是只有文件所有者和超级用户才可以更改文件或目录的模式。chmod命令支持两种不同的改变文件模式的方法-八进制数字表示法和符号表示法。

首先是八进制表示法。

  1. 八进制表示法

八进制表示法指的是使用八进制数字来设置所期待的权限模式。因为每个八进制数对应3个二进制数,所以这种关系正好可以和用来存储文件模式的结构一一映射。

八进制 二进制 文件模式
0 000 ---
1 001 --x
2 010 -w-
3 011 -wx
4 100 r--
5 101 r-x
6 110 rw-
7 111 rwx

通过使用3位八进制数字,我们可以分别设置文件所有者、组成员、其他所有用户的所有模式。

例如,若我们想设置文件所有者具有读写权限,而取消组用户和其他所有用户的所有权限,则命令如下

chmod 600 ls-output.txt

再次查看文件ls-output.txt的权限,则输入结果

-rw------- 1 root root 42955 Jul 26 18:19 ls-output.txt
  1. 符号表示法

除了上面的八进制表示法之外,chmod还支持符号表示法。该符号表示法分为三部分:更改会影响谁、要执行哪种操作以及设置哪种权限。可以通过字符u、g、o和a的组合来指定要影响的对象。

符号 含义
u user的简写,表示文件或目录的所有者
g 文件所属群组
o others的简写,表示其他所有用户
a all的简写,是u、g、o的三者组合

如果没有指定字符,则表示使用all,操作符“+”表示增加一种权限,“-”表示删除一种权限,“=”表示只有指定的权限可以用,其他所有权限都被删除。权限由字符“r”、“w”、“x”来指定。

下面是一些符号表示法示例

符号 含义
+x 为文件所有者、组成员和其他所有用户添加可执行权限
o-rw 除了文件所有者和所属群组外,删除其他所有用户的读写权限
u+x,go=rw 为文件所有者添加可执行权限,同时设置所属群组和其他所有用户具有读和可写权限,需用都好分隔

相对于八进制表示法,符号表示法的优点在于允许设置单个属性,而不影响其他的任何属性。

# su-以其他用户和组ID的身份来运行shell

su命令用来以另一个用户的身份来启动shell,该命令的一般形式如下:

su [-l] [user]

如果包含“-l”选项,那么将得到的shell会话界面将是用于指定用户的登录shell界面。这意味着,该指定用户的运行环境将被加载,而且其工作目录也将更改为该指定用户的主目录。如果没有指定用户,那么默认假定为超级用户。

  1. 使用超级用户的身份来启动shell

需要注意的是,-l可以缩写为-。因此,我们可以使用以下的命令来以超级用户的身份启动shell。

su -

在输入su命令后,系统会提示输入该超级用户的密码。如果密码输入正确,那么将出现新的shell提示符,该提示符表示该shell将拥有超级用户的特权,而且当前的工作目录也是用于超级用户的主目录。一旦进入这个新的shell环境,我们就可以以超级用户的身份执行命令了。

在使用结束时,输入exit,将返回之前的shell环境。

  1. 使用su命令执行单个命令

我们也可以使用su命令执行单个命令,而不是开启一个新的交互命令界面,操作如下:

su -c 'commond'

使用这种格式,单个命令行将被传递到一个新的shell环境下进行执行。这里需要用单引号把命令行引起来。

su -c 'ls -l /root/*'

运行结果

-rw------- 1 root root 6921 Jan 29 05:02 /root/anaconda-ks.cfg
-rw------- 1 root root    0 Jul 26 22:36 /root/ls-output.txt
-rw------- 1 root root 6577 Jan 29 05:02 /root/original-ks.cfg

sudo-以另一个用户的身份执行命令

sudo命令在许多方面类似于su命令

# susudo命令的几点区别

  1. 对于sudo命令来说,管理者可以通过配置sudo命令,使系统以一种可控的方式,允许一个普通用户以一个不同的身份执行命令。在特定情况下,用户可能被限制只能执行一条或几条特定的命令,而对其他命令没有执行权限。
  2. 使用sudo命令并不需要输入超级用户的密码。使用sudo命令时,用户只需要输入自己的密码来进行认证。一旦认证被通过,指定的命令就会被执行。
  3. sudo命令并不需要启动一个新的shell环境,也不需要加载另一个用户的运行环境。

# chown-更改文件所有者和所属群组

chown命令用来更改文件或者目录的所有者和所属群组。使用这个命令需要超级用户的权限。chown命令的语法格式如下:

chown [owner][:group] file...

chown 命令更改的是文件所有者还是文件所属群组,或者对两者都更改,取决于该命令的第一个参数。

下面是chown命令参数示例

参数 结果
bob 把文件所有者从当前所有者更改为用户bob
bob:users 把文件所有者从当前所有者更改为用户bob,并将其文件所属群组更改为users组
:admins 把文件所属群组更改为admins组,文件所有者不变
bob: 把文件所有者从当前所有者更改为用户bob,并把文件所属群组更改为用户bob登录系统时所属的组

# passwd-修改用户密码

有时候,我们需要修改账号密码,这时候就需要使用命令passwd命令了。一般情况下,我们只能修改当前用户的密码,当然,若是超级用户,则可以修改其他用户的账号密码。 修改密码的一般格式如下:

passwd [user]
  1. 修改用户自己的密码

若是修改自己的密码,则只需要输入输入passwd命令即可,接下来,shell会提示用户输入旧密码和新密码。

  1. 修改其他用户的密码

如果我们拥有超级用户的权限,那么我们就可以修改其他用户的密码。只需要指定一个user参数即可。对于超级用户来说,我们还可以使用该命令的其他选项设置账户锁定、密码失效等功能。

passwd命令会尝试用户使用“强”密码,也就是说它会拒绝接受太简单、太短、与之前相似的密码或者容易猜到的密码。为了安全起见,最好设置复杂一点的密码。

# 第十章 进程信息查看与进程控制

在学习进程信息查看与进程控制命令之前,我们先来了解一下进程的工作方式。

# 进程的工作方式

系统启动时,内核先把它的一些程序初始化为进程,然后运行一个称为init的程序。init程序将依次运行一系列称为脚本初始化的shell脚本(这些脚本在/etc目录下),这些脚本将会启动所有的系统服务。其中的很多服务都是通过守护程序来实现的。而后台程序只是呆在后台做自己的事情。因此,即使没有用户登录,系统也会忙于执行一些例行程序。

内存会保存每个进程的信息以便确保任务有序进行。比如,每个进程将被分配一个称为进程ID的号码。进程ID是按照递增的顺序来分配的,init进程的PID始终为1.内核也记录分配给每个进程的内存信息以及用来恢复运行的进程就绪信息。

有时候计算机运行速度会变慢,或者应用程序会停止响应。本章将介绍命令行中可以用来查看程序当前运行情况以及终止运行异常的进程的一些工具。

# ps-显示当前所有进程的运行情况

用来查看进程信息的命令中,使用最普遍的就是ps命令。

  1. 输出和当前终端会话相关的进程信息

ps命令有很多选项,其中最简单的使用格式如下:

ps

执行命令,输出结果

  PID TTY          TIME CMD
    3 tty1     00:00:00 init
    4 tty1     00:00:00 bash
   26 tty1     00:00:00 ps

默认情况下,ps命令输出的信息不是很多,只是输出和当前终端会话相关的进程信息。其中

  • TTY代表了进程的控制终端,
  • TIME字段表示了进程消耗的CPU时间总和
  1. 反映系统运行情况的视图界面

我们增加一个选项x,我们将被告知所有的进程,而不需要关注它们是由哪个终端所控制的。

ps x

得到输出结果,在输出结果中,TTY列中的出现的“?”表示没有终端。

  PID TTY      STAT   TIME COMMAND
    1 ?        Ss     0:00 /init
    3 tty1     Ss     0:00 /init
    4 tty1     S      0:00 -bash
   27 tty2     Ss     0:00 /init
   28 tty2     S      0:00 -bash
   41 tty2     S      0:00 su shenzx
   57 tty1     R      0:00 ps x

同时在输出结果中还添加了一个名为STAT的新列。SRTAT是state的缩写,显示的是进程的当前状态。对照下表,可以看到进程的状态由好几个。

状态 含义
R 运行状态,进程正在运行或准备运行
S 睡眠状态,进程不在运行。而是等待某事件发生
D 不可终端的睡眠状态,进程在等待I/O操作,如硬盘驱动
T 暂停状态,进程被指示暂停,后续还可继续运行
Z 无效或僵尸状态,子进程被终止,但还没有被其父进程彻底释放掉
< 高优先级进程,进程可以被赋予更多的重要性,分配更多的CPU时间
N 低优先级进程,低优先级进程只有在其他更高优先级的进程使用完之后才能获得使用处理器的时间

这些进程状态的后面可以带其他的字符来表示不同的特殊进程特性。

  1. 显示属于每个用户的进程信息

另外一个常用的选项组合是aux,执行命令

ps aux

输出如下的详细结果

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   8324   156 ?        Ss   11:27   0:00 /init
root         3  0.0  0.0   8328   160 tty1     Ss   11:27   0:00 /init
root         4  0.0  0.0 115664  2048 tty1     S    11:27   0:00 -bash
root        27  0.0  0.0   8328   160 tty2     Ss   14:58   0:00 /init
root        28  0.0  0.0 115664  2040 tty2     S    14:58   0:00 -bash
root        41  0.0  0.0 118768  2188 tty2     S    14:58   0:00 su shenzx
shenzx      42  0.0  0.0 115660  2060 tty2     S    14:58   0:00 bash
root        58  0.0  0.0 119064  2068 tty1     R    15:20   0:00 ps aux

该选项组合会显示属于每个用户的进程信息,各列的含义如下

标题 含义
USER 用户ID,表示该进程的所有者
%CPU CPU使用百分比
%MEM 内存使用百分比
VSZ 虚拟耗用内存大小
RSS 实际使用的内存大小。进程使用的物理内存大小(以KB为单位)
START 进程开启的时间,如果数值超过24小时,那么将使用日期来表示

# top-动态查看进程信息

虽然ps命令可以显示有关机器运行的很多情况,但是它提供的只是ps命令被执行时刻机器状态的一个写照。要查看机器运行情况的动态视图,可以使用top命令查看系统进程的运行情况。

top

top命令将按照进程的活动顺序,以列表的形式持续更新显示系统进程的当前信息(默认每3秒更新一次)。

top - 16:11:15 up  4:43,  0 users,  load average: 0.52, 0.58, 0.59
Tasks:   8 total,   1 running,   7 sleeping,   0 stopped,   0 zombie
%Cpu(s):  4.9 us,  3.9 sy,  0.0 ni, 90.8 id,  0.0 wa,  0.4 hi,  0.0 si,  0.0 st
KiB Mem : 16695540 total, 11518216 free,  4940848 used,   236476 buff/cache
KiB Swap: 13107196 total, 13107196 free,        0 used. 11613836 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0    8324    156    132 S   0.0  0.0   0:00.12 init
    3 root      20   0    8328    160    120 S   0.0  0.0   0:00.01 init
    4 root      20   0  115664   2048   1940 S   0.0  0.0   0:00.17 bash
   27 root      20   0    8328    160    120 S   0.0  0.0   0:00.00 init
   28 root      20   0  115664   2040   1928 S   0.0  0.0   0:00.03 bash
   41 root      20   0  118768   2188   2152 S   0.0  0.0   0:00.07 su
   42 shenzx    20   0  115660   2060   1872 S   0.0  0.0   0:00.04 bash
   59 root      20   0  119488   2220   1592 R   0.0  0.0   0:00.41 top

结果中顶部显示的是系统总体状态信息,这些信息包含很多有用的内容,其含义如下:

  • 第一行中的信息
字段 含义
top 程序名
16:11:15 一天当中当前的时间
up 4:43 正常运行时间。从机器最后一次启动开始计算的时间总数
0 users 显示有几个用户已登录
load average 负载均值(load average)指的是等待运行的进程数,即共享CPU资源的处于可运行状态的进程数。
显示的三个值分别对应不同的时间段
第一个对应的是前60秒的均值
第二个对应的是前5分钟的均值
最后一个对应的是前15分钟的均值
该值小于1.0代表机器不忙
  • 第二行中的信息
字段 含义
Tasks: 统计进程数及各个进程的状态信息
4.9 us 4.9%的CPU时间被用户进程占用,这里指的是内核外的进程
3.9 sy 3.9%的CPU时间被系统进程占用
0.0 ni 0.0%的CPU时间被低优先级进程占用
90.8 id 90.8%的CPU时间是空闲的
0.0 wa 0.0%的CPU时间用来等待I/O操作
  • 第三行中的信息
字段 含义
Mem 显示物理内存(随机存取内存)的使用情况
Swap 显示交换空间(虚拟内存)的使用情况

top命令可以接受键盘指令,若需要退出top命令,则输入q。若输入h,则显示程序的帮助界面。

一般来说,top命令速度优于输出监控信息的图形化应用程序,而且消耗的资源也比较少。

# Ctrl-C-中断进程

在Linux中,我们可以在终端里按下Ctrl-C组合键中断一个程序,它意味着我们委婉地请求程序结束。

例如,我们上一节学习的动态查看进程信息的top命令。当我们执行top命令后,若不按组合键Ctrl-C,则终端的提示符不会返回。

[root@LAPTOP-2ESIRNKO ~]# top
top - 10:11:31 up  1:27,  0 users,  load average: 0.52, 0.58, 0.59
Tasks:   4 total,   1 running,   3 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3.3 us,  4.3 sy,  0.0 ni, 91.4 id,  0.0 wa,  0.9 hi,  0.0 si,  0.0 st
KiB Mem : 16695540 total, 11592476 free,  4866588 used,   236476 buff/cache
KiB Swap: 13107196 total, 13107196 free,        0 used. 11688096 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0    8324    156    132 S   0.0  0.0   0:00.10 init
    3 root      20   0    8328    160    124 S   0.0  0.0   0:00.00 init
    4 root      20   0  115664   2072   1976 S   0.0  0.0   0:00.10 bash
   20 root      20   0  119488   2236   1608 R   0.0  0.0   0:00.32 top

只有按下Ctrl-C请求程序结束后,终端提示符才会返回。

[root@LAPTOP-2ESIRNKO ~]# top
top - 10:13:14 up  1:29,  0 users,  load average: 0.52, 0.58, 0.59
Tasks:   4 total,   1 running,   3 sleeping,   0 stopped,   0 zombie
%Cpu(s):  1.5 us,  1.5 sy,  0.0 ni, 95.4 id,  0.0 wa,  1.5 hi,  0.0 si,  0.0 st
KiB Mem : 16695540 total, 11572640 free,  4886424 used,   236476 buff/cache
KiB Swap: 13107196 total, 13107196 free,        0 used. 11668260 avail Mem

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    1 root      20   0    8324    156    132 S   0.0  0.0   0:00.10 init
    3 root      20   0    8328    160    124 S   0.0  0.0   0:00.00 init
    4 root      20   0  115664   2076   1976 S   0.0  0.0   0:00.10 bash
   21 root      20   0  119488   2184   1548 R   0.0  0.0   0:00.01 top


[root@LAPTOP-2ESIRNKO ~]#

# &-使进程在后台运行

假设我们想要shell提示符返回,又不终止程序,则可以通过让该程序在后台运行来实现。我们可以把终端想象成又一个前台(表面可见的内容,例如shell提示符)和一个后台(隐藏在表层下面的内容)。

要想在程序启动时让程序在后台运行,可以在命令后面加上和字符(&)来实现。

# jobs-查看当前终端后台运行的任务

为了演示如何使用jobs命令查看当前终端后台运行的任务,我们先使top命令在后台运行。

 top &

此时,返回输出结果

[1] 22

这个信息是shell的一个称为作业控制的特性表现,shell这条信息表明已经启动的作业编号为1([1]),其对应的PID是22。若执行ps命令,可以查看到当前运行的进程。

  PID TTY          TIME CMD
    3 tty1     00:00:00 init
    4 tty1     00:00:00 bash
   22 tty1     00:00:00 top
   23 tty1     00:00:00 ps

[1]+  Stopped                 top

# fg-让进程回到前台运行

后台运行的进程不会受到任何键盘输入的影响,包括试图用来中断它的Ctrl-C组合键,要想使得进程返回到前台运行,可以使用fg命令来实现。

我们可以在fg命令后面加上百分比符号和作业编号(称为jobspec选项)来实现这个功能。如果后台只有一个任务,则可以不带jobspec选项。

fg %1

这里,由于top命令在后台很快就自动结束了。所以会报错。

# Ctrl-Z-停止(暂停)进程

如果我们只是想要暂停进程,而不是终止进程,那么,我们就可以按Ctrl-Z暂停进程。

# bg-让进程移到后台运行

若我们暂停了进程运行,或者在程序启动时没有让进程在后台运行,可以使用bg命令将进程移到后台运行。当然,暂停了的进程也可以使用fg命令让其在前台运行。

bg %1

# kill-发送信号到进程

kill命令通常用来“杀死”(终止)进程,它可以用来终止运行不正常的程序。

事实上,kill命令是用来给进程发信号。信号是操作系统和程序间通信的多种方式之一。在使用Ctrl-C和Ctrl-Z时已经见识过信号的作用。

  • 当按下Ctrl-C组合键的情况下,它将发送一个INT(中断)信号。
  • 当按下Ctrl-Z组合键的情况下,它将发送一个TSTP(终端暂停)信号。

反过来,程序“侦听”信号,而且在接收到信号的时候按照它们的指示进行操作。

kill最常用的语法格式如下:

kill [-signal] PID

其中,signal代表的信号编号。如果命令行中没有指定信号编号,那么默认将发送TERM(终止)信号, 下面是kill命令最常用来发送的信号。

# Kill命令最常用的发送信号

信号编号 信号名 含义
1 HUP 挂起信号,当一个后台进程接收到该信号时,它将重启并且重新读取它的配置文件
2 INT 中断信号,执行效果和在终端按下Ctrl-C键的效果一样,用来终止一个程序
9 KILL 杀死信号,KILL信号不会被真正意义上地被发送到目标程序,而是内核立即终止该程序。当进程以这种方式被终止时,它将没有机会对它自己进行“清理”或者对当前工作进行保存。KILL信号只能当作其它的终端信号都执行失败的情况。
15 TERM 终止信号,kill默认发送的信号类型。如果程序有足够“活力”来接收信号,那么它将被终止。
18 CONT 继续运行信号,恢复之前接受了STOP信号的进程
19 STOP 暂停信号,该信号将使进程暂停,而不是终止。和KILL信号类似,该信号不会被发送给目标进程。

# 系统常用的其它信号

在Linux系统中,还存在一些经常被系统使用的信号。

信号编号 信号名 含义
3 QUIT 退出信号
11 SEGV 段错误信号,若程序试图在没有写权限的空间执行写操作,那么系统将发送该信号
20 TSTP 终端暂停信号,在按下Ctrl-Z组合键时将发出该信号,TSTP信号由程序接收,并可以被程序所忽略
28 WINCH 窗口改变信号。当窗口大小改变时,系统将发送该信号。类似topless的一些程序将会对该信号做出响应。

如果想要查看更多的信号,使用如下命令将显示完整的信号列表。

kill -l

# killall-发送信号给多个进程

通过使用killall命令,我们可以给指定程序或者指定用户名的多个进程发送信号。一般语法格式如下:

killall [-u user] [-signal] name...

其中name是程序名称,...代表若有多个程序,程序名之间用多个空格分隔。

记住,和kill命令一样,你必须具有超级用户权限,才能够使用killall命令给不属于自己的进程发送信号。

LastUpdated: 7/9/2020, 9:08:09 AM