百度#资#在文末:更新中~~~

第一部分Linux命令行

第1章初识Linux shell

深入探究 Linux 内核

内核主要负责以下四种功能:  系统内存管理  软件程序管理  硬件设备管理  文件系统管理

1. 系统内存管理 :操作系统内核的主要功能之一就是内存管理。内核不仅管理服务器上的可用物理内存,还可 以创建和管理虚拟内存(即实际并不存在的内存)。 内核通过硬盘上的存储空间来实现虚拟内存,这块区域称为交换空间(swap space)。内核不

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统

内存存储单元按组划分成很多块,这些块称作页面(page)。内核将每个内存页面放在物理内存或交换空间。然后,内核会维护一个内存页面表,指明哪些页面位于物理内存内,哪些页面被换到了磁盘上。 内核会记录哪些内存页面正在使用中,并自动把一段时间未访问的内存页面复制到交换空间 区域(称为换出,swapping out)——即使还有可用内存。当程序要访问一个已被换出的内存页 面时,内核必须从物理内存换出另外一个内存页面给它让出空间,然后从交换空间换入请求的内 存页面。显然,这个过程要花费时间,拖慢运行中的进程。只要Linux系统在运行,为运行中的 程序换出内存页面的过程就不会停歇。

 2. 软件程序管理 Linux操作系统将运行中的程序称为进程。进程可以在前台运行,将输出显示在屏幕上,也 可以在后台运行,隐藏到幕后。内核控制着Linux系统如何管理运行在系统上的所有进程。

内核创建了第一个进程(称为init进程)来启动系统上所有其他进程。当内核启动时,它会 将init进程加载到虚拟内存中。内核在启动任何其他进程时,都会在虚拟内存中给新进程分配一 块专有区域来存储该进程用到的数据和代码。 

[root@liruilong ~]# vim /etc/inittab 
[root@liruilong ~]#

 

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_02

Linux操作系统有5个启动运行级。

  • 运行级为1时,只启动基本的系统进程以及一个控制台终端进程。我们称之为单用户模式。 单用户模式通常用来在系统有问题时进行紧急的文件系统维护。
  • 标准的启动运行级是3。在这个运行级上,大多数应用软件,比如网络支持程序,都会启动。
  • 另一个Linux中常见的运行级是5。在这个运行级上系统会启动图形化的X Window系统

3. 硬件设备管理 内核的另一职责是管理硬件设备。任何Linux系统需要与之通信的设备,都需要在内核代码 中加入其驱动程序代码。驱动程序代码相当于应用程序和硬件设备的中间人,允许内核与设备之 间交换数据。在Linux内核中有两种方法用于插入设备驱动代码:

  • 编译进内核的设备驱动代码
  • 可插入内核的设备驱动模块

Linux系统将硬件设备当成特殊的文件,称为设备文件。设备文件有3种分类:

 字符型设备文件  块设备文件  网络设备文件

字符型设备文件是指处理数据时每次只能处理一个字符的设备。大多数类型的调制解调器和 终端都是作为字符型设备文件创建的。

块设备文件是指处理数据时每次能处理大块数据的设备, 比如硬盘。

网络设备文件是指采用数据包发送和接收数据的设备,包括各种网卡和一个特殊的回环设 备。这个回环设备允许Linux系统使用常见的网络编程协议同自身通信。

 4. 文件系统管理 不同于其他一些操作系统,Linux内核支持通过不同类型的文件系统从硬盘中读写数据。除 了自有的诸多文件系统外,Linux还支持从其他操作系统(比如Microsoft Windows)采用的文件 系统中读写数据。内核必须在编译时就加入对所有可能用到的文件系统的支持。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_03

Linux内核采用虚拟文件系统(Virtual File System,VFS)作为和每个文件系统交互的接口。 这为Linux内核同任何类型文件系统通信提供了一个标准接口。当每个文件系统都被挂载和使用 时,VFS将信息都缓存在内存中。 

GNU 工具

除了由内核控制硬件设备外,操作系统还需要工具来执行一些标准功能,比如控制文件和 程序。GNU组织(GNU是GNU’s Not Unix的缩写)开发了一套完整的Unix工具

1. 核心GNU工具 GNU项目的主旨在于为Unix系统管理员设计出一套类似于Unix的环境。这个目标促使该项目 移植了很多常见的Unix系统命令行工具。供Linux系统使用的这组核心工具被称为coreutils(core utilities)软件包。

GNU coreutils软件包由三部分构成:  用以处理文件的工具  用以操作文本的工具  用以管理进程的工具

2. shell GNU/Linux shell是一种特殊的交互式工具。它为用户提供了启动程序、管理文件系统中的文 件以及运行在Linux系统上的进程的途径。shell的核心是命令行提示符。命令行提示符是shell负责 交互的部分。它允许你输入文本命令,然后解释命令,并在内核中执行。

shell包含了一组内部命令,用这些命令可以完成诸如复制文件、移动文件、重命名文件、显 示和终止系统中正运行的程序等操作。

将多个shell命令放入文件中作为程序执行。这些文件被称作shell脚本。你在命令行 上执行的任何命令都可放进一个shell脚本中作为一组命令执行。

在Linux系统上,通常有好几种Linux shell可用。不同的shell有不同的特性,有些更利于创建 脚本,有些则更利于管理进程。

所有Linux发行版默认的shell都是bash shell。bash shell由GNU项 目开发,被当作标准Unix shell——Bourne shell(以创建者的名字命名)的替代品。bash shell的名 称就是针对Bourne shell的拼写所玩的一个文字游戏,称为Bourne again shell。

Linux 桌面环境 1. X Window系统   2. KDE桌面  3. GNOME桌面4. Unity桌面

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_04

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_05

第2章走进shell

输入命令setterm -inversescreen on 也可以 使用选项off关闭该特性。

输入setterm –background white,然后按回车键, 接着输入setterm –foreground black

第3章基本的bash shell命令

shell 提示符 默认bash shell提示符是美元符号($),

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_06

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_07

表示标准输出和错误都不要,丢进黑洞,让他消失的无影无踪。/dev/null

nohup ./program >/dev/null 2>&1 &

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

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_08

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

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

把隐藏文件和普通文件及目录一起显示出来,就得用到-a参数。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_09

-R参数是ls命令可用的另一个参数,叫作递归选项

的下述信息:

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

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

 文件的硬链接总数;

 文件属主的用户名;

 文件属组的组名;

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

 文件的上次修改时间;  文件名或目录名。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_10

过滤输出列表

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_11

 问号(?)代表一个字符;  星号(*)代表零个或多个字符。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_12

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_13

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_14

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

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

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_15

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_16

复制文件

最好是加上-i选项,强制shell询问是否需要覆盖已有文件。

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

-d只列出目录本身的信息,不列出其中的内容

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_17

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

链接文件

 符号链接  硬链接

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

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_18

证明链接文件是独立文件的方法是查看inode编号 

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_19

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

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_20

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_21

带有硬链接的文件共享inode编号。这是因为它们终归是同一个文件

重命名文件

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

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_22

删除文件

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

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_23

创建目录

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

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_24

删除目录

删除目录的基本命令是rmdir。

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

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_25

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

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_26

查看文件内容

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_27

查看整个文件

1. cat命令 -n参数会给所有的行加上行号。 只想给有文本的行加上行号,可以用-b参数。 -T参数会用^I字符组合去替换文中的所有制表符。

2. more命令 more命令只支持文本文件中的基本移动

3. less命令,能够翻页

查看部分文件

1. tail命令

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

2. head命令 head命令,顾名思义,会显示文件开头那些行的内容。

>第4章更多的bash shell

监测程序

Linux系统中使用的GNU ps命令支持3种不同类型的命令行参数:

 Unix风格的参数,前面加单破折线;  BSD风格的参数,前面不加破折线;  GNU风格的长参数,前面加双破折线。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_28

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_29

  UID:启动这些进程的用户。

 PID:进程的进程ID。

 PPID:父进程的进程号(如果该进程是由另一个进程启动的)。

 C:进程生命周期中的CPU利用率。  STIME:进程启动时的系统时间。

 TTY:进程启动时的终端设备。

 TIME:运行进程需要的累计CPU时间。

 CMD:启动的程序名称。

上例中输出了合理数量的信息,这也正是大多数系统管理员希望看到的。如果想要获得更多 的信息,可采用-l参数,它会产生一个长格式输出。

2. BSD风格的参数 

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_30

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_31

 <:该进程运行在高优先级上。

 N:该进程运行在低优先级上。

 L:该进程有页面锁定在内存中。

 s:该进程是控制进程。

 l:该进程是多线程的。

 +:该进程运行在前台。

3. GNU长参数   GNU开发人员在这个新改进过的ps命令中加入了另外一些参数。其中一些GNU长参数 复制了现有的Unix或BSD类型的参数,而另一些则提供了新功能。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_32

实时监测进程    top命令跟ps命令相似,能够显示进程信息,但它是实时显 示的

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_33

 PID:进程的ID。

 USER:进程属主的名字。

 PR:进程的优先级。

 NI:进程的谦让度值。

 VIRT:进程占用的虚拟内存总量。

 RES:进程占用的物理内存总量。

 SHR:进程和其他进程共享的内存总量。

 S:进程的状态(D代表可中断的休眠状态,R代表在运行状态,S代表休眠状态,T代表 跟踪状态或停止状态,Z代表僵化状态)。

 %CPU:进程使用的CPU时间比例。

 %MEM:进程使用的内存占可用内存的比例。

 TIME+:自进程启动到目前为止的CPU时间总量。

 COMMAND:进程所对应的命令行名称,也就是启动的程序名

top命令在启动时会按照%CPU值对进程排序。可以在top运行时使用多种交互 命令重新排序。每个交互式命令都是单字符,在top命令运行时键入可改变top的行为。键入f允 许你选择对输出进行排序的字段,键入d允许你修改轮询间隔。键入q可以退出top。用户在top 命令的输出上有很大的控制权。

结束进程

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_34

1. kill命令 kill命令可通过进程ID(PID)给进程发信号。默认情况下,kill命令会向命令行中列出的 全部PID发送一个TERM信号

2. killall命令 killall命令非常强大,它支持通过进程名而不是PID来结束进程。killall命令也支持通 配符

监测磁盘空间

Linux文件系统将所有的磁盘都并入一个虚拟目录下。在使用新的存储媒 体之前,需要把它放到虚拟目录下。这项工作称为挂载(mounting)。Linux发行版都能自动挂载特定类型的可移动存储媒体。

挂载存储媒体 1. mount命令 Linux上用来挂载媒体的命令叫作mount。默认情况下,mount命令会输出当前系统上挂载的 设备列表。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_35

mount命令提供如下四部分信息:  媒体的设备文件名  媒体挂载到虚拟目录的挂载点  文件系统类型  已挂载媒体的访问状态

 vfat:Windows长文件系统。

 ntfs:Windows NT、XP、Vista以及Windows 7中广泛使用的高级文件系统。

 iso9660:标准CD-ROM文件系统。

mount -t type device directory

type参数指定了磁盘被格式化的文件系统类型。Linux可以识别非常多的文件系统类型。

#手动将U盘/dev/sdb1挂载到/media/disk,可用下面的命令:
mount -t vfat /dev/sdb1 /media/disk

umount命令

umount [directory | device ]
umount命令支持通过设备文件或者是挂载点来指定要卸载的设备。如果有任何程序正在使
用设备上的文件,系统就不会允许你卸载它:

使用 df 命令

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_36

 du 命令

 -c:显示所有已列出文件总的大小。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_37

 -h:按用户易读的格式输出大小,即用K替代千字节,用M替代兆字节,用G替代吉字 节。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_38

 -s:显示每个输出参数的总计。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_39

处理数据文件

排序,处理大量数据时的一个常用命令是sort命令

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_40

数字排序使用 -n 参数,告诉sort命令把数字识别成数字而不是字符

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_41

使用 -M 参数按照月份排序。

-k和-t参数在对按字段分隔的数据进行排序时非常有用,例如/etc/passwd文件。可以用-t 参数来指定字段分隔符,然后用-k参数来指定排序的字段。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_42

搜索数据 

grep [options] pattern [file]

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_43

压缩数据

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_44

gzip软件包是GNU项目的产物,意在编写一个能够替代原先Unix中compress工具的免费版 本。

gzip:用来压缩文件。  gzcat:用来查看压缩过的文本文件的内容。  gunzip:用来解压文件。

归档数据,tar命令最开始是用来将文件写到磁带设备上归档的

tar function [options] object1 object2 ...

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_45

#这些选项经常合并到一起使用。首先,你可以用下列命令来创建一个归档文件:
tar -cvf test.tar test/ test2/
#上面的命令创建了名为test.tar的归档文件,含有test和test2目录内容。列出tar文件test.tar的内容(但并不提取文件)。:
tar -tf test.tar
#从tar文件test.tar中提取内容。如果tar文件是从一个目录结构创建的,那整个目录结构都会在当前目录下重新创建
tar -xvf test.tar

tar -zxvf filename.tgz  解压

>第5章理解shell

默认的交互shell会在用户登录某个虚拟控制台终端或在GUI中运行终端仿真器时启动。不过 还有另外一个默认shell是/bin/sh,它作为默认的系统shell,用于那些需要在启动时使用的系统shell 脚本。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_46

shell 的父子关系

用于登录某个虚拟控制器终端或在GUI中运行终端仿真器时所启动的默认的交互shell,是一 个父shell。

在CLI提示符后输入/bin/bash命令或其他等效的bash命令时,会创建一个新的shell程序。 这个shell程序被称为子shell(child shell)。子shell也拥有CLI提示符,同样会等待命令输入。

当输入bash、生成子shell的时候,你是看不到任何相关的信息的,

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_47

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_48

输入命令bash之后,一个子shell就出现了。第二个ps -f是在子shell中执行的。可以从显示 结果中看到有两个bash shell程序在运行。第一个bash shell程序,也就是父shell进程

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_49

在生成子shell进程时,只有部分父进程的环境被复制到子shell环境中。这会对包括变量在内 的一些东西造成影响。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_50

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_51

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_52

exit命令不仅能退出子shell,还能用来登出当前的虚拟控制台终端或终端仿真器软件。只需 要在父shell中输入exit,就能够从容退出CLI了。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_53

进程列表:所有的命令依次执行,不存在任何问题。不过这并不是进程列表。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_54

命令列表要想成为进程列表,这些命令必须包含在括号里,括号的加入使 命令列表变成了进程列表,生成了一个子shell来执行对应的命令。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_55

进程列表是一种命令分组(command grouping)。另一种命令分组是将命令放入花括号中, 并在命令列表尾部加上分号(;)。语法为{ command; }。使用花括号进行命令分组并不 会像进程列表那样创建出子shell。

要想知道是否生成了子shell。得借助一个使用了环境变量的命令。如果该命令返回0,就表明没有子shell。如果返回 1或者其他更大的数字,就表明存在子shell。

echo $BASH_SUBSHELL。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_56

别出心裁的子 shell 用法, 在交互式shell中,一个高效的子shell用法就是使用后台模式

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_57

在CLI中运用子shell的创造性方法之一就是将进程列表置入后台模式。你既可以在子shell中 进行繁重的处理工作,同时也不会让子shell的I/O受制于终端。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_58

将进程列表置入后台模式并不是子shell在CLI中仅有的创造性用法。协程就是另一种方法。

协程 协程可以同时做两件事。它在后台生成一个子shell,并在这个子shell中执行命令。 要进行协程处理,得使用coproc命令,还有要在子shell中执行的命令。

jobs命令能够显示出协程的处理状态。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_59

必须确保在第一个花括号({)和命令名之间有一个空格。还必须保证命令以分号(;)结 尾。另外,分号和闭花括号(})之间也得有一个空格。

 将协程与进程列表结合起来产生嵌套的子shell

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_60

协程能够让你尽情发挥想象力,发送或接收来自子shell中进程的信息。只有在拥有多个协 程的时候才需要对协程进行命名,因为你得和它们进行通信。否则的话,让coproc命令 将其设置成默认的名字COPROC就行了。

 协程能够让你尽情发挥想象力,发送或接收来自子shell中进程的信息。只有在拥有多个协 程的时候才需要对协程进行命名,因为你得和它们进行通信。否则的话,让coproc命令 将其设置成默认的名字COPROC就行了。

理解 shell 的内建命令

内建命令和非内建命令的操作方式大不相同。

外部命令:也被称为文件系统命令,是存在于bash shell之外的程序。它们并不是shell 程序的一部分。外部命令程序通常位于/bin、/usr/bin、/sbin或/usr/sbin中。

ps就是一个外部命令。你可以使用which和type命令找到它。作为外部命令,ps命令执行时会创建出一个子进程

[root@liruilong ~]# which ps
/usr/bin/ps
[root@liruilong ~]# type -a ps
ps is /usr/bin/ps
[root@liruilong ~]# ls -la /bin/ps
-rwxr-xr-x 1 root root 100112 Apr 1 2020 /bin/ps
[root@liruilong ~]#

当外部命令执行时,会创建出一个子进程。这种操作被称为衍生(forking)。外部命令ps很 方便显示出它的父进程以及自己所对应的衍生子进程。当进程必须执行衍生操作时,它需要花费时间和精力来设置新子进程的环境

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_61

内建命令

[root@liruilong ~]# type ps
ps is hashed (/usr/bin/ps)
[root@liruilong ~]# type cd
cd is a shell builtin
[root@liruilong ~]#

使用history命令 。bash shell会跟踪你用过的命令。你可以唤回这些命令 并重新使用

输入!!,然后按回 车键就能够唤出刚刚用过的那条命令来使用。

命令历史记录被保存在隐藏文件.bash_history中,它位于用户的主目录中。这里要注意的是,

  1. bash命令的历史记录是先存放在内存中,当shell退出时才被写入到历史文件中。
  2. 要实现强制写入,需 要使用history命令的-a选项,
  3.  要想强制重新读 取.bash_history文件,更新终端会话的历史记录,可以使用history -n命令。
  4. 唤回历史列表中任意一条命令。只需输入惊叹号和命令在历史列表中的编号即可。

命令别名

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_62

[root@liruilong ~]# alias -p
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
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'
[root@liruilong ~]#

因为命令别名属于内部命令,一个别名仅在它所被定义的shell进程中才有效。

>第6章使用Linux环境变量

bash shell用一个叫作环境变量(environment variable)的特性来存储有关shell会话和工作环 境的信息(这也是它们被称作环境变量的原因)。这项特性允许你在内存中存储数据,以便程序 或shell中运行的脚本能够轻松访问到它们。

 全局变量  局部变量 全局环境变量 全局环境变量对于shell会话和所有生成的子shell都是可见的。局部变量则只对创建它们的 shell可见

要查看全局变量,可以使用env或printenv命令。要显示个别环境变量的值,可以使用printenv命令,但是不要用env命令。

[root@liruilong ~]# printenv HOME
/root
[root@liruilong ~]# echo $HOME
/root

 局部环境变量 。set命令会显示为某个特定进程设置的所有环境变量,包括局部变量、全局变量 以及用户定义变量。

设置用户定义变量

设置局部用户定义变量 

如果要给变量赋一个含有空格的字符串值,必须用单引号来界定字符串的首和尾。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_63

如果是你自己创建的局 部变量或是shell脚本,请使用小写字母

设置全局环境变量这个过程通过export命令来完成,变量名前面不需要加$。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_64

删除环境变量

可以用unset命令 完成这个操作。在unset命令中引用环境变量时,记住不要使用$。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_65

默认的 shell 环境变量

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_66

设置 PATH 环境变量

PATH环境变量定义了用于进行命令和程序查找的目录。

[root@liruilong ~]# echo $PATH
/usr/local/sbin
:/usr/local/bin
:/usr/sbin:/usr/bin
:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/bin
:/usr/tomcat/apache-tomcat-9.0.21/lib
:/root/bin
[root@liruilong ~]#

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_67

 如果希望子shell也能找到你的程序的位置,一定要记得把修改后的PATH环境变量导出

$export PATH="$PATH:/home/user/bin"
也可以使用
$ PATH="$PATH:/home/user/bin"
$ export PATH
$ echo $PATH
/home/slynux/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr
/games:/home/user/bin

定位系统环境变量 

登入Linux系统启动一个bash shell时,默认情况下bash会在几个文件中查找命令。这些文件叫作启动文件或环境文件bash检查的启动文件取决于你启动bash shell的方式。启动bash shell有3种方式:

  • 登录时作为默认登录shell
  • 作为非登录shell的交互式shell
  • 作为运行脚本的非交互shell

登录shell会从5个不同的启动文件里 读取命令:

  1. /etc/profile
  2. $HOME/.bash_profile
  3. $HOME/.bashrc
  4. $HOME/.bash_login
  5. $HOME/.profile

/etc/profile文件是系统上默认的bash shell的主启动文件。系统上的每个用户登录时都会执行 这个启动文件。

[root@liruilong ~]# cat /etc/profile
# /etc/profile

# System wide environment and startup programs, for login setup
# Functions and aliases go in /etc/bashrc

# It's NOT a good idea to change this file unless you know what you
# are doing. It's much better to create a custom.sh shell script in
# /etc/profile.d/ to make custom changes to your environment, as this
# will prevent the need for merging in future updates.

pathmunge () {
case ":${PATH}:" in
*:"$1":*)
;;
*)
if [ "$2" = "after" ] ; then
PATH=$PATH:$1
else
PATH=$1:$PATH
fi
esac
}


if [ -x /usr/bin/id ]; then
if [ -z "$EUID" ]; then
# ksh workaround
EUID=`/usr/bin/id -u`
UID=`/usr/bin/id -ru`
fi
USER="`/usr/bin/id -un`"
LOGNAME=$USER
MAIL="/var/spool/mail/$USER"
fi

# Path manipulation
if [ "$EUID" = "0" ]; then
pathmunge /usr/sbin
pathmunge /usr/local/sbin
else
pathmunge /usr/local/sbin after
pathmunge /usr/sbin after
fi

HOSTNAME=`/usr/bin/hostname 2>/dev/null`
HISTSIZE=1000
if [ "$HISTCONTROL" = "ignorespace" ] ; then
export HISTCONTROL=ignoreboth
else
export HISTCONTROL=ignoredups
fi

export PATH USER LOGNAME MAIL HOSTNAME HISTSIZE HISTCONTROL

# By default, we want umask to get set. This sets it for login shell
# Current threshold for system reserved uid/gids is 200
# You could check uidgid reservation validity in
# /usr/share/doc/setup-*/uidgid file
#export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.71-2.b15.el7_2.x86_64
export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64
export CATALINA_HOME=/usr/tomcat/apache-tomcat-9.0.21

export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$CATALINA_HOME/lib
export PATH=$PATH:$JAVA_HOME/bin:$CATALINA_HOME/lib

if [ $UID -gt 199 ] && [ "`/usr/bin/id -gn`" = "`/usr/bin/id -un`" ]; then
umask 002
else
umask 022
fi

for i in /etc/profile.d/*.sh ; do
if [ -r "$i" ]; then
if [ "${-#*i}" != "$-" ]; then
. "$i"
else
. "$i" >/dev/null
fi
fi
done

unset i
unset -f pathmunge

:for语句。它用来迭代/etc/profile.d目录 

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_68

大部分应用都会创建两个启动文件:一个供 bash shell使用(使用.sh扩展名),一个供c shell使用(使用.csh扩展名)。

$HOME目录下的启动文件:提供一个用户专属的启动文件来定义该用户所用到的环 境变量。大多数Linux发行版只用这四个启动文件中的一到两个:

交互式 shell 进程 的bash shell不是登录系统时启动的(比如是在命令行提示符下敲入bash时启动),那 么你启动的shell叫作交互式shell,

交互式shell启动不会访问/etc/profile文件只会检查用户HOME目录 中的.bashrc文件。.bashrc文件有两个作用:

  • 一是查看/etc目录下通用的bashrc文件,
  • 二是为用户提供一个定制自 己的命令别名和私有脚本函数的地方。

非交互式 shell 系统执行shell脚本时用的就是这种shell。不同的地方在于它 没有命令行提示符 bash shell提供了BASH_ENV环境变量。当shell启动一个非交互式shell进 程时,它会检查这个环境变量来查看要执行的启动文件。如果有指定的文件,shell会执行该文件 里的命令

环境变量持久化

对全局环境变量来说(Linux系统中所有用户都需要使用的变量),可能更倾向于将新的或修 改过的变量设置放在/etc/profile文件中

最好是在/etc/profile.d目录中创建一个以.sh结尾的文件。把所有新的或修改过的全局环境变 量设置放在这个文件中。

在大多数发行版中,存储个人用户永久性bash shell变量的地方是$HOME/.bashrc文件

数组变量

[root@liruilong ~]# liruilong=(li rui long)
[root@liruilong ~]# echo $liruilong
li
[root@liruilong ~]# echo ${liruilong[1]}
rui
[root@liruilong ~]# echo ${liruilong[2]}
long
[root@liruilong ~]# echo ${liruilong[*]}
li rui long
[root@liruilong ~]# unset liruilong
[root@liruilong ~]# echo ${liruilong[*]}

[root@liruilong ~]#

>第7章理解Linux文件权限

Linux 的安全性

用户权限是通过创建用户时分配的用户ID(User ID,通常缩写为UID)来跟踪的。

/etc/passwd 文件 

系统账户,是系统上运行的各种服务进程访问资源用的特殊账户。所有运行在后台的服务都需要用一个 系统用户账户登录到Linux系统上。Linux为系统账户预留了1000以下的UID值。

绝大多数Linux系统都将用户密码保存在另一个单独的文件中(叫作shadow文件,位置 在/etc/shadow)。只有特定的程序(比如登录程序)才能访问这个文件。

  •  登录用户名
  •  用户密码
  •  用户账户的UID(数字形式)
  •  用户账户的组ID(GID)(数字形式)
  •  用户账户的文本描述(称为备注字段)
  •  用户HOME目录的位置
  •  用户的默认shell

[root@liruilong ~]# cat /etc/shadow root:$6$Uebh9/WEzEaQfT$8b0B6oBgWUTEmYojDW9.6PHOw0.jD7A.SENsHFD/YPwh/L9jRJK0yWAtRF4BEteYZETeMiInp72dTvi


添加新用户  以使用加入了-D选项的useradd

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_69

[root@liruilong ~]# useradd -D
GROUP=100 #新用户会被添加到GID为100的公共组
HOME=/home #新用户的HOME目录将会位于/home/loginname;
INACTIVE=-1 # 新用户账户密码在过期后不会被禁用;
EXPIRE= # 新用户账户未被设置过期日期;
SHELL=/bin/bash #新用户账户将bash shell作为默认shell;
SKEL=/etc/skel #系统会将/etc/skel目录下的内容复制到用户的HOME目录下
CREATE_MAIL_SPOOL=yes #系统为该用户账户在mail目录下创建一个用于接收邮件的文件
[root@liruilong ~]#

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_70

删除用户 userdel可以满足这个需求。默认情况下,userdel命令会只 删除/etc/passwd文件中的用户信息,而不会删除系统中属于该账户的任何文件。 如果加上-r参数,userdel会删除用户的HOME目录以及邮件目录

修改用户  usermod 它能用来修改/etc/passwd文件中的大部 分字段,  -l修改用户账户的登录名。  -L锁定账户,使用户无法登录。  -p修改账户的密码。  -U解除锁定,使用户能够登录

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_71

-e选项能强制用户下次登录时修改密码。你可以先给用户设置一个简单的密码,之后再强制 在下次登录时改成他们能记住的更复杂的密码

 chpasswd命令能从 标准输入自动读取登录名和密码对(由冒号分割)列表,给密码加密,然后为用户账户设置。你 也可以用重定向命令来将含有userid:passwd对的文件重定向给该命令。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_72

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_73

chsh、chfn和chage工具专门用来修改特定的账户信息。

chsh命令用来快速修改默认的用 户登录shell。使用时必须用shell的全路径名作为参数,不能只用shell名。

# chsh -s /bin/csh test
Changing shell for test.
Shell changed.
#

 chfn命令提供了在/etc/passwd文件的备注字段中存储信息的标准方法。chfn命令会将用于 Unix的finger命令的信息存进备注字段,而不是简单地存入一些随机文本(比如名字或昵称之 类的),或是将备注字段留空。finger命令可以非常方便地查看Linux系统上的用户信息

出于安全性考虑,很多Linux系统管理员会在系统上禁用finger命令,不少Linux发行版 甚至都没有默认安装该命令

chage命令用来帮助管理用户账户的有效期。你需要对每个值设置多个参数,??? 没懂

使用 Linux 组

每个组都有唯一的GID——跟UID类似,在系统上这是个唯一的数值。除了GID,每个组还 有唯一的组名。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_74

组密码允许非组内成员通过它临时成为该组成员。这个功能并不很普遍,但确实存在。

创建新组:

修改组

groupadd xiaoming
cat /etc/group | grep xiaomin*
usermod -G xiaoming liruilong
cat /etc/group | grep xiaomin*
groupmod -n XM xiaoming
cat /etc/group | grep XM*
cat /etc/group | grep xiaomin*

 理解文件权限 

使用文件权限符

 -代表文件  d代表目录  l代表链接  c代表字符型设备  b代表块设备  n代表网络设备 r代表对象是可读的  w代表对象是可写的 x代表对象是可执行的 对象的属主  对象的属组  系统其他用户

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_75

默认文件权限 umask命令用来设置所创建文件和目录 的默认权限。

 u代表用户  g代表组  o代表其他  a代表上述所有

  • X:如果对象是目录或者它已有执行权限,赋予执行权限。
  • s:运行时重新设置UID或GID。
  • t:保留文件或目录。
  • u:将权限设置为跟属主一样。
  • g:将权限设置为跟属组一样。
  • o:将权限设置为跟其他用户一样

改变安全性设置

chmod命令用来改变文件和目录的安全性设置

[ugoa…][[+-=][rwxXstugo…]

 X:如果对象是目录或者它已有执行权限,赋予执行权限。  s:运行时重新设置UID或GID。  t:保留文件或目录。  u:将权限设置为跟属主一样。  g:将权限设置为跟属组一样。  o:将权限设置为跟其他用户一样。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_76

改变所属关系

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_77

chown命令采用一些不同的选项参数。-R选项配合通配符可以递归地改变子目录和文件的所 属关系。-h选项可以改变该文件的所有符号链接文件的所属关系。

只有root用户能够改变文件的属主。任何属主都可以改变文件的属组,但前提是属主必须 是原属组和目标属组的成员

 chgrp命令可以更改文件或目录的默认属组。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_78

共享文件

Linux系统上共享文件的方法是创建组

  • 设置用户ID(SUID):当文件被用户使用时,程序会以文件属主的权限运行。
  • 程序会以文件属组的权限运行;对目录来说,目录中 创建的新文件会以目录的默认属组作为默认属组。
  •  粘着位:进程结束后文件还驻留(粘着)在内存中。share

SGID位对文件共享非常重要。启用SGID位后,你可以强制在一个共享目录下创建的新文件都属于该目录的属组,这个组也就成为了每个用户的属组。

SGID可通过chmod命令设置。它会加到标准3位八进制值之前(组成4位八进制值),或者在符号模式下用符号s。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_79

用mkdir命令来创建希望共享的目录。然后通过chgrp命令将目录的默认属组改为包含所有需要共享文件的用户的组(你必须是该组的成员)。最后,将目录的SGID位置位,以保证 目录中新建文件都用shared作为默认属组。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_80

所有组成员都需把他们的umask值设置成文件对属组成员可写。在前面的例子中,umask改成了002,所以文件对属组是可写的。新文件会沿用目录的属组,而不是用户的默认属组 ,即所有的sharedemo组成员都可以访问这个文件了。

小结:

useradd命令用来创建新的用户账户,groupadd 命令用来创建新的组账户。修改已有用户账户,我们用usermod命令。类似的groupmod命令用 来修改组账户信息。

umask命令用来设置系统中所创建的文件和目录的默认安全设置。系统管理员通常 会在/etc/profile文件中设置一个默认的umask值,但你可以随时通过umask命令来修改自己的 umask值。

chmod命令用来修改文件和目录的安全设置。只有文件的属主才能改变文件或目录的权限。 不过root用户可以改变系统上任意文件或目录的安全设置。chown和chgrp命令可用来改变文件 默认的属主和属组。

SGID位会强制某个目录下创建的新 文件或目录都沿用该父目录的属组,而不是创建这些文件的用户的属组。这可以为系统的用户之 间共享文件提供一个简便的途径。

>第8章管理文件系统

探索 Linux 文件系统

基本的 Linux 文件系统:

1. ext文件系统:Linux操作系统中引入的最早的文件系统叫作扩展文件系统( extended filesystem,简记为ext ),它为Linux提供了一个基本的类Unix文件系统:使用虚拟目录来操作硬件设备,在物理设备上按定长的块来存储数据。

ext文件系统采用名为索引节点的系统来存放虚拟目录中所存储文件的信息。索引节点系统 在每个物理设备中创建一个单独的表(称为索引节点表)来存储这些文件的信息。存储在虚拟目 录中的每一个文件在索引节点表中都有一个条目。ext文件系统名称中的extended部分来自其跟踪 的每个文件的额外数据。

Linux通过唯一的数值(称作索引节点号)来引用索引节点表中的每个索引节点,这个值是 创建文件时由文件系统分配的。文件系统通过索引节点号而不是文件全名及路径来标识文件。

 文件名  文件大小  文件的属主  文件的属组  文件的访问权限  指向存有文件数据的每个硬盘块的指针

2. ext2文件系统:

ext2文件系统还改变了文件在数据块中存储的方式。ext文件系统常 见的问题是在文件写入到物理设备时,存储数据用的块很容易分散在整个设备中(称作碎片化, fragmentation)。数据块的碎片化会降低文件系统的性能,因为需要更长的时间在存储设备中查找 特定文件的所有块。 保存文件时,ext2文件系统通过按组分配磁盘块来减轻碎片化。通过将数据块分组,文件系 统在读取文件时不需要为了数据块查找整个物理设备。

如果计算机系统在存储文件和更新索引节点表之间发生了什么,这二者的内容就不同步了,ext2文件系统由于容易在系统崩溃或断电时损坏而臭名昭著。

3.日志文件系统

日志文件系统为Linux系统增加了一层安全性。它不再使用之前先将数据直接写入存储设备 再更新索引节点表的做法,而是先将文件的更改写入到临时文件(称作日志,journal)中。在数 据成功写到存储设备和索引节点表之后,再删除对应的日志条目。

4.ext3文件系统:

2001年,ext3文件系统被引入Linux内核中,直到最近都是几乎所有Linux发行版默认的文件 系统。它采用和ext2文件系统相同的索引节点表结构,但给每个存储设备增加了一个日志文件, 以将准备写入存储设备的数据先记入日志。 默认情况下,ext3文件系统用有序模式的日志功能——只将索引节点信息写入日志文件直到数据块都被成功写入存储设备才删除。你可以在创建文件系统时用简单的一个命令行选项将 ext3文件系统的日志方法改成数据模式或回写模式。 虽然ext3文件系统为Linux文件系统添加了基本的日志功能,但它仍然缺少一些功能。例如 ext3文件系统无法恢复误删的文件,它没有任何内建的数据压缩功能(虽然有个需单独安装的补 丁支持这个功能),ext3文件系统也不支持加密文件。鉴于这些原因,Linux项目的开发人员选择 再接再厉,继续改进ext3文件系统。

5.ext4文件系统 扩展ext3文件系统功能的结果是ext4文件系统,ext4文件系统在2008年 受到Linux内核官方支持,现在已是大多数流行的Linux发行版采用的默认文件系统,除了支持数据压缩和加密,ext4文件系统还支持一个称作区段(extent)的特性区段在存储设备上按块分配空间,但在索引节点表中只保存起始块的位置。由于无需列出所有用来存储文件中数据的数据块,它可以在索引节点表中节省一些空间。

ext4还引入了块预分配技术(block preallocation)。如果你想在存储设备上给一个你知道要变 大的文件预留空间,ext4文件系统可以为文件分配所有需要用到的块,而不仅仅是那些现在已用到的块。ext4文件系统用0填满预留的数据块,不会将它们分配给其他文件。

  • 3. Reiser文件系统
  • 4. JFS文件系统
  • 5. XFS文件系统

操作文件系统

fdisk工具用来帮助管理安装在系统上的任何存储设备上的分区。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_81

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_82

分区可以按主分区(primary partition)或扩展分区(extended partition)创建。主分区可以被文件系统直接格式化,而扩展分区则只能容纳其他逻辑分区。扩展分区出现的原因是每个存储设 备上只能有4个分区。可以通过创建一个扩展分区,然后在扩展分区内创建多个逻辑分区进行扩展。

创建文件系统

在将数据存储到分区之前,你必须用某种文件系统对其进行格式化,这样Linux才能使用它。 每种文件系统类型都用自己的命令行程序来格式化分区

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_83

为分区创建了文件系统之后,下一步是将它挂载到虚拟目录下的某个挂载点,这样就可以将 数据存储在新文件系统中了。你可以将新文件系统挂载到虚拟目录中需要额外空间的任何位置。 

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_84

$ sudo mount -t ext4 /dev/sdb1 /mnt/my_partition

mount命令将新的硬盘分区添加到挂载点。mount命令的 -t 选项指明了要挂载的文件系统类型(ext4)。现在可以在新分区中保存 新文件和目录了

这种挂载文件系统的方法只能临时挂载文件系统。当重启Linux系统时,文件系统并不会 自动挂载。要强制Linux在启动时自动挂载新的文件系统,可以将其添加到/etc/fstab文件。

 文件系统的检查与修复

fsck命令能够检查和修复大部分类型的Linux文件系统,包括本章早些时候讨论过的ext、 ext2、ext3、ext4、ReiserFS、JFS和XFS。该命令的格式是: fsck options filesystem

逻辑卷管理

二、物理卷、逻辑卷、卷组、快照卷之间的联系

  • 物理卷(Physical Volume,PV):就是指硬盘分区,也可以是整个硬盘或已创建的软RAID,是LVM的基本存储设备。
  • 卷组(Volume Group,VG):是由一个或多个物理卷所组成的存储池,在卷组上能创建一个或多个逻辑卷。
  • 逻辑卷(Logical Volume,LV):类似于非LVM系统中的硬盘分区,它建立在卷组之上,是一个标准的块设备,在逻辑卷之上可以建立文件系统。

可以做这样一个设想来理解以上三者的关系:如果把PV比作地球的一个板块,VG则是一个地球,因为地球是由多个板块组成的,那么在地球上划分一个区域并标记为亚洲,则亚洲就相当于一个LV。

相互联系:在创建卷组时一定要为逻辑卷进行快照预留出空间,而后快照访问逻辑卷的另一个入口,只要把物理卷加到卷组之后,这个物理卷所提供的物理空间事先就被划分好一个个块,而这个块在没格式化之前叫做PE(Physical Extend)【物理盘区】,是逻辑存储的一个小匣子,卷组的大小是由多个PE组成,而逻辑卷的大小是把卷组中的PE放到逻辑卷中,此时,PE不再叫做PE,而是叫做LE(Logical Extend)【逻辑盘区】,其实,逻辑卷中的LE也叫做PE,只是站在角度不同而已。

如果某个物理卷损坏后,存储在逻辑卷中的LE也就会损坏,想让数据不损坏,可以把物理卷中PE做成镜像

逻辑卷管理布局,Linux 逻辑卷管理器(logical volume manager,LVM)可以让你在无需重建整个文件系统的情况下,轻松地管理磁盘空间。用标准分区在硬盘上创建了文件系统,为已有文件系统添加额外的空间多少是一种痛苦的体验。你只能在同一个物理硬盘的可用空间范围内调整分区大小。

         多个物理卷集中在一起可以形成一个卷组(volume group,VG)逻辑卷管理系统将卷组视 为一个物理硬盘,但事实上卷组可能是由分布在多个物理硬盘上的多个物理分区组成的卷组提供了一个创建逻辑分区的平台,而这些逻辑分区则包含了文件系统。

逻辑卷(logical volume,LV)逻辑卷为Linux提供了创建文件系统的分区环境,作用类似于到目前为止我们一直在探讨的Linux中的物理硬盘分区。Linux系统将逻 辑卷视为物理分区。 可以使用任意一种标准Linux文件系统来格式化逻辑卷,然后再将它加入Linux虚拟目录中的某个挂载点。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_85

Linux 中的 LVM

1. 快照

  • LVM1只允许你创建只读快照。一旦创建了快照,就不能再写入东西了。
  • LVM2允许你创建在线逻辑卷的可读写快照。有了可读写的快照,就可以删除原先的逻辑卷, 然后将快照作为替代挂载上。这个功能对快速故障转移或涉及修改数据的程序试验(如果失败, 需要恢复修改过的数据)非常有用。

这个功能叫作快照。在备份由于高可靠性需求而无法锁定的重要数据时,快照功能非常给力。传统的备份方法在将文件复制到备份媒体上时通常要将文件锁定。快照允许你在复制的同时,保证运行关键任务的。

2. 条带化,LVM2提供的另一个引人注目的功能是条带化(striping)。马毓姝

  • 条带化可跨多个物理硬盘创建逻辑卷。当Linux LVM将文件写入逻辑卷时,文件中的数据块会被分散到多个硬盘上。每个后继数据块会被写到下一个硬盘上。 
  • 条带化有助于提高硬盘的性能,因为Linux可以将一个文件的多个数据块同时写入多个硬盘, 而无需等待单个硬盘移动读写磁头到多个不同位置。这个改进同样适用于读取顺序访问的文件, 因为LVM可同时从多个硬盘读取数据。(多路复用)。

LVM条带化不同于RAID条带化。LVM条带化不提供用来创建容错环境的校验信息。事实 上,LVM条带化会增加文件因硬盘故障而丢失的概率。单个硬盘故障可能会造成多个逻 辑卷无法访问。 

3. 镜像

  • LVM逻辑卷也容易受到断电和磁盘故障的影响。一旦文件系统损坏,就有可能再也无法恢复。   LVM快照功能提供了一些安慰,你可以随时创建逻辑卷的备份副本,但对有些环境来说可能 还不够。对于涉及大量数据变动的系统

使用 Linux LVM

定义物理卷:  创建过程的第一步就是将硬盘上的物理分区转换成Linux LVM使用的物理卷区段, fdisk命令

  • 创建了基本的Linux分区之后,你需要通过t命令改变分区类型分区类型8e表示这个分区将会被用作Linux LVM系统的一部分,而不是一个直接的文件系统 (就像你在前面看到的83类型的分区)。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_86

  • 1. 用分区来创建实际的物理卷。这可以通过pvcreate命令来完成。pvcreate定义了 用于物理卷的物理分区。它只是简单地将分区标记成Linux LVM系统中的分区而已。想查看创建进度的话,可以使用pvdisplay命令来显示已创建的物理卷列表
  • 2. 创建卷组 ,物理卷中创建一个或多个卷组 命令行创建卷组,需要使用vgcreate命令。vgcreate命令需要一些命令行参数来定义 卷组名以及你用来创建卷组的物理卷名。 看新创建的卷组的细节,可用vgdisplay命令。
  • 创建逻辑卷 ,Linux系统使用逻辑卷来模拟物理分区,并在其中保存文件系统。Linux系统会像处理物理分 区一样处理逻辑卷,允许你定义逻辑卷中的文件系统,然后将文件系统挂载到虚拟目录上 创建逻辑卷,使用lvcreate命令。
    卷组名(Vol1)用来标识创建新逻辑卷时要使 用的卷组。 -l选项定义了要为逻辑卷指定多少可用的卷组空间。注意,你可以按照卷组空闲空间的百分 比来指定这个值。本例中为新逻辑卷使用了所有的空闲空间。
  • 4. 创建文件系统运行完 lvcreate命令之后,逻辑卷就已经产生了,但它还没有文件系统。
  • 5. 挂载逻辑分区, 在创建了新的文件系统之后,可以用标准Linux mount命令将这个卷挂载到虚拟目录中,就跟它是物理分区一样。唯一的不同是你需要用特殊的路径来标识逻辑卷
  • 6. 修改LVM Linux LVM的好处在于能够动态修改文件系统,因此最好有工具能够让你实现这些操作。在 Linux有一些工具允许你修改现有的逻辑卷管理配置。

fdisk命令用来对存储设备进行分区, 以便安装文件系统。在分区存储设备时,必须定义在上面使用什么类型的文件系统。

在存储设备分区上直接创建文件系统的一个限制因素是,如果硬盘空间用完了,你无法轻易 地改变文件系统的大小。但Linux支持逻辑卷管理,这是一种跨多个存储设备创建虚拟分区的方 法。这种方法允许你轻松地扩展一个已有文件系统,而不用完全重建。Linux LVM包提供了跨多 个存储设备创建逻辑卷的命令行命令。

>第9童安装软件程序

Linux上能见到的各种包管理系统(package management system,PMS),以及用来进行软件安装、管理和删除的命令行工具。

PMS工具及相关命令在不同的Linux发行版上有很大的不同。Linux中广泛使用的两种主要的 PMS基础工具是dpkg和rpm。

  • 基于Debian的发行版(如Ubuntu和Linux Mint)使用的是dpkg命令,这些发行版的PMS工具 也是以该命令为基础的.
  • 用 aptitude 管理软件包
  • 基于Red Hat的发行版(如Fedora、openSUSE及Mandriva)使用的是rpm命令,该命令是其PMS 的底层基础。类似于dpkg命令,rmp命令能够列出已安装包、安装新包和删除已有软件。
  •  yum:在Red Hat和Fedora中使用。

列出已安装包

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_87

如果需要找出系统上的某个特定文件属于哪个软件包,万能的yum可以做到!只要输 入命令: yum provides file_name

用 yum 安装软件 yum install package_name

  • 可以手动下载rpm安装文件并用yum安装,这叫作本地安装。基本的命令是: yum localinstall package_name.rpm
  • 对更新列表中的所有包进行更新,只要输入如下命令: yum update
  • 只删除软件包而保留配置文件和数据文件,就用如下命令: yum remove package_name
  • 要删除软件和它所有的文件,就用erase选项: yum erase package_name

处理损坏的包依赖关系   

  • 如果系统出现了这个问题,先试试下面的命令: yum clean all
  • yum update --skip-broken --skip-broken    选项允许你忽略依赖关系损坏的那个包,继续去更新其他软件包。这可能 救不了损坏的包,但至少可以更新系统上的其他包。
  • yum deplist package_name 

yum 软件仓库

  • 要想知道你现在正从哪些仓库中获取软件,输入如下命令: yum repolist
  • yum的仓库定义文件位于 /etc/yum.repos.d。你需要添加正确的URL,并获得必要的加密密钥。

>第10章使用编辑器

vi编辑器是Unix系统最初的编辑器。它使用控制台图形模式来模拟文本编辑窗口,允许查看 文件中的行、在文件中移动、插入、编辑和替换文本.

vim 编辑器

Linux which命令用于查找文件。which指令会在环境变量$PATH设置的目录里查找符合条件的文件。

readlink –f命令就可以了。它能够立刻找出链接文件的最后一环。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_88

  1. 如在启动vim时未指定文件名,或者这个文件不存在,vim会开辟一段新的缓冲区域来编辑。
  2. 如果你在命令行下指定了一个已有文件的名字,vim会将文件的整个内容都读到一块缓冲区域来准备编辑

vim编辑器有两种操作模式:  普通模式  插入模式

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_89

vim中有用来移动 光标的命令。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_90

  •  h:左移一个字符。
  •  j:下移一行(文本中的下一行)。
  •  k:上移一行(文本中的上一行)。
  •  l:右移一个字符。

在大的文本文件中一行一行地来回移动会特别麻烦,幸而vim提供了一些能够提高移动速度 的命令。

  •  PageDown(或Ctrl+F):下翻一屏。
  •  PageUp(或Ctrl+B):上翻一屏。
  •  G:移到缓冲区的最后一行。
  •  num G:移动到缓冲区中的第num行。
  •  gg:移到缓冲区的第一行。

vim编辑器在普通模式下有个特别的功能叫命令行模式。命令行模式提供了一个交互式命令 行,可以输入额外的命令来控制vim的行为。要进入命令行模式,在普通模式下按下冒号键。光标会移动到消息行,然后出现冒号,等待输入命令。

  •  q:如果未修改缓冲区数据,退出。
  •  q!:取消所有对缓冲区数据的修改并退出。
  •  w filename:将文件保存到另一个文件中。
  •  wq:将缓冲区数据保存到文件中并退出。

编辑数据

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_91

复制和粘贴

vim在 删除数据时,实际上会将数据保存在单独的一个寄存器中。可以用p命令取回数据。

vim中复制命令是y(代表yank)。可以在y后面使用和d命令相同 的第二字符(yw表示复制一个单词,y$表示复制到行尾)。输入p命令粘贴

查找和替换

  • 用vim查找命令来轻松查找缓冲区中的数据。要输入一个查找字符串,就按下斜线(/)
  •  如果要查找的文本出现在光标当前位置之后,则光标会跳到该文本出现的第一个位置。
  •  如果要查找的文本未在光标当前位置之后出现,则光标会绕过文件末尾,出现在该文本 所在的第一个位置(并用一条消息指明)。
  •  输出一条错误消息,说明在文件中没有找到要查找的文本。
  • 继续查找同一个单词,按下斜线键,然后按回车键。或者使用n键,表示下一个(next)
  • 替换命令允许你快速用另一个单词来替换文本中的某个单词。必须进入命令行模式才能使用 替换命令。替换命令的格式是: :s/old/new/
  •  :s/old/new/g:一行命令替换所有old。
  •  :n,ms/old/new/g:替换行号n和m之间所有old。
  •  :%s/old/new/g:替换整个文件中的所有old。
  •  :%s/old/new/gc:替换整个文件中的所有old,但在每次出现时提示。

其他编译器:

  • nano 编辑器:nano文本编辑器是Unix系统的Pico编辑器的克隆版。尽管Pico也是一款简单轻便的文本编辑 器,但是它并没有采用GPL许可协议。nano文本编辑器不仅采用了GPL许可协议,而且还加入了 GNU项目。
  • emacs 编辑器
  • KDE 系编辑器
  • GNOME 编辑器

第二部分 shell脚本编程基础

shell 的执行方式

  • 如果.不在PATH里面,要执行当前目录下的可执行文件,使用全路径:./executable-file
  • PATH是环境变量,如果将当前目录“./”添加到环境变量中,那么也可以不用“./”,直接输入当前目录下有可执行权限的可执行文件就可以运行了
  • 如果要执行一个sh脚本,不管那个脚本有没有可执行权限,都可以使用:sh [file]
  • 这时file是作为参数传给sh的,如果file不在当前目录下,也需要使用全路径。
  • 1、source命令用法:source FileName
     作用:在当前bash环境下读取并执行FileName中的命令。该filename文件可以无"执行权限",注:该命令通常用命令“.”来替代。source(或点)命令通常用于重新执行刚修改的初始化文档。    source命令(从 C Shell 而来)是bash shell的内置命令。点命令,就是个点符号,(从Bourne Shell而来)。
    2、sh和bash命令用法:  sh FileName、 bash FileName
         作用:在当前bash环境下读取并执行FileName中的命令。该filename文件可以无"执行权限" 注:两者在执行文件时的不同,是分别用自己的shell来跑文件 sh使用“-n”选项进行shell脚本的语法检查,使用“-x”选项实现shell脚本逐条语句的跟踪,可以巧妙地利用shell的内置变量增强“-x”选项的输出信息等。
    3、./的命令用法:  ./FileName
         作用:打开一个子shell来读取并执行FileName中命令。 注:运行一个shell脚本时会启动另一个命令解释器.每个shell脚本有效地运行在父shell(parent shell)的一个子进程里.这个父shell是指在一个控制终端或在一个xterm窗口中给你命令指示符的进程. shell脚本也可以启动他自已的子进程.   这些子shell(即子进程)使脚本并行地,有效率地地同时运行脚本内的多个子任务.

>第11章构建基本脚本

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_92

创建 shell 脚本文件

必须在文件的第一行指定要使用的shell,其格式为: #!/bin/bash

PATH环境变量被设置成只在一组目录中查找命令。要让shell找到test1脚本,只需采取以下两种作法之一:

  • 将shell脚本文件所处的目录添加到PATH环境变量中;
  • 在提示符中用绝对或相对文件路径来引用shell脚本文件。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_93

echo命令可用单引号或双引号来划定文本字符串。如果在字符串中用到了它们,你需要在 文本中使用其中一种引号,而用另外一种来将字符串划定起来。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_94

echo 取消换行;可以用echo语句 的-n参数。只要将第一个echo语句改成这样就行:

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_95

使用变量:

在shell命令使用 其他数据来处理信息。这可以通过变量来实现,常用环境变量,用户变量

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_96

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_97

命令替换,有两种方法可以将命令输出赋给变量:  反引号字符(`) $()格式

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_98

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_99

命令替换会创建一个子shell来运行对应的命令。子shell(subshell)是由运行该脚本的shell 所创建出来的一个独立的子shell(child shell)。正因如此,由该子shell所执行命令是无法 使用脚本中所创建的变量的

在命令行提示符下使用路径./运行命令的话,也会创建出子shell;要是运行命令的时候 不加入路径,就不会创建子shell。如果你使用的是内建的shell命令,并不会涉及子shell。 在命令行提示符下运行脚本时一定要留心!

重定向输入和输出

如果输出文件已经存在了,重定向操作(>)符会用新的文件数据覆盖已有文件。用双大于号(>>)来追加数据。

输入重定向和输出重定向正好相反。输入重定向将文件的内容重定向到命令,而非将命令的 输出重定向到文件。

一个简单的记忆方法就是:在命令行上,命令总是在左侧,而重定向符号“指向”数据流动 的方向。小于号说明数据正在从输入文件流向命令。

内联输入重定向(inline input redirection):须指定一个文本标记来划分输 入数据的开始和结尾。任何字符串都可作为文本标记,但在数据的开始和结尾文本标记必须一致。

wc命令可以对对数据中的文本进行计数。默认情况下,它会输出3个值:  文本的行数  文本的词数  文本的字节数。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_100

管道

管道符号在shell编程之外也很少用到。该符号由两个 竖线构成,一个在另一个上面。然而管道符号的印刷体通常看起来更像是单个竖线(|)。在美式 键盘上,它通常和反斜线(\)位于同一个键。管道被放在命令之间,将一个命令的输出重定向 到另一个命令中:

不要以为由管道串起的两个命令会依次执行。Linux系统实际上会同时运行这两个命令,在 系统内部将它们连接起来。在第一个命令产生输出的同时,输出会被立即送给第二个命令。数据 传输不会用到任何中间文件或缓冲区。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_101

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_102

执行数学运算:expr 命令

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_103

 

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_104

使用方括号:在bash中,在将一个数学运算结果赋给某个变量时,可以用美元符和 方括号($[ operation ])将数学表达式围起来。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_105

浮点解决方案;用内建的bash计算器, 叫作bc,能够识别: 数字(整数和浮点数)  变量(简单变量和数组)  注释(以#或C语言中的/* */开始的行)  表达式  编程语句(例如if-then语句)  函数

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_106

在脚本中使用bc,variable=$(echo "options; expression" | bc) 第一部分options允许你设置变量。如果你需要不止一个变量,可以用分号将其分开。 expression参数定义了通过bc执行的数学表达式。这里有个在脚本中这么做的例子。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_107

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_108

如果需要进行大量运算,最好的办法是使用内联输入重定向

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_109

在bash 计算器中创建的变量只在bash计算器中有效,不能在shell脚本中使用。

退出脚本

查看退出状态码:shell中运行的每个命令都使用退出状态码(exit status)告诉shell它已经运行完毕。

退出状态码被缩减到了0~255的区间。shell通过模运算得到这个结果。一个值的模就是被除 后的余数。最终的结果是指定的数值除以256后得到的余数。在这个例子中,指定的值是300(返 回值),余数是44,因此这个余数就成了最后的状态退出码。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_110

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_111

exit 命令

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_112

>第12章使用结构化命令

许多程序要求对shell脚本中的命令施加一些逻辑流程控制。有一类命令会根据条件使脚本跳 过某些命令。这样的命令通常称为结构化命令(structured command)

使用 if-then 语句

bash shell的if语句会运行if后面的那个命令。如果该命令的退出状态码(参见第11章)是0 (该命令成功运行),位于then部分的命令就会被执行(支持缩进,类似python)。如果该命令的退出状态码是其他值,then部分的命令就不会被执行,bash shell会继续执行脚本中的下一个命令。fi语句用来表示if-then 语句到此结束。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_113

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_114

if语句行使用grep命令在/etc/passwd文件中查找某个用户名当前是否在系统上使用。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_115

if-then-else 语句

当if语句中的命令返回退出状态码0时,then部分中的命令会被执行,这跟普通的if-then 语句一样。当if语句中的命令返回非零退出状态码时,bash shell会执行else部分中的命令。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_116

嵌套 if:要检查/etc/passwd文件中是否存在某个用户名以及该用户的目录是否尚在,可以使用嵌套的 if-then语句。嵌套的if-then语句位于主if-then-else语句的else代码块中。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_117

嵌套 if:要检查/etc/passwd文件中是否存在某个用户名以及该用户的目录是否尚在,可以使用嵌套的 if-then语句。嵌套的if-then语句位于主if-then-else语句的else代码块中。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_118

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_119

可以使用else部分的另一种形式:elif。这样就不用再书写多个if-then语句了。elif使 用另一个if-then语句延续else部分。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_120

elif语句行提供了另一个要测试的命令,这类似于原始的if语句行。如果elif后命令的退 出状态码是0,则bash会执行第二个then语句部分的命令。使用这种嵌套方法,代码更清晰,逻 辑更易懂。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_121

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_122

test 命令

test命令提供了在if-then语句中测试不同条件的途径,如果test命令中列出的条件成立, test命令就会退出并返回退出状态码0。这样if-then语句就与其他编程语言中的if-then语句 以类似的方式工作了。如果条件不成立,test命令就会退出并返回非零的退出状态码,这使得 if-then语句不会再被执行。

test condition


《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_123

如果不写test命令的condition部分,它会以非零的退出状态码退出,并执行else语句块。

当你加入一个条件时,test命令会测试该条件。例如,可以使用test命令确定变量中是否 有内容。这只需要一个简单的条件表达式。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_124

if [ condition ]
then
commands
fi

 方括号定义了测试条件。注意,第一个方括号之后和第二个方括号之前必须加上一个空格, 否则就会报错test命令可以判断三类条件:

  •  数值比较
    bash shell只能处理整数。如果你只是要通过echo语句来显示这个结果,那没问题

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_125

  •  字符串比较
    大于号和小于号必须转义,否则shell会把它们当作重定向符号,把字符串值当作文件 名;

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_126

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_127

  •  文件比较

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_128

  • 检查目录 -d测试会检查指定的目录是否存在于系统中。如果你打算将文件写入目录或是准备切换到某 个目录中,先进行测试总是件好事情。
  • 检查对象是否存在 -e比较允许你的脚本代码在使用文件或目录前先检查它们是否存在
  • 检查文件 -e比较可用于文件和目录。要确定指定对象为文件,必须用-f比较。
  • 检查是否可读 在尝试从文件中读取数据之前,最好先测试一下文件是否可读。可以使用-r比较测试。
  • 检查空文件 应该用-s比较来检查文件是否为空,尤其是在不想删除非空文件的时候。要留心的是,当 -s比较成功时,说明文件中有数据。
  • 检查是否可写 -w 比较会判断你对文件是否有可写权限。脚本test16.sh只是脚本test13.sh的修改版。现在不单 检查item_name是否存在、是否为文件,还会检查该文件是否有写入权限。
  • 检查文件是否可以执行 -x比较是判断特定文件是否有执行权限的一个简单方法。虽然可能大多数命令用不到它,但 如果你要在shell脚本中运行大量脚本,它就能发挥作用。
  • 检查所属关系 -O 比较可以测试出你是否是文件的属主。
  • 检查默认属组关系 -G比较会检查文件的默认组,如果它匹配了用户的默认组,则测试成功。由于-G比较只会 检查默认组而非用户所属的所有组,
  • 检查文件日期 -nt比较会判定一个文件是否比另一个文件新。如果文件较新,那意味着它的文件创建日 期更近。-ot比较会判定一个文件是否比另一个文件旧。如果文件较旧,意味着它的创建日期 更早。

复合条件测试

if-then语句允许你使用布尔逻辑来组合测试。有两种布尔运算符可用:

  •  [ condition1 ] && [ condition2 ]
  •  [ condition1 ] || [ condition2 ]

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_129

if-then 的高级特性

 用于数学表达式的双括号

 用于高级字符串处理功能的双方括号

使用双括号(( expression )) 双括号命令允许你在比较过程中使用高级数学表达式。test命令只能在比较中使用简单的 算术操作。双括号命令提供了更多的数学符号,不需要将双括号中表达式里的大于号转义。这是双括号命令提供的另一个高级特性。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_130

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_131


#!/bin/bash
#changing the IFS value
IFS=$'\n'
is=0
for entry in $(cat /etc/passwd)
do
echo "Values in $entry ? $is"
IFS=:
for value in $entry
do
if [ $is -eq 2 ]
then
break 2
fi
echo -n " $value "
done
echo
if [ $is -eq 3 ]
then
break
fi
(( is=$is ++ 1 ))
done

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_132

使用双方括号 [[ expression ]] 双方括号里的expression使用了test命令中采用的标准字符串比较。但它提供了test命 令未提供的另一个特性——模式匹配(pattern matching)

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_133

case 命令

case命令会将指定的变量与不同模式进行比较。如果变量和模式是匹配的,那么shell会执行 为该模式指定的命令。可以通过竖线操作符在一行中分隔出多个模式模式。星号会捕获所有与已 知模式不匹配的值。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_134

第13章更多的结构化命令

for命令

遍历:for命令最基本的用法就是遍历for命令自身所定义的一系列值。for循环假定每个值都是用空格分割的

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_135

读取列表中的复杂值,使用转义字符(反斜线)来将单引号转义; 使用双引号来定义用到单引号的值。

for命令用空格来划分列表中的每个值。如果在单独的数据值中有 空格,就必须用双引号将这些值圈起来

从变量读取列表

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_136

从命令读取值:生成列表中所需值的另外一个途径就是使用命令的输出。可以用命令替换来执行任何能产生输出的命令,然后在for命令中使用该命令的输出。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_137

更改字段分隔符:特殊的环境变量IFS,叫作内部字段分隔符(internal field separator)。 IFS环境变量定义了bash shell用作字段分隔符的一系列字符: 空格  制表符  换行符(解决但行数据中的空格问题)IFS=$'\n'

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_138

 读取 /etc/pwsswd文件,可以将IFS替换为:。

用通配符读取目录:应该将$file变 量用双引号圈起来

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_139

C语言风格的for命令

for (( variable assignment ; condition ; iteration process ))

 变量赋值可以有空格;  条件中的变量不以美元符开头;  迭代过程的算式未用expr命令格式。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_140

使用多个变量

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_141

while命令(可以使用多个测试命令)

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_142

until命令

until命令和while命令工作的方式完全相反,即条件问false时才循环。until命令要求你指定一个通常返回非零退 出状态码的测试命令

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_143

嵌套循环

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_144

循环处理文件数据

#!/bin/bash
#changing the IFS value
IFS.OLD=$IFS
IFS=$'\n'
is=0
for entry in $(cat /etc/passwd)
do
echo "Values in $entry – $is"
IFS=:
for value in $entry
do
echo -n " $value "
done
echo
is=$[ $is + 1 ]
if [ $is -eq 3 ]
then
break
fi
done

控制循环

 break命令  continue命令

跳出单个循环

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_145

跳出内部循环

[root@liruilong tmp]# sh ddd.sh
Values in root:x:0:0:root:/root:/bin/bash ? 0
root x 0 0 root /root /bin/bash
Values in bin:x:1:1:bin:/bin:/sbin/nologin ? 1
bin x 1 1 bin /bin /sbin/nologin
Values in daemon:x:2:2:daemon:/sbin:/sbin/nologin ? 2
daemon x 2 2 daemon /sbin /sbin/nologin
Values in adm:x:3:4:adm:/var/adm:/sbin/nologin ? 3


#!/bin/bash
#changing the IFS value
IFS=$'\n'
is=0
for entry in $(cat /etc/passwd)
do
echo "Values in $entry – $is"
IFS=:
for value in $entry
do
if [ $is -eq 3 ]
then
break
fi
echo -n " $value "
done
echo
if [ $is -eq 3 ]
then
break
fi
is=$[ $is + 1 ]
done

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_146

跳出外部循环

#!/bin/bash
#changing the IFS value
IFS=$'\n'
is=0
for entry in $(cat /etc/passwd)
do
echo "Values in $entry – $is"
IFS=:
for value in $entry
do
if [ $is -eq 2 ]
then
break 2 ##跳出
fi
echo -n " $value "
done
echo
if [ $is -eq 3 ]
then
break
fi
is=$[ $is + 1 ]
done

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_147

continue 命令

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_148

处理循环的輸出

在shell脚本中,你可以对循环的输出使用管道或进行重定向。这可以通过在done命令 之后添加一个处理命令来实现

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_149

实例

查找可执行文件:当你从命令行中运行一个程序的时候,Linux系统会搜索一系列目录来查找对应的文件。这 些目录被定义在环境变量PATH中。如果你想找出系统中有哪些可执行文件可供使用,只需要扫 描PATH环境变量中所有的目录就行了。

#!/bin/bash
IFS=:
echo "<head><title>可执行文件清单</title></head>" >fileSh.html
for folder in $PATH
do
echo "<h1> $folder: </h1>"
i=0
for file in $folder/*
do
if [ -x $file ];then
if [ $i -eq 3 ];then
echo '...'
break
fi
echo "<span>$file<span>"
(( i=$i++1 ))
fi
done
echo "<hr/>"
done >> fileSh.html
~
[root@liruilong tmp]# head  fileSh.html 
<h1> /usr/local/sbin: </h1>
<hr/>
<h1> /usr/local/bin: </h1>
<hr/>
<h1> /usr/sbin: </h1>
<span>/usr/sbin/accessdb<span>
<span>/usr/sbin/acs-plugin-manager<span>
<span>/usr/sbin/addgnupghome<span>
<span>/usr/sbin/addpart<span>
<span>/usr/sbin/adduser<span>
[root@liruilong tmp]# cat /dev/null > fileSh.html
[root@liruilong tmp]# head fileSh.html

 

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_150

<head><title>可执行文件清单</title></head>
<h1> /usr/local/sbin: </h1>
<hr/>
<h1> /usr/local/bin: </h1>
<hr/>
<h1> /usr/sbin: </h1>
<span>/usr/sbin/accessdb<span>
<span>/usr/sbin/acs-plugin-manager<span>
<span>/usr/sbin/addgnupghome<span>
...
<hr/>
<h1> /usr/bin: </h1>
<span>/usr/bin/[<span>
<span>/usr/bin/a2p<span>
<span>/usr/bin/abs2rel<span>
...
<hr/>
<h1> /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/bin: </h1>
<span>/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/bin/alt-java<span>
<span>/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/bin/appletviewer<span>
<span>/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/bin/clhsdb<span>
...
<hr/>
<h1> /usr/tomcat/apache-tomcat-9.0.21/lib: </h1>
<hr/>
<h1> /root/bin: </h1>
<hr/>
~
~

创建多个用户账户(直接指定默认密码不是加密的密码。所以无法登录)

#!/bin/bash
# process new user accounts
input="users.csv"
while IFS=',' read -r userid name passwd
do
echo "adding $userid"
useradd -c "$name" -p $passwd -m $userid
done < "$input"
~

小结

第14章处理用户输入

命令行参数

  • 向shell脚本传递数据的最基本方法是使用命令行参数。命令行参数允许在运行脚本时向命令 行添加数据。
  • bash shell会将一些称为位置参数(positional parameter)的特殊变量分配给输入到命令行中的 所有参数。
  • 位置参数变量是标准的数字$0是程序名,$1是第 一个参数,$2是第二个参数,依次类推,直到第九个参数$9
  • 每个参数都是用空格分隔的,所以shell会将空格当成两个值的分隔符。要在参数值中 包含空格,必须要用引号

读取脚本名:basename命令会返回不包含路径的脚本名

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_151

#!/bin/bash
# Using basename with the $0 parameter
#
name=$(basename $0)
echo
echo The script name is: $name
#!/bin/bash
# Testing a Multi-function script
#
name=$(basename $0)
#
if [ $name = "addem" ]
then
total=$[ $1 + $2 ]
#
elif [ $name = "multem" ]
then
total=$[ $1 * $2 ]
fi
#
echo
echo The calculated value is $total
#
~

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_152

测试参数:在使用参数前一定要检查其中是否存在数据,使用了-n测试来检查命令行参数$1中是否有数据

#!/bin/bash
# testing parameters before use
#
if [ -n "$1" ]
then
echo Hello $1, glad to meet you.
else
echo "Sorry, you did not identify yourself. "
fi

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_153

特殊参数变量

特殊变量$#含有脚本运行时携带的命令行参数的个数,也可用于参数前测试参数的总数。

抓取所有的数据:$*和$@变量可以在单个变量中存储所有的命令行参数

  • $*变量会将命令行上提供的所有参数当作一个单词保存。这个单词包含了命令行中出现的每 一个参数值。基本上$*变量会将这些参数视为一个整体
  • $@变量会将命令行上提供的所有参数当作同一字符串中的多个独立的单词。这样 你就能够遍历所有的参数值,得到每个参数。这通常通过for命令完成
[root@liruilong ~]# sh param.sh li rui long 
有几个参数 3
所有的参数:li rui long
all params: li rui long
$*方式
$*paramenter #1 = li rui long
2
$@方式
$@ Parameter #1 = li
$@ Parameter #2 = rui
$@ Parameter #3 = long
[root@liruilong ~]# vim param.sh
[root@liruilong ~]# vim param.sh

#!bin/bash
echo "有几个参数 ${#}"
echo "所有的参数:$*"
echo "all params: $@"
echo "\$*方式"
count=1
for param in "$*"
do
echo "\$*paramenter #$count = $param"
echo "$[ $count + 1 ]"
done

echo "\$@方式"
count=1
#
for param in "$@"
do
echo "\$@ Parameter #$count = $param"
count=$[ $count + 1 ]
done

移动变量

bash shell的shift命令能够用来操作命令行参 数。shift命令会根据它们的相对位置来移动命令行参数,

  • 默认情况下它会将每个参数变量向左移动一个位置。所以,变量$3 的值会移到$2中,变量$2的值会移到$1中,而变量$1的值则会被删除(注意,变量$0的值,也 就是程序名,不会改变)。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_154

shift方法
Parameter #1 = li
Parameter #2 = rui
Parameter #3 = long

echo "shift方法"
count=1
while [ -n "$1" ]
do
echo "Parameter #$count = $1"
count=$[ $count + 1 ]
shift
done

处理选项

在提取每个单独参数时,用case语句(参见第12章)来判断某个参数是否为选项。

case语句会检查每个参数是不是有效选项。如果是的话,就运行对应case语句中的命令。 不管选项按什么顺序出现在命令行上,这种方法都适用。

分离参数和选项,对Linux来说,这个特殊字符是双破折线(--)。shell会用双破折线来表明选项列表结束。:

使用 getopt 命令:getopt命令可以接受一系列任意形式的命令行选项和参数,并自动将它们转换成适当的格 式。它的命令格式如下:

getopt optstring parameters

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_155

在脚本中使用getopt 可以在脚本中使用getopt来格式化脚本所携带的任何命令行选项或参数

将选项标准化

在创建shell脚本时,显然可以控制具体怎么做。你完全可以决定用哪些字母选项以及它们的 用法。 但有些字母选项在Linux世界里已经拥有了某种程度的标准含义。如果你能在shell脚本中支 持这些选项,脚本看起来能更友好一些。

获得用户输入

基本的读取:read命令从标准输入(键盘)或另一个文件描述符中接受输入。在收到输入后,read命令 会将数据放进一个变量。

第15章呈现数据

理解输入和输出

标准文件描述符Linux系统将每个对象当作文件处理。这包括输入和输出进程。Linux用文件描述符(file descriptor)来标识每个文件对象。文件描述符是一个非负整数,可以唯一标识会话中打开 的文件。每个进程一次最多可以有九个文件描述符。出于特殊目的,bash shell保留了前三个文 件描述符(0、1和2)。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_156

 STDIN :STDIN文件描述符代表shell的标准输入。对终端界面来说,标准输入是键盘。shell从STDIN 文件描述符对应的键盘获得输入,在用户输入时处理每个字符。在使用输入重定向符号(<)时,Linux会用重定向指定的文件来替换标准输入文件描述符。 它会读取文件并提取数据,就如同它是键盘上键入的。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_157

STDOUT: STDOUT文件描述符代表shell的标准输出。在终端界面上,标准输出就是终端显示器。shell 的所有输出(包括shell中运行的程序和脚本)会被定向到标准输出中,也就是显示器。大多数bash命令会将输出导向STDOUT文件描述符。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_158

STDERR shell通过特殊的STDERR文件描述符来处理错误消息。STDERR文件描述符代表shell的标准错 误输出。shell或shell中运行的程序和脚本出错时生成的错误消息都会发送到这个位置。默认情况下,错误消息也会输出到显示器输出中。

重定向错误,只重定向错误

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_159

重定向错误和数据,为了避免错误信息散落在输出文件中,相较于标准输出,bashshell自动赋予了错误消息更高的优先级。这样你能够集中浏览错误信息了。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_160

在脚本中重定向输出

可以在脚本中用STDOUT和STDERR文件描述符以在多个位置生成输出,只要简单地重定向相应的文件描述符就行了。有两种方法来在脚本中重定向输出:临时重定向行输出 , 永久重定向脚本中的所有命令。

临时重定向:

如果有意在脚本中生成错误消息,可以将单独的一行输出重定向到STDERR,你所需要做的 是使用输出重定向符来将输出信息重定向到STDERR文件描述符。在重定向到文件描述符时,你 必须在文件描述符数字之前加一个&:

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_161

默认情况下,Linux会将STDERR导向STDOUT。但是,如果你在运行脚本时重定向了 STDERR,脚本中所有导向STDERR的文本都会被重定向。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_162

永久重定向

如果脚本中有大量数据需要重定向,那重定向每个echo语句就会很烦琐。取而代之,你可 以用exec命令告诉shell在脚本执行期间重定向某个特定文件描述符。

exec命令会启动一个新shell并将STDOUT文件描述符重定向到文件。脚本中发给STDOUT的所 有输出会被重定向到文件。 可以在脚本执行过程中重定向STDOUT。一旦重定向了STDOUT或STDERR,就很难再将它们重定向回原来的位置。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_163

在脚本中重定向输入:使用与脚本中重定向STDOUT和STDERR相同的方法来将STDIN从键盘重定向到其他 位置。exec命令允许你将STDIN重定向到Linux系统上的文件中。

创建自己的重定向

在shell 中最多可以有9个打开的文件描述符。其他6个从3~8的文件描述符均可用作输入或输出重定向。

创建输出文件描述符:可以用exec命令来给输出分配文件描述符。和标准的文件描述符一样,一旦将另一个文件 描述符分配给一个文件,这个重定向就会一直有效,直到你重新分配。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_164

重定向文件描述符: 怎么恢复已重定向的文件描述符。你可以分配另外一个文件描述符给标准文件描述 符,反之亦然

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_165

.

创建输入文件描述符:可以用和重定向输出文件描述符同样的办法重定向输入文件描述符

#!/bin/bash
# redirecting input file descriptors
exec 6<&0
exec 0< testfile
count=1
while read line
do
echo "Line #$count: $line"
count=$[ $count + 1 ]
done
exec 0<&6
read -p "Are you done now? " answer
case $answer in
Y|y) echo "Goodbye";;
N|n) echo "Sorry, this is the end.";;
esac
~

创建读写文件描述符:可以打开单个文件描述符来作为输入和输出。可以用同 一个文件描述符对同一个文件进行读写,由于你是对同一个文件进行数据读写,shell会维护一个 内部指针,指明在文件中的当前位置。

#!/bin/bash
# testing input/output file descriptor
exec 3<> testfile
read line <&3
echo "Read: $line"
echo "This is a test line" >&3
~

关闭文件描述符 (exec 3>&-):创建了新的输入或输出文件描述符,shell会在脚本退出时自动关闭它们。有些情况下,你需要在脚本结束前手动关闭文件描述符。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_166

列出打开的文件描述符

lsof命令会列出整个Linux系统打开的所有文件描述符

阻止命令输出

在Linux系统上null文件的标准位置是/dev/null。你重定向到该位置的任何数据都会被丢掉, 不会显示。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_167

也可以在输入重定向中将/dev/null作为输入文件。由于/dev/null文件不含有任何内容,程序员 通常用它来快速清除现有文件中的数据,而不用先删除文件再重新创建。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_168

创建临时文件

Linux系统有特殊的目录,专供临时文件使用。Linux使用/tmp目录来存放不需要永久保留的 文件。大多数Linux发行版配置了系统在启动时自动删除/tmp目录的所有文件。

系统上的任何用户账户都有权限在读写/tmp目录中的文件。这个特性为你提供了一种创建临 时文件的简单方法,而且还不用操心清理工作。

有个特殊命令可以用来创建临时文件。mktemp命令可以在/tmp目录中创建一个唯一的临时 文件。shell会创建这个文件,但不用默认的umask值

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_169

创建本地临时文件,mktemp命令的输出正是它所创建的文件的名字。在脚本中使用mktemp命令 时,可能要将文件名保存到变量中,这样就能在后面的脚本中引用了。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_170

mktemp命令的输出正是它所创建的文件的名字。在脚本中使用mktemp命令 时,可能要将文件名保存到变量中,这样就能在后面的脚本中引用了。

创建临时目录.

-d选项告诉mktemp命令来创建一个临时目录而不是临时文件

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_171

#!/bin/bash
# using a temporary directory
tempdir=$(mktemp -d dir.XXXXXX)
cd $tempdir
tempfile1=$(mktemp temp.XXXXXX)
tempfile2=$(mktemp temp.XXXXXX)
exec 7> $tempfile1
exec 8> $tempfile2
echo "Sending data to directory $tempdir"
echo "This is a test line of data for $tempfile1" >&7
echo "This is a test line of data for $tempfile2" >&8
~

记录消息

将输出同时发送到显示器和日志文件,这种做法有时候能够派上用场。你不用将输出重定向 两次,只要用特殊的tee命令就行.既能将数据保存在文件中,也能将数据显示在屏幕上。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_172

实例

文件重定向常见于脚本需要读入文件和输出文件时。这个样例脚本两件事都做了。它读取.csv 格式的数据文件,输出SQL INSERT语句来将数据插入数据库

shell脚本使用命令行参数指定待读取的.csv文件。.csv格式用于从电子表格中导出数据,所以 你可以把数据库数据放入电子表格中,把电子表格保存成.csv格式,读取文件,然后创建INSERT 语句将数据插入MySQL数据库。

书的这个地方可能有问题,加了 < 变成两个参数了。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_173

#!/bin/bash
# read file and create INSERT statements for MySQL
outfile='members.sql'
IFS=','
while read lname fname address city state zip
do
cat >> $outfile << EOF
INSERT INTO members (lname,fname,address,city,state,zip) VALUES
('$lname', '$fname', '$address', '$city', '$state', '$zip');
EOF
done < ${1}
[root@liruilong tmp]# vim mysql.sh 
[root@liruilong tmp]# cat members.csv
Blum,Richard,123 Main St.,Chicago,IL,60601
Blum,Barbara,123 Main St.,Chicago,IL,60601
Bresnahan,Christine,456 Oak Ave.,Columbus,OH,43201
Bresnahan,Timothy,456 Oak Ave.,Columbus,OH,43201

[root@liruilong tmp]#

脚本的输入/输出都可以从标准输 入(STDIN)/标准输出(STDOUT)重定向到系统中的任意文件。除了STDOUT,你可以通过重定 向STDERR输出来重定向由脚本产生的错误消息。这可以通过重定向与STDERR输出关联的文件描 述符(也就是文件描述符2)来实现。可以将STDERR输出和STDOUT输出到同一个文件中,也可 以输出到完全不同的文件中。这样就可以将脚本的正常消息同错误消息分离开。

第16章控制脚本

处理信号

Linux利用信号与运行在系统中的进程进行通信,不同的Linux信号以及Linux如 何用这些信号来停止、启动、终止进程。可以通过对脚本进行编程,使其在收到特定信号时执行 某些命令,从而控制shell脚本的操作。

Linux系统和应用程序可以生成超过30个信号,

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_174

默认情况下,bash shell会忽略收到的任何SIGQUIT (3)和SIGTERM (5)信号(正因为这样, 交互式shell才不会被意外终止)。但是bash shell会处理收到的SIGHUP (1)和SIGINT (2)信号。

生成信号;bash shell允许用键盘上的组合键生成两种基本的Linux信号。

  • 中断进程 Ctrl+C组合键会生成SIGINT信号,并将其发送给当前在shell中运行的所有进程
  • 暂停进程 Ctrl+Z组合键会生成一个SIGTSTP信号, 你可以在进程运行期间暂停进程,而无需终止它。尽管有时这可能会比较危险(比如,脚本 打开了一个关键的系统文件的文件锁),但通常它可以在不终止进程的情况下使你能够深入脚本 内部一窥究竟。
  • 停止shell中运行的任何进程。停止(stopping)进程跟终止(terminating)进程不同:停止进程会让程序继续保留在内存中,并能从上次停止的位置 继续运行。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_175

在S列中(进程状态),ps命令将已停止作业的状态为显示为T。这说明命令要么被跟踪,要 么被停止了。

如果在有已停止作业存在的情况下,你仍旧想退出shell,只要再输入一遍exit命令就行了。 shell会退出终止已停止作业。或者,既然你已经知道了已停止作业的PID,就可以用kill命令 来发送一个SIGKILL信号来终止它。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_176

在终止作业时,最开始你不会得到任何回应。但下次如果你做了能够产生shell提示符的操作 (比如按回车键),你就会看到一条消息,显示作业已经被终止了.

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_177

捕获信号:也可以不忽略信号,在信号出现时捕获它们并执行其他命令。trap命令允许你来指定shell 脚本要监看并从shell中拦截的Linux信号。如果脚本收到了trap命令中列出的信号,该信号不再 由shell处理,而是交由本地处理。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_178

[root@liruilong ~]# ./test1.sh 
This is a test script
Loop #1
Loop #2
Loop #3
Loop #4
Loop #5
Loop #6
^C Sorry! I have trapped Ctrl-C
Loop #7
^C Sorry! I have trapped Ctrl-C
Loop #8
^C Sorry! I have trapped Ctrl-C
Loop #9
^C Sorry! I have trapped Ctrl-C
Loop #10
This is the end of the test script
[root@liruilong ~]# cat test1.sh
#!/bin/bash
# Testing signal trapping
#
trap "echo ' Sorry! I have trapped Ctrl-C'" SIGINT
#
echo This is a test script
#
count=1
while [ $count -le 10 ]
do
echo "Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
#
echo "This is the end of the test script"
#

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_179

捕获脚本退出

除了在shell脚本中捕获信号,你也可以在shell脚本退出时进行捕获(类似于钩子进程)。这是在shell完成任务时 执行命令的一种简便方法。要捕获shell脚本的退出,只要在trap命令后加上EXIT信号就行。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_180

修改或移除捕获

脚本中的不同位置进行不同的捕获处理,只需重新使用带有新选项的trap命令。

#!/bin/bash
# Modifying a set trap
#
trap "echo ' Sorry... Ctrl-C is trapped.'" SIGINT
#
count=1
while [ $count -le 5 ]
do
echo "Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
#
trap "echo ' I modified the trap!'" SIGINT
#
count=1
while [ $count -le 5 ]
do
echo "Second Loop #$count"
sleep 1
count=$[ $count + 1 ]
done
#

两个破折号就行了,以在trap命令后使用单破折号来恢复信号的默认行为。单破折号和双破折号都可以 正常发挥作用

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_181

移除信号捕获后,脚本按照默认行为来处理SIGINT信号,也就是终止脚本运行。但如果信 号是在捕获被移除前接收到的,那么脚本会按照原先trap命令中的设置进行处理

以后台模式运行脚本

以后台模式运行shell脚本非常简单。只要在命令后加个&符就行了。运行多个后台作业,每次启动新作业时,Linux系统都会为其分配一个新的作业号和PID。通过ps命令,可以看到 所有脚本处于运行状态

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_182

在非控制台下运行脚本

nohup命令运行了另外一个命令来阻断所有发送给该进程的SIGHUP信号。这会在退出终端会 话时阻止进程退出。

shell会给命令分配一个作业号,Linux系统会为其分配一个PID号。区 别在于,当你使用nohup命令时,如果关闭该会话,脚本会忽略终端会话发过来的SIGHUP信号

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_183

由于nohup命令会解除终端与进程的关联,进程也就不再同STDOUT和STDERR联系在一起。 为了保存该命令产生的输出,nohup命令会自动将STDOUT和STDERR的消息重定向到一个名为 nohup.out的文件中。

nohup.out文件包含了通常会发送到终端显示器上的所有输出。在进程完成运行后,你可以查 看nohup.out文件中的输出结果。

作业控制

启动、停止、终止以及恢复作业的这些功能统称为作业控制,作业控制中的关键命令是jobs命令。jobs命令允许查看shell当前正在处理的作业。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_184

要想查看作业的PID,可以在jobs命令中加入-l选项

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_185

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_186

  • jobs命令输出中的加号和减号。带加号的作业会被当做默认作业。在使用 作业控制命令时,如果未在命令行指定任何作业号,该作业会被当成作业控制命令的操作对象。
  • 当前的默认作业完成处理后,带减号的作业成为下一个默认作业。任何时候都只有一个带加号的作业和一个带减号的作业,不管shell中有多少个正在运行的作业。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_187

  • 要以后台模式重启一个作业,可用bg命令加上作业号,当作业被转入后台模式时,并不会列出其PID。
  • 要以前台模式重启作业,可用带有作业号的fg命令。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_188

调整谦让度(修改脚本优先级)

在多任务操作系统中(Linux就是),内核负责将CPU时间分配给系统上运行的每个进程。调 度优先级(scheduling priority)是内核分配给进程的CPU时间(相对于其他进程)。在Linux系统 中,由shell启动的所有进程的调度优先级默认都是相同的。

调度优先级是个整数值,从-20(最高优先级)到+19(最低优先级)。默认情况下,bash shell 以优先级0来启动所有进程

nice 命令:nice命令允许你设置命令启动时的调度优先级。要让命令以更低的优先级运行,只要用nice 的-n命令行来指定新的优先级级别。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_189

nice命令的-n选项并不是必须的,只需要在破折号后面跟上优先级就行了。nice命令阻止普通系统用户来提高命令的优先级。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_190

renice 命令:它允许你指定 运行进程的PID来改变它的优先级。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_191

  •  只能对属于你的进程执行renice;
  •  只能通过renice降低进程的优先级;
  •  root用户可以通过renice来任意调整进程的优先级。 如果想完全控制运行进程,必须以root账户身份登录或使用sudo命令。

定时运行作业(定时任务)

Linux系统提供了多个在预选时间运行脚本的方法:at命令和cron表。每个方法都使用不同的技术来安排脚本的运行时间和频率。接下来会依次介绍这些方法。

用 at 命令来计划执行作业:at命令允许指定Linux系统何时运行脚本。at命令会将作业提交到队列中,指定shell何时运 行该作业。at的守护进程atd会以后台模式运行,检查作业队列来运行作业。大多数Linux发行 版会在启动时运行此守护进程。

atd守护进程会检查系统上的一个特殊目录(通常位于/var/spool/at)来获取用at命令提交的 作业默认情况下,atd守护进程会每60秒检查一下这个目录。有作业时,atd守护进程会检查 作业设置运行的时间。如果时间跟当前时间匹配,atd守护进程就会运行此作业。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_文件系统_192

at命令的基本格式非常简单: at [-f filename] time

time参数指定了Linux系统何时运行该作业。如果你指定的时间已经错过,at命令会在第二 天的那个时间运行指定的作业。

at命令能识别多种不同的时间格式。

  •  标准的小时和分钟格式,比如10:15。
  •  AM/PM指示符,比如10:15 PM。
  •  特定可命名时间,比如now、noon、midnight或者teatime(4 PM)。

除了指定运行作业的时间,也可以通过不同的日期格式指定特定的日期。

  •  标准日期格式,比如MMDDYY、MM/DD/YY或DD.MM.YY。
  •  文本日期,比如Jul 4或Dec 25,加不加年份均可。
  •  你也可以指定时间增量。
  •  当前时间+25 min
  •  明天10:15 PM
  •  10:15+7天

在你使用at命令时,该作业会被提交到作业队列(job queue)。作业队列会保存通过at命令 提交的待处理的作业。针对不同优先级,存在26种不同的作业队列。作业队列通常用小写字母a~z 和大写字母A~Z来指代。作业队列的字母排序越高,作业运行的优先级就越低(更高的nice值)。默认情况下,at的作业会被提交到a作业队列。如果想以更高优先级运行作业,可以用-q参数指定不同的队列字母。

获取作业的输出

当作业在Linux系统上运行时,显示器并不会关联到该作业,Linux系统会将 提交该作业的用户的电子邮件地址作为STDOUT和STDERR。任何发到STDOUT或STDERR的输出都 会通过邮件系统发送给该用户。使用e-mail作为at命令的输出极其不便。at命令利用sendmail应用程序来发送邮件。如 果你的系统中没有安装sendmail,那就无法获得任何输出!因此在使用at命令时,最好在脚本 中对STDOUT和STDERR进行重定向

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_193

at命令会显示分配给作业的作业号以及为作业安排的运行时间。-f选项指明使用哪个脚本 文件,now指示at命令立刻执行该脚本。如果不想在at命令中使用邮件或重定向,最好加上-M选项来屏蔽作业产生的输出信息。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_194

列出等待的作业:atq命令可以查看系统中有哪些作业在等待。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_195

删除作业:用atrm命令来删除等待中的作业。只能删除你提交的作业,不能删除其他人的。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_196

安排需要定期执行的脚本(脚本执行自动化)

Linux系统使用cron程序来安排要定期执行的作业。cron程序会在后台运行并检查一个特殊的 表(被称作cron时间表),以获知已安排执行的作业。

cron时间表 cron时间表采用一种特别的格式来指定作业何时运行。cron时间表允许你用特定值、取值范围(比如1~5)或者是通配符(星号)来指定条目其格式如下:

min hour dayofmonth month dayofweek command

  • 每天的10:15运行一个命令  :15 10 * * * command 
  • 每周一4:15 PM运行的命令:15 16 * * 1 command 
  • 在每个月的第一天中午12点执行命令   00 12 1 * * command 
  • 设置一个在每个月的最后一天执行的命令, 00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command 它会在每天中午12点来检查是不是当月的最后一天,如果是,cron将会运行该命令。
  • 命令列表必须指定要运行的命令或脚本的全路径名。 15 10 * * * /home/rich/test4.sh > test4out cron程序会用提交作业的用户账户运行该脚本。因此,你必须有访问该命令和命令中指定的 输出文件的权限。

构建cron时间表 每个系统用户(包括root用户)都可以用自己的cron时间表来运行安排好的任务。Linux提供 了crontab命令来处理cron时间表。要列出已有的cron时间表,可以用-l选项。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_197

默认情况下,用户的cron时间表文件并不存在。要为cron时间表添加条目,可以用-e选项。 在添加条目时,crontab命令会启用一个文本编辑器,使用已有的cron时间表作 为文件内容(或者是一个空文件,如果时间表不存在的话)。

crontab -e  为当前账户添加计划任务
crontab -e -u lisi 指定lisi账户添加计划任务
* * * * * date >> /opt/test 每分钟执行date任务
5-15 * * * * date >> /opt/test 每小时的5-15分钟
10,13,17 * * * * date >> /opt/test 每小时的10,13,17分钟执行
*/5 * * * * date >> /opt/test 每隔3分支执行一次
10-15/2 * * * * date >> /opt/test 每小时的10-15分钟里,每隔2分钟执行一次
crontab -r 删除计划任务
systemctl is-enabled crond.service 检测计划任务服务是否开机自启

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_198

浏览cron目录

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_199

因此,如果脚本需要每天运行一次,只要将脚本复制到daily目录,cron就会每天执行它。

anacron程序,主要用于执行错过的作业,如果某个作业在cron时间表中安排运行的时间已到,但这时候Linux系统处于关机状态,那么 这个作业就不会被运行。当系统开机时,cron程序不会再去运行那些错过的作业。要解决这个问 题,许多Linux发行版还包含了anacron程序。

这个功能常用于进行常规日志维护的脚本。如果系统在脚本应该运行的时间刚好关机, 日志文件就不会被整理,可能会变很大。通过anacron,至少可以保证系统每次启动时整理日 志文件。

anacron程序只会处理位于cron目录的程序,比如/etc/cron.monthly。它用时间戳来决定作业 是否在正确的计划间隔内运行了。每个cron目录都有个时间戳文件,该文件位于/var/spool/ anacron。

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_200

anacron时间表的基本格式和cron时间表略有不同

period delay identifier command

period条目定义了作业多久运行一次,以天为单位。anacron程序用此条目来检查作业的时间 戳文件。

  • delay条目会指定系统启动后anacron程序需要等待多少分钟再开始运行错过的脚本。
  • command条目包含了run-parts程序和一个cron脚本目录名。run-parts程序负责运行目录中传给它的 任何脚本。 
  • anacron不会运行位于/etc/cron.hourly的脚本。这是因为anacron程序不会处理执行时间 需求小于一天的脚本。
  • identifier条目是一种特别的非空字符串,如cron-weekly。它用于唯一标识日志消息和错误 邮件中的作业

使用新 shell 启动脚本

当用户登入bash shell时需要运行的启动文件

  •  $HOME/.bash_profile
[root@liruilong ~]# more /root/.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

export PATH
  •  $HOME/.bash_login
  •  $HOME/.profile

应该将需要在登录时运行的脚本放在上面第一个文件中。

每次启动一个新shell时,bash shell都会运行.bashrc文件。可以这样来验证:在主目录下 的.bashrc文件中加入一条简单的echo语句,然后启动一个新shell

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_linux_201

[root@liruilong ~]# cat .bashrc
# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
[root@liruilong ~]#

.bashrc文件通常也是通过某个bash启动文件来运行的。因为.bashrc文件会运行两次:一次是 当你登入bash shell时,另一次是当你启动一个bash shell时。如果你需要一个脚本在两个时刻都得 以运行,可以把这个脚本放进该文件中。

第三部分 高级shell脚本编程

第17章创建函数

基本的脚本函数:

创建方式:

function name { commands }
name() { commands }

要在脚本中使用函数,只需要像其他shell命令一样,在行中指定函数名就行了。 

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_bash_202

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_运维_203

返回值

bash shell会把函数当作一个小型脚本,运行结束时会返回一个退出状态码(参见第11章)。 有3种不同的方法来为函数生成退出状态码。

默认退出状态码:默认情况下,函数的退出状态码是函数中最后一条命令返回的退出状态码。在函数执行结束 后,可以用标准变量$?来确定函数的退出状态码

[root@liruilong shells]# vim test4.sh 
[root@liruilong shells]# sh test4.sh
testing the function:
trying to display a non-existent file
total 4
-rw-r--r-- 1 root root 184 Mar 18 19:26 test4.sh
The exit status is: 0
[root@liruilong shells]# vim test4.sh

#!/bin/bash
# testing the exit status of a function
func1() {
echo "trying to display a non-existent file"
ls -l
}
echo "testing the function: "
func1
echo "The exit status is: $?"
~

典型退出状态码及其含义

退出状态码

含义

0

命令运行成功

1

通知未知错误

2

误用shell命令

126

命令不可执行

127

没有找到命令

128

无效退出参数

128+x

linux信号x的严重错误

130

命令通过Ctrl+C终止

255

退出状态码越界

《Linux命令行与shell脚本编程大全(第3版)》读书笔记_操作系统_204

使用 return 命令:使用return命令来退出函数并返回特定的退出状态码。return命令允许指定一个 整数值来定义函数的退出状态码,从而提供了一种简单的途径来编程设定函数退出状态码。退出状态码必须是0~255

[root@liruilong shells]# vim test5.sh
[root@liruilong shells]# sh test5.sh
Enter a value: 12
doubling the value
The new value is 24
[root@liruilong shells]# vim test5.sh

#!/bin/bash
# using the return command in a function
function dbl {
read -p "Enter a value: " value
echo "doubling the value"
return $[ $value * 2 ]
}
##调用脚本
dbl
echo "The new value is $?"
  • 如果在用$?变量提取函数返回值之前执行了其他命令,函数的返回值就会丢失。记住,$? 变量会返回执行的最后一条命令的退出状态码
  • 由于退出状态码必须小于256,函数的结果必须生成 一个小于256的整数值。任何大于256的值都会产生一个错误值。

使用函数输出: result='dbl' 会将dbl函数的输出赋给$result变量

[root@liruilong shells]# sh test6.sh
Enter a value: 12
The new value is 24
[root@liruilong shells]# vim test6.sh

#!/bin/bash
# using the echo to return a value
function dbl {
read -p "Enter a value: " value
echo $[ $value * 2 ]
}
result=$(dbl)
echo "The new value is $result"

在函数中使用变量

向函数传递参数:函数可以使用标准的参数环境变量来表示命令行上传给函数的参数,函数名会在$0 变量中定义,函数命令行上的任何参数都会通过$1、$2等定义。也可以用特殊变量$#来判断传 给函数的参数数目

[root@liruilong shells]# vim test7.sh

#!/bin/bash
#!/bin/bash
# passing parameters to a function
function addem {
if [ $# -eq 0 ] || [ $# -gt 2 ]
then
echo -1
elif [ $# -eq 1 ]
then
echo $[ $1 + $1 ]
else
echo $[ $1 + $2 ]
fi
}
## 函数传参数·
echo -n "Adding 10 and 15: "
value=$(addem 10 15)
echo $value
echo -n "Let's try adding just one number: "
value=$(addem 10)
echo $value
echo -n "Now trying adding no numbers: "
value=$(addem)
echo $value
echo -n "Finally, try adding three numbers: "
value=$(addem 10 15 20)
echo $value

[root@liruilong shells]# sh test7.sh
Adding 10 and 15: 25
Let's try adding just one number: 20
Now trying adding no numbers: -1
Finally, try adding three numbers: -1

由于函数使用特殊参数环境变量作为自己的参数值,因此它无法直接获取脚本在命令行中的 参数值

在函数中处理变量:函数使用两种类型的变量:  全局变量  局部变量

  • 全局变量这里不多记了,用的基本都是局部变量:变量声明的前面加上local关键字。
  • 也可以在变量赋值语句中使用local关键字: local temp=$[ $value + 5 ],local关键字保证了变量只局限在该函数中。如果脚本中在该函数之外有同样名字的变量, 那么shell将会保持这两个变量的值是分离的
[root@liruilong shells]# sh test8.sh
The result is 22
temp is smaller
[root@liruilong shells]# vim test8.sh

#!/bin/bash
# demonstrating the local keyword
function func1 {
local temp=$[ $value + 5 ]
result=$[ $temp * 2 ]
}
temp=4
value=6
func1
echo "The result is $result"
if [ $temp -gt $value ]
then
echo "temp is larger"
else
echo "temp is smaller"
fi

数组变量和函数:

向函数传数组参数:如果试图将该数组变量作为函数参数,函数只会取数组变量的第一个值。

[root@liruilong shells]# sh test9.sh
The original array is: 1 2 3 4 5
The parameters are: 1
The received array is 1
[root@liruilong shells]# vim test9.sh

#!/bin/bash
# trying to pass an array variable
function testit {
echo "The parameters are: $@"
thisarray=$1
echo "The received array is ${thisarray[*]}"
}

myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
testit $myarray

解决办法:将该数组变量的值分解成单个的值,然后将这些值作为函数参数使 用。在函数内部,可以将所有的参数重新组合成一个新的变量.

[root@liruilong tmp]# sh test.sh
The original array is 1 2 3 4 5
The new array value is: 1 2 3 4 5
[root@liruilong tmp]# vim test.sh
#!/bin/bash
#rray variable to function test
function testit {
local newarray
newarray=( "$@")
echo "The new array value is: ${newarray[*]}"
}
myarray=(1 2 3 4 5)
echo "The original array is ${myarray[*]}"
testit ${myarray[*]}

从函数返回数组

从函数里向shell脚本传回数组变量也用类似的方法。函数用echo语句来按正确顺序输出单个 数组值,然后脚本再将它们重新放进一个新的数组变量中。

第18章图形化桌面环境中的脚本程

第19章初识sed和gawk2

第20正则表达式

第21章sed进阶

第22章gawk进阶"

第23章使用其他shell

第四部分创建实用的脚本

第24章编写简单的脚本实用工具2

第25章创建与数据库、Web及电子...

第26章一些小有意思的脚本

附录A bash命令快速指南

附录B sed和gawk快速指南

​https://pan.baidu.com/s/1872SOUVIVF4E-GwybOyxtw ​​ 提##:iokd