Linux基础(1)

初识Linux-Linux入门-CSDNCS入门技能树

下面列出几个主要的Linux distributions发行者网址:

Red Hat: http://www.redhat.com

SuSE: https://www.suse.com

Fedora: https://getfedora.org/

CentOS: http://www.centos.org/

Debian: http://www.debian.org/

Ubuntu: http://www.ubuntu.com/

Gentoo: Welcome – Gentoo Linux

目录

1. Linux介绍

1.1 Linux distribution

1.2 bash进站与欢迎界面

1.3 终端机环境设置

1.4 屏幕操作命令

1.5 登录退出与重启

1.6 运行级别(多重登录环境的7个基本终端窗口)

2. 文件目录

2.1. 常见文件操作

2.1.1. 取得路径的文件名与目录名

2.1.2. 查看文件内容的指令

2.1.3. 修改文件时间或创建文件 touch

2.1.4. 观察文件类型:file

2.1.5. 查找文件

2.2. 常用文件介绍

2.2.1. Linux文件类型

2.2.2. Linux目录配置的依据--FHS

2.3. 文件与目录的默认权限与隐藏权限

2.3.1. 文件默认权限设置:umask

2.3.2. 文件隐藏属性

2.3.3. 文件特殊权限 SUID, SGID, SBIT

2.3.4. 权限与指令间的关系(重要)

2.4. 文件权限与目录配置

2.4.1. 改变文件属性和权限

2.4.2. 目录与文件之权限意义

2.5. Linux用户与群组

2.5.1. Linux识别用户

/etc/passwd 文件结构

/etc/shadow文件结构

用户切换

找回密码

2.5.2. 群组

/etc/group文件结构

有效群组与初始群组

/etc/gshadow文件结构

群组与用户的关系

账号管理

用户新增删除

用户与群组的设置

Linu用户管理

2.6. 工作/定时调度

2.6.1. 常见例行调度

2.6.2. at

2.6.2.1. at的运行方式

2.6.2.2. at 的使用

2.6.2.3. at 的后台执行

2.6.2.4. at工作的管理

2.6.3. cron

2.6.3.1. 使用者设置

2.6.3.2. 使用

2.6.4. 唤醒停机期间未进行的任务 anacron

2.6.4.1. anacron执行流程

3. 程序管理

3.1. 什么是程序?

3.1.1. process和program

3.1.2. 程序调用的流程 fork-and-exec

3.1.3. 系统或网络服务 : 常驻内存的程序

3.2. 工作管理(job control)/后台运行

3.2.1. 将指令丢到背景中“执行”的 &

3.2.2. 将目前工作丢到背景中暂停 : Ctrl+z

3.2.3. 观察并恢复目前的背景工作 : jobs

3.2.4. 将背景工作拿到前景来处理:fg

3.2.5. 后台下的状态变成前台运行: bg

3.2.6. 管理背景当中的工作: kill

3.2.7. 离线管理 nohup

3.3. 程序的观察 ps和top

3.3.1. ps

3.3.2. 僵尸程序

3.3.3. top

3.3.4. pstree

3.3.5. 执行优先级调整

3.4. 系统资源的观察

3.4.1. free 观察内存

3.4.2. uname:查阅系统与核心相关信息

3.4.3. uptime:观察系统启动时间与工作负载

3.4.4. netstat :追踪网络或插槽档

3.4.5. dmesg :分析核心产生的讯息

3.4.6. vmstat :侦测系统资源变化

4. 特殊文件与程序

4.1. 具有 SUID/SGID 权限的指令执行状态

4.2. /proc/* 代表的意义

4.3. 查询已打开文件或已执行程序打开的文件

4.4. lsof :列出被程序所打开的文件文件名

4.5. pidof :找出某支正在执行的程序的 PID

5. 系统服务daemons

5.1. 什么是 daemon 与服务 (service)

5.2. daemon 的主要分类

5.2.1. systemd 的配置文件放置目录

5.2.2. systemd 的 unit 类型分类说明

5.3. 通过 systemctl 管理服务

5.3.1. systemctl 管理单一服务(service unit)的启动/开机启动与观察状态

5.3.2. 通过 systemctl 观察系统上所有的服务

5.3.3. systemctl 配置文件相关目录简介

5.3.4. systemctl 配置文件的设置项目简介

5.3.5. 使用Systemd管理应用进程

5.3.6. 以系统服务启动说明

5.3.7. systemctl 针对 timer 的配置文件(定时启动服务)

6. 软件安装: 源代码与Tarball

6.1. 编译器与可执行文件

6.1.1. 二进制文件

6.1.2. 函数库

6.2. make 与 configure

6.3. 什么是Tarball的软件

6.3.1. 安装与升级软件

6.3.2. 传统语言进行编译的范例

6.3.3. 主、副程序链接 :副程序的编译

6.3.4. 调用外部函数库:加入链接的函数库

6.3.5. gcc的简易用法

6.3.6. make进行宏编译

6.3.7. makefile 的基本语法与变量

6.4. Tarball的管理与安装的指令

6.5. 一般 Tarball 软件安装的建议事项 (如何移除?升级?)

6.5.1. Linux distribution 默认的安装软件的路径

6.5.2. 示例

6.5.3. 利用 patch 更新源代码

6.6. 函数库管理

6.6.1. 动态与静态函数库

6.6.2. ldconfig 与 /etc/ld.so.conf

6.6.3. 程序的动态函数库解析: ldd

6.7. 检验软件正确性

6.7.1. md5sum / sha1sum / sha256sum

7. 软件安装 RPM, SRPM 与 YUM

7.1. Linux 界的两大主流: RPM 与 DPKG

7.2. 什么是 RPM 与 SRPM

7.2.1. 什么是 i386, i586, i686, noarch, x86_64

7.2.2. RPM 属性相依的克服方式: YUM 线上升级

7.3. RPM 软件管理程序: rpm

7.3.1. RPM 默认安装的路径

7.3.2. RPM 安装 (install)

7.3.3. RPM 升级与更新 (upgrade/freshen)

7.3.4. RPM 查询 (query)

7.3.5. RPM验证与数码签章(Verify/signature)

7.3.5.1. RPM验证文件改动

7.3.5.2. 数码签章 (digital signature)

7.3.6. RPM 反安装(卸载)与重建数据库 (erase/rebuilddb)

7.4. YUM线上升级机制

7.4.1. 利用 yum 进行查询、安装、升级与移除功能

7.4.2. yum 的配置文件

7.4.3. 修改软件库产生的问题与解决之道


1. Linux介绍

1.1 Linux distribution

为了让使用者能够接触到Linux,于是很多的商业公司或非营利团体, 就将Linux Kernel(含tools)与可运行的软件整合起来,加上自己具有创意的工具程序, 这个工具 程序可以让使用者以光盘/DVD或者通过网络直接安装/管理Linux系统。 这个“Kernel + Softwares + Tools + 可完整安装程序”的咚咚,我们称之为Linux distribution,一般中文 翻译为“可完整安装套件”,或Linux发布商套件等.

事实上鸟哥认为distributions主要分为两大系统:

  1. 一种是使用RPM方式安装软件的系统,包括Red Hat, Fedora, SuSE等都是这类;
  2. 一种则是使用Debian的dpkg方式安装软件的系统,包括Debian, Ubuntu, B2D等等。

1.2 bash进站与欢迎界面

在终端机接口 (tty1 ~ tty6) 登陆的时候,会有几行提示的字串 , 那就是进站画面

  1. 提示字符串存放位置 :
    1. /etc/issue : 终端机接口 (tty1 ~ tty6) 登陆的时候用的
    2. /etc/issue.net : 提供给telnet这个远程登录程序用的
  1. issue文件中的内容也是可以使用反斜线作为变量取用(类似PS1变量定义的内容一样)
  2. man issue man agetty 得到issue内的各个代码的意义 如下:
\d 本地端时间的日期
\l 显示第几个终端机接口;
\m 显示硬件的等级 (i386/i486/i586/i686...);
\n 显示主机的网络名称;
\O 显示 domain name;
\r 操作系统的版本 (相当于 uname -r)
\t 显示本地端时间的时间;
\S 操作系统的名称;
\v 操作系统的版本。

您想要让使用者登陆后取得一些讯息,例如您想要让大家都知道的讯息, 那么可以将讯息加入 /etc/motd 里面去 (一定要用 root 的身份才能修改!)

1.3 终端机环境设置

stty(setting tty) 和 set 指令

stty : 设置快捷键的作用

set : 设置一下终端机环境

[dmtsai@study ~]$ stty [-a]
  选项与参数:
  -a :将目前所有的 stty 参数列出来;
# 范例一:列出所有的按键与按键内容
[dmtsai@study ~]$ stty -a
speed 38400 baud; rows 20; columns 90; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>;
swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V;
flush = ^O; min = 1; time = 0;
...

几个重要的代表意义是:
  # intr : 送出一个 interrupt (中断) 的讯号给目前正在 run 的程序 (就是终止啰!);
  # quit : 送出一个 quit 的讯号给目前正在 run 的程序;
  # erase : 向后删除字符,
  # kill : 删除在目前命令行上的所有文字;
  # eof : End of file 的意思,代表“结束输入”。
  # start : 在某个程序停止后,重新启动他的 output
  # stop : 停止目前屏幕的输出;
  # susp : 送出一个 terminal stop 的讯号给正在 run 的程序。

# 设置按键的作用
[dmtsai@study ~]$ stty erase ^h # 这个设置看看就好,不必真的实做!不然还要改回来!


在 Linux 下面使用 vim 时,却也经常不小心就按下 [crtl]+s !问题来了,按下这个组合钮之后,整个 vim
就不能动了 (整个画面锁死)! 请问该如何处置?
# 有个 stop 的项目就是按下 [crtl]+s 的!那么恢复成 start 就是 [crtl]+q

1.4 屏幕操作命令

Ctrl + C 终止目前的命令

Ctrl + D 输入结束 (EOF),例如邮件结束的时候;

Ctrl + M 就是 Enter 啦!

Ctrl + S 暂停屏幕的输出

Ctrl + Q 恢复屏幕的输出

Ctrl + U 在提示字符下,将整列命令删除

Ctrl + Z “暂停”目前的命令

[dmtsai@study ~]$ set [-uvCHhmBx]
    选项与参数:
    -u :默认不启用。若启用后,当使用未设置变量时,会显示错误讯息;
    -v :默认不启用。若启用后,在讯息被输出前,会先显示讯息的原始内容;
    -x :默认不启用。若启用后,在指令被执行前,会显示指令内容(前面有 ++ 符号)
    -h :默认启用。与历史命令有关;
    -H :默认启用。与历史命令有关;
    -m :默认启用。与工作管理有关;
    -B :默认启用。与刮号 [] 的作用有关;
    -C :默认不启用。若使用 > 等,则若文件存在时,该文件不会被覆盖。
# 范例一:显示目前所有的 set 设置值
[dmtsai@study ~]$ echo $-
himBH
# 那个 $- 变量内容就是 set 的所有设置啦! bash 默认是 himBH 喔!

# 范例二:设置 "若使用未定义变量时,则显示错误讯息"
[dmtsai@study ~]$ set -u
[dmtsai@study ~]$ echo $vbirding
-bash: vbirding: unbound variable
# 默认情况下,未设置/未宣告 的变量都会是“空的”,不过,若设置 -u 参数,
# 那么当使用未设置的变量时,就会有问题啦!很多的 shell 都默认启用 -u 参数。
# 若要取消这个参数,输入 set +u 即可!

# 范例三:执行前,显示该指令内容。
[dmtsai@study ~]$ set -x
++ printf '\033]0;%s@%s:%s\007' dmtsai study '~' # 这个是在列出提示字符的控制码!
[dmtsai@study ~]$ echo ${HOME}
+ echo /home/dmtsai
/home/dmtsai
++ printf '\033]0;%s@%s:%s\007' dmtsai study '~'
# 看见否?要输出的指令都会先被打印到屏幕上喔!前面会多出 + 的符号!

1.5 登录退出与重启

# 现在关机或1分钟后关机(h就是halt)(并会断开远程工具的连接)
halt/shutdown -h now/shutdown -h 1	
# 立即重启(并会断开远程工具的连接)
reboot/shutdown -r now	
# 将内存数据同步磁盘
sync	


exit	命令行界面:退出用户登录;
有图形界面:退出终端(小黑板)而非系统
登陆失败	用户登录名把大写字母换成小写字母
clear/ctrl+L	清屏
shell解释	作为命令和内核之间的解释器(国内一般是bash);shell壳的意思,对内隐藏OS内核细节,对外为用户提供服务

查看默认级别:systemctl get-default
设置默认级别:systemctl set-default TARGET.target(在centos7以前,/etc/inittab文件中 .进行了简化,如下:
multi-user.target: analcgous to runlevel 3
graphical.targe : analcgous to runlevel 5)
如:systemctl set-default multi-user.target
Linux不识别小键盘	

常用命令

halt/shutdown -h now/shutdown -h 1

现在关机或1分钟后关机(h就是halt)(并会断开远程工具的连接)

reboot/shutdown -r now

立即重启(并会断开远程工具的连接)

sync

将内存数据同步磁盘

su(su - 用户名)

权限高的切换到权限低的不需密码;反之需要

切换为root用户(其他用户);

su - username 和su username 最大的区别的就是是否切换环境,带-是同时切换环境,某些命令才可以执行:如logout才有效

logout

注销用户:退出当前用户(在图形界面无效)

当root到其他用户:可以logout回退到root,再logout就会退出系统(注意必须是su -切换才可)

exit

命令行界面:退出用户登录;

有图形界面:退出终端(小黑板)而非系统

1.6 运行级别(多重登录环境的7个基本终端窗口)

  1. 在 Linux 当中,默认提供了六个文字界面登陆窗口,以及一个图形界面,你可以使用 [Alt]+[F1].....[F7] 来切换不同的终端机界面,而且每个终端机界面的登陆者还可以不同人!这个东西可就很有用啦!尤其是在某个程序死掉的时候
  2. 其实,这也是多任务环境下所产生的一个情况啦!我们的 Linux 默认会启动六个终端机登陆环境的程序所以我们就会有六个终端机接口。 您也可以减少啊!就是减少启动的终端机程序就好了。

Init [0,1,2,3,4,5,6]

0 : 关机

1 : 单用户【找回丢失密码】

2:多用户状态没有网络服务

3∶多用户状态有网络服务

4∶系统未使用保留给用户

5 : 图形界面

6:系统重启

常用运行级别是3和5

也可以指定默认运行级别

切换运行级别(如多用户有网络切换到图形界面):其实就是纯命令行到图形界面;或者关机等

Linux 几乎可以说绝对不会死机的!因为他可以在任何时候, 将某个被困住的程序杀掉,然后再重新执行该程序而不用重新开机!

那么如果我在 Linux 下以文字界面登陆,在屏幕当中显示错误讯息后就挂了~动都不能动,该如何是好? 这个时候那默认的七个窗口就帮上忙啦!你可以随意的再按 [Alt]+[F1].....[F7] 来切换到其他的终端机界面,然后以 ps -aux 找出刚刚的错误程序,然后给他 kill 一下,回到刚刚的终端机界面恢复正常!

为什么可以这样做呢?每个程序之间可能是独立的,也可能有相依性, 只要到独立的程序当中,删除有问题的那个程序,当然他就可以被系统移除掉 .

systemctl get-default									# 查看默认级别
systemctl set-default TARGET.target   # 设置默认级别

# TARGET.target(在centos7以前,/etc/inittab文件中 .进行了简化,如下:
multi-user.target: analcgous to runlevel 3
graphical.targe : analcgous to runlevel 5)
如:systemctl set-default multi-user.target

2. 文件目录

tmp:临时目录,有时Linux会清理,不能存放重要数据

  1. file 命令用于确定文件的类型。
  2. 它通过检查文件的内容和元数据来识别文件的类型,并输出相应的信息。
  3. file 命令可以识别各种类型的文件,包括文本文件、二进制文件、压缩文件、图像文件等。它可以告诉您文件是什么类型的,例如文本文件、可执行文件、图像文件、音频文件等。
  4. 语法 : file 文件/目录路径

2.1. 常见文件操作

2.1.1. 取得路径的文件名与目录名
  1. basename /etc/sysconfig/network : network 就取得最后的文件名
  2. dirname /etc/sysconfig/network : /etc/sysconfig 取得的变成目录名了!

2.1.2. 查看文件内容的指令

cat : Concatenate(连续),从第一行开始显示文件内容;

tac : 从最后一行开始显示,是cat倒写

nl : 显示的时候, 顺道输出行号

more : 一页一页的显示文件内容

less : 与more类似, 但比more更好的是, 可以往前翻页

head : 只看头几行

tail : 尾部几行

od : 以二进制方式读取文件内容

cat [-AbEnTv] 文件名
	-A :相当于 -vET 的整合选项,可列出一些特殊字符而不是空白而已;
  -b :列出行号,仅针对非空白行做行号显示,空白行不标行号!
  -E :将结尾的断行字符 $ 显示出来;
  -n :打印出行号,连同空白行也会有行号,与 -b 的选项不同;(常用)
  -T :将 [tab] 按键以 ^I 显示出来;
  -v :列出一些看不出来的特殊字符

nl [-bnw] 文件
选项与参数:
  -b :指定行号指定的方式,主要有两种:
      -b a :表示不论是否为空行,也同样列出行号(类似 cat -n);
      -b t :如果有空行,空的那一行不要列出行号(默认值);
  -n :列出行号表示的方法,主要有三种:
      -n ln :行号在屏幕的最左方显示;
      -n rn :行号在自己字段的最右方显示,且不加 0 ;
      -n rz :行号在自己字段的最右方显示,且加 0 ;
  -w :行号字段的占用的字符数。

more
  空白键 (space):代表向下翻一页;
  Enter :代表向下翻“一行”;
  /字串 :代表在这个显示的内容当中,向下搜寻“字串”这个关键字;重复搜寻同一个字串,可以直接按下 n 即可
  :f :立刻显示出文件名以及目前显示的行数;
  q :代表立刻离开 more ,不再显示该文件内容。
  b 或 [ctrl]-b :代表往回翻页,不过这动作只对文件有用,对管线无用。

less : 可以向前翻页
	
  空白键 :向下翻动一页;
  [pagedown]:向下翻动一页;
  [pageup] :向上翻动一页;
  /字串 :向下搜寻“字串”的功能;
  ?字串 :向上搜寻“字串”的功能;
  n :重复前一个搜寻 (与 / 或 ? 有关!)
  N :反向的重复前一个搜寻 (与 / 或 ? 有关!)
  g :前进到这个数据的第一行去;
  G :前进到这个数据的最后一行去 (注意大小写);
  q :离开 less 这个程序;


head 与 tail 都是以“行”为单位来进行数据撷取

head [-n number] 文件
	-n :后面接数字,代表显示几行的意思
head -n -100 /etc/man_db.conf # 就会列出前面31行,后面100行不会打印出来
tail -n +100 /etc/man_db.conf” # 代表该文件从100行以后都会被列出来,前面的99行都不会被显示出来

od [-t TYPE] 文件
	-t :后面可以接各种“类型 (TYPE)”的输出,例如:
    a :利用默认的字符来输出;
    c :使用 ASCII 字符来输出
    d[size] :利用十进制(decimal)来输出数据,每个整数占用 size Bytes ;
    f[size] :利用浮点数值(floating)来输出数据,每个数占用 size Bytes ;
    o[size] :利用八进位(octal)来输出数据,每个整数占用 size Bytes ;
    x[size] :利用十六进制(hexadecimal)来输出数据,每个整数占用 size Bytes ;

基本上,在一般的环境中,使用 [tab] 与空白键的效果差不多,都是一堆空白啊!我们无法知道两者的差别。此时使用 cat -A 就能够发现那些空白的地方是啥鬼东西了![tab]会以 ^I 表示, 断行字符则是以 $ 表示,所以你可以发现每一行后面都是 $ !不过断行字符在Windows/Linux则不太相同,Windows的断行字符是 ^M$

2.1.3. 修改文件时间或创建文件 touch

有三个主要的变动时间 :

  1. modification time mtime): 当该文件的“内容数据”变更时,就会更新这个时间!内容数据指的是文件的内容,而不是文件的属性或权限喔!
  2. status time ctime):当该文件的“状态 (status)”改变时,就会更新这个时间,举例来说,像是权限与属性被更改了,都会更新这个时间啊。
  3. access time atime):当“该文件的内容被取用”时,就会更新这个读取时间 (access)。举例来说,我们使用 cat 去读取 /etc/man_db.conf , 就会更新该文件的 atime 了。

在默认的情况下,ls 显示出来的是该文件的 mtime

即使我们复制一个文件时,复制所有的属性,但也没有办法复制 ctime 这个属性的。

[root@study ~]$ date; ls -l /etc/man_db.conf ; ls -l --time=atime /etc/man_db.conf ; \
> ls -l --time=ctime /etc/man_db.conf

Tue Jun 16 00:43:17 CST 2015 # 目前的时间!
-rw-r--r--. 1 root root 5171 Jun 10 2014 /etc/man_db.conf # 在 2014/06/10 创建的内容(mtime)
-rw-r--r--. 1 root root 5171 Jun 15 23:46 /etc/man_db.conf # 在 2015/06/15 读取过内容(atime)
-rw-r--r--. 1 root root 5171 May 4 17:54 /etc/man_db.conf # 在 2015/05/04 更新过状态(ctime)

万一发现一个文件来自未来,如何让该文件的时间变成“现在”的时刻?就用“touch”这个指令

touch [-acdmt] 文件
    -a :仅修订 access time;
    -c :仅修改文件的时间,若该文件不存在则不创建新文件;
    -d :后面可以接欲修订的日期而不用目前的日期,也可以使用 --date="日期或时间"
    -m :仅修改 mtime ;
    -t :后面可以接欲修订的时间而不用目前的时间,格式为[YYYYMMDDhhmm]

touch 文件
在默认的状态下,如果 touch 后面有接文件,则该文件的三个时间 (atime/ctime/mtime) 
都会更新为目前的时间。若该文件不存在,则会主动的创建一个新的空的文件

touch -d "2 days ago" bashrc 	# 将日期调整为两天前
touch -t 201406150202 bashrc	# 日期改为 2014/06/15 2:02
2.1.4. 观察文件类型:file
[root@study ~]# file ~/.bashrc
/root/.bashrc: ASCII text <==告诉我们是 ASCII 的纯文本文件啊!
[root@study ~]# file /usr/bin/passwd
/usr/bin/passwd: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically
linked (uses shared libs), for GNU/Linux 2.6.32,
BuildID[sha1]=0xbf35571e607e317bf107b9bcf65199988d0ed5ab, stripped
# 可执行文件的数据可就多的不得了!包括这个文件的 suid 权限、相容于 Intel x86-64 等级的硬件平台
# 使用的是 Linux 核心 2.6.32 的动态函数库链接等等。
[root@study ~]# file /var/lib/mlocate/mlocate.db
/var/lib/mlocate/mlocate.db: data <== 这是 data 文件!

2.1.5. 查找文件
指令文件名的搜寻:
  which [-a] command	# 这个指令是根据“PATH”这个环境变量所规范的路径,去搜寻“可执行文件”的文件名
    -a :将所有由 PATH 目录中可以找到的指令均列出,而不止第一个被找到的指令名称
      怎么 history 这个常用的指令竟然找不到啊!为什么呢?这是因为 history 是“bash 内置的指令”
      但是 which 默认是找 PATH 内所规范的目录,所以当然一定找不到的(有 bash 就有 history!)!
      那怎办?没关系!我们可以通过type 这个指令
	type

文件文件名的搜寻:	
# find 不很常用的!因为速度慢之外,也很操硬盘,如果真的找不到了,才以 find 来搜寻! 
# 为什么呢?因为 whereis只找系统中某些特定目录下面的文件而已,locate 则是利用数据库来搜寻文件名
whereis [-bmsu] 文件或目录名
    -l :可以列出 whereis 会去查询的几个主要目录而已
    -b :只找 binary 格式的文件
    -m :只找在说明文档 manual 路径下的文件
    -s :只找 source 来源文件
    -u :搜寻不在上述三个项目当中的其他特殊文件
# whereis 主要是针对 /bin /sbin 下面的可执行文件,以及 /usr/share/man 下面的 man page 文件,跟几个比较特定的目录来处理
# 想要知道 whereis 到底查了多少目录?可以使用 whereis -l 来确认一下
locate [-ir] keyword  # 直接在后面输入“文件的部分名称”
    -i :忽略大小写的差异;
    -c :不输出文件名,仅计算找到的文件数量
    -l :仅输出几行的意思,例如输出五行则是 -l 5
    -S :输出 locate 所使用的数据库文件的相关信息,包括该数据库纪录的文件/目录数量等
    -r :后面可接正则表达式的显示方式
# 数据是由“已创建的数据库 /var/lib/mlocate/” 里面的数据所搜寻到的
# 数据库的创建默认是在每天执行一次(每个 distribution 都不同,CentOS 7.x 是每天更新数据库一次!),所
# 以当你新创建起来的文件,却还在数据库更新之前搜寻该文件,那么 locate 会告诉你“找不到!”因为必须要更新数据库

updatedb # 直接输入,根据 /etc/updatedb.conf 的设置去搜寻系统硬盘内的文件名,并更新/var/lib/mlocate 内的数据库文件;


find [PATH] [option] [action]		# find 本来就会搜寻次目录

    1. 与时间有关的选项:共有 -atime, -ctime 与 -mtime ,以 -mtime 说明
        -mtime n :n 为数字,意义为在 n 天之前的“一天之内”被更动过内容的文件;
        -mtime +n :列出在 n 天之前(不含 n 天本身)被更动过内容的文件文件名;
        -mtime -n :列出在 n 天之内(含 n 天本身)被更动过内容的文件文件名。
        -newer file :file 为一个存在的文件,列出比 file 还要新的文件文件名
        
    范例一:将过去系统上面 24 小时内有更动过内容 (mtime) 的文件列出
    [root@study ~]# find / -mtime 0
    # 那个 0 是重点!0 代表目前的时间,所以,从现在开始到 24 小时前,
    # 有变动过内容的文件都会被列出来!那如果是三天前的 24 小时内?
    # find / -mtime 3 有变动过的文件都被列出的意思!
    范例二:寻找 /etc 下面的文件,如果文件日期比 /etc/passwd 新就列出
    [root@study ~]# find /etc -newer /etc/passwd
    # -newer 用在分辨两个文件之间的新旧关系是很有用的!
    
    find /var -mtime -4  # 找出“4天内被更动过的文件文件名
    find /var -mtime 4	 # 找出“4天前的那一天”的文件文件名
    
    2. 与使用者或群组名称有关的参数:
    -uid n :n 为数字,这个数字是使用者的帐号 ID,亦即 UID ,这个 UID 是记录在
    				/etc/passwd 里面与帐号名称对应的数字。这方面我们会在第四篇介绍。
    -gid n :n 为数字,这个数字是群组名称的 ID,亦即 GID,这个 GID 记录在
    				/etc/group,相关的介绍我们会第四篇说明~
    -user name :name 为使用者帐号名称喔!例如 dmtsai
    -group name:name 为群组名称喔,例如 users ;
    -nouser :寻找文件的拥有者不存在 /etc/passwd 的人!
    -nogroup :寻找文件的拥有群组不存在于 /etc/group 的文件!
    					当你自行安装软件时,很可能该软件的属性当中并没有文件拥有者,
    					这是可能的!在这个时候,就可以使用 -nouser 与 -nogroup 搜寻。
         
    范例三:搜寻 /home 下面属于 dmtsai 的文件
    [root@study ~]# find /home -user dmtsai
    # 这个东西也很有用的~当我们要找出任何一个使用者在系统当中的所有文件时,
    # 就可以利用这个指令将属于某个使用者的所有文件都找出来喔!
    范例四:搜寻系统中不属于任何人的文件
    [root@study ~]# find / -nouser
    # 通过这个指令,可以轻易的就找出那些不太正常的文件。如果有找到不属于系统任何人的文件时,
    # 不要太紧张,那有时候是正常的~尤其是你曾经以源代码自行编译软件时。

    3. 与文件权限及名称有关的参数:
      -name filename:搜寻文件名称为 filename 的文件;
      -size [+-]SIZE:搜寻比 SIZE 还要大(+)或小(-)的文件。这个 SIZE 的规格有:
      								c: 代表 Byte, k: 代表 1024Bytes。所以,要找比 50KB
      								还要大的文件,就是“ -size +50k ”
      -type TYPE :搜寻文件的类型为 TYPE 的,类型主要有:一般正规文件 (f), 设备文件 (b, c),
      						 目录 (d), 链接文件 (l), socket (s), 及 FIFO (p) 等属性。
      -perm mode :搜寻文件权限“刚好等于” mode 的文件,这个 mode 为类似 chmod
      						 的属性值,举例来说, -rwsr-xr-x 的属性为 4755 !
      -perm -mode :搜寻文件权限“必须要全部囊括 mode 的权限”的文件,举例来说,
                    我们要搜寻 -rwxr--r-- ,亦即 0744 的文件,使用 -perm -0744,
                    当一个文件的权限为 -rwsr-xr-x ,亦即 4755 时,也会被列出来,
                    因为 -rwsr-xr-x 的属性已经囊括了 -rwxr--r-- 的属性了。
      -perm /mode :搜寻文件权限“包含任一 mode 的权限”的文件,举例来说,我们搜寻
      -rwxr-xr-x ,亦即 -perm /755 时,但一个文件属性为 -rw-------
      						 也会被列出来,因为他有 -rw.... 的属性存在!
      范例五:找出文件名为 passwd 这个文件
      [root@study ~]# find / -name passwd
      范例五-1:找出文件名包含了 passwd 这个关键字的文件
      [root@study ~]# find / -name "*passwd*"
      # 利用这个 -name 可以搜寻文件名啊!默认是完整文件名,如果想要找关键字,
      # 可以使用类似 * 的任意字符来处理
      范例六:找出 /run 目录下,文件类型为 Socket 的文件名有哪些?
      [root@study ~]# find /run -type s
      # 这个 -type 的属性也很有帮助喔!尤其是要找出那些怪异的文件,
      # 例如 socket 与 FIFO 文件,可以用 find /run -type p 或 -type s 来找!
      范例七:搜寻文件当中含有 SGID 或 SUID 或 SBIT 的属性
      [root@study ~]# find / -perm /7000
      # 所谓的 7000 就是 ---s--s--t ,那么只要含有 s 或 t 的就列出,所以当然要使用 /7000,
      # 使用 -7000 表示要同时含有 ---s--s--t 的所有三个权限。而只需要任意一个,就是 /7000

      4. 额外可进行的动作:
      -exec command :command 为其他指令,-exec 后面可再接额外的指令来处理搜寻到的结果。
      -print :将结果打印到屏幕上,这个动作是默认动作!
      范例八:将上个范例找到的文件使用 ls -l 列出来~
      [root@study ~]# find /usr/bin /usr/sbin -perm /7000 -exec ls -l {} \;
      # 注意到,那个 -exec 后面的 ls -l 就是额外的指令,指令不支持命令别名,
      # 所以仅能使用 ls -l 不可以使用 ll 喔!注意注意!
      范例九:找出系统中,大于 1MB 的文件
      [root@study ~]# find / -size +1M
 

+4 代表大于等于5天前的文件名:ex> find /var -mtime +4

-4 代表小于等于4天内的文件文件名:ex> find /var -mtime -4

4 则是代表4-5那一天的文件文件名:ex> find /var -mtime 4

该范例中特殊的地方有 {} 以及 \; 还有 -exec 这个关键字,这些东西的意义为:

  1. {} 代表的是“由 find 找到的内容”,如上图所示,find 的结果会被放置到 {} 位置中;
  2. -exec 一直到 \; 是关键字,代表 find 额外动作的开始 (-exec) 到结束 (\;) ,在这中间的就是 find 指令内的额外动作。

在本例中就是“ ls -l {} ”!因为“ ; ”在 bash 环境下是有特殊意义的,因此利用反斜线来跳脱

2.2. 常用文件介绍

1、空设备节点/dev/null

  1. 本质上是一个黑洞文件,是一个特殊的设备文件节点,用于丢弃程序的输出。
  2. 其内部实现是一个位桶,所有写入该设备的数据都会被立即丢弃,不会写入任何物理存储介质,因此称之为“黑洞”。写入的数据无法恢复
  3. 在Unix和类Unix系统中,文件是一切的基础,所有的输入和输出都是通过文件来进行的,在一些情况下,我们需要将不必要的输出或错误信息丢弃掉,那么/dev/null就是一个非常方便的工具。

在Linux和类Unix系统中,可以通过命令行来查看空设备节点/dev/null。以下是几种常见的方法:

  1. 使用ls命令查看:
    1. ls -l /dev/null
    2. 输出示例:crw-rw-rw- 1 root root 1, 3 Jan 1 08:00 /dev/null
      1. 其中,第一个字符“c”表示该文件是一个设备文件(char代表字符设备,blk代表块设备),
      2. 接下来的“rw-rw-rw-”表示文件的权限,1, 3是设备的主从(设备)号,
      3. 最后的“/dev/null”是设备的路径。
  1. 使用file命令查看:
    1. file /dev/null
    2. 输出示例:/dev/null: character special (1/3)
      1. 其中,“character special”表示这是一个字符设备文件。
  1. 直接输出文件内容:
    1. cat /dev/null
    2. 这个命令不会产生任何输出,因为/dev/null是一个黑洞文件,所有写入该设备的数据都会被立即丢弃,不会写入任何物理存储介质。

2.2.1. Linux文件类型

执行文件,普通文件,目录文件,链接文件和设备文件,管道文件

  1. 普通文件 -
    1. 纯文本文件(ASCII), 二进制档(binary), 数据格式文件(data:某些特定格式的文件)
  1. 目录 d
  2. 套接字 s :
    1. 数据接口文件(sockets), 被用在网络上的数据承接, 启动一个程序来监听用户端的要求, 而用户端就可以通过这个socket来进行数据的沟通了
  1. 符号链接 l
  2. 块设备 b :
    1. 为设备文件里面的可供储存的周边设备(可随机存取设备)
  1. 字符设备 c :
    1. 例如键盘、鼠标(一次性读取设备,不能够截断输出),举例来说,你不可能让鼠标“跳到”另一个画面,而是“连续性滑动”到另一个地方
  1. 管道 p : 数据输送档 (FIFO,pipe),
    1. 主要的目的在解决多个程序同时存取一个文件所造成的错误问题。 FIFO是first-in-first-out的缩写。

2.2.2. Linux目录配置的依据--FHS

FHS(Filesystem Hierarchy Standard )的重点在于规范每个特定的目录下应该要放置什么样子的数据而已

而将目录定义成为四种交互作用的形态 :

  1. 可分享的:可以分享给其他系统挂载使用的目录,所以包括可执行文件与使用者的邮件等数据, 是能够分享给网络上其他主机挂载用的目录;
  1. 不可分享的:自己机器上面运行的设备文件或者是与程序有关的socket文件等, 由于仅与自身机器有关,所以当然就不适合分享给其他主机了。
  1. 不变的:有些数据是不会经常变动的,跟随着distribution而不变动。 例如函数库、文件说明文档、系统管理员所管理的主机服务配置文件等等;
  1. 可变动的:经常改变的数据,例如登录文件、一般用户可自行收受的新闻群组等。

事实上,FHS针对目录树架构仅定义出三层目录下面应该放置什么数据而已,分别是下面这三个目录的定义:

  1. / (root, 根目录):与开机系统有关;
  2. /usr (unix software resource):与软件安装/执行有关;
  3. /var (variable):与系统运行过程有关。

根目录的意义与内容 :

  1. 根目录是整个系统最重要的一个目录,因为不但所有的目录都是由根目录衍生出来的,同时根目录也与开机/还原/系统修复等动作有关
  2. 根目录(/)所在分区应该越小越好, 且应用程序所安装的软件最好不要与根目录放在同一个分区内,保持根目录越小越好。 如此不但性能较佳,根目录所在的文件系统也较不容易发生问题。
  3. 有鉴于上述的说明,因此FHS定义出根目录(/)下面应该要有下面这些次目录的存在才好,即使没有实体目录,FHS也希望至少有链接文件存在才好:

其他重要目录 :

  1. /lost+found 这个目录是使用标准的ext2/ext3/ext4文件系统格式才会产生的一个目录,目的在于当文件系统发生错误时, 将一些遗失的片段放置到这个目录下。不过如果使用的是 xfs 文件系统的话,就不会存在这个目录了!
  2. /proc 这个目录本身是一个“虚拟文件系统(virtual filesystem)”喔!他放置的数 据都是在内存当中, 例如系统核心、行程信息(process)、周边设备的状态及网络状态等等。因为这个目录下的数据都是在内存当中, 所以本身不 占任何硬盘空间啊!比较重要的文件例如:/proc/cpuinfo, /proc/dma, /proc/interrupts, /proc/ioports, /proc/net/* 等等。
  3. /sys 这个目录其实跟/proc非常类似,也是一个虚拟的文件系统,主要也是记录 核心与系统硬件信息较相关的信息。 包括目前已载入的核心模块与核心侦测到的硬件设备信息等等。这个目录同样不占硬盘容量喔!

早期 Linux 在设计的时候,若发生问题时,救援模式通常仅挂载根目录而已,因此有五个重要的目录被要求一定要与根目录放置在一起, 那就是 /etc, /bin, /dev, /lib, /sbin 这五个重要目录。现在许多的 Linux distributions 由于已经将许多非必要的文件移出/usr 之外了, 所以 /usr 也是越来越精简,同时因为 /usr 被建议为“即使挂载成为只读,系统还是可以正常运行”的模样,所以救援模式也能同时挂载 /usr

/usr的意义与内容 : Unix Software Resource的缩写

如果你知道如何通过网络进行分区的挂载(例如在服务器篇会谈到的NFS服务器),那么/usr确实可以分享给区域网络内的其他主机来使用喔!

/var 的意义与内容:

如果/usr是安装时会占用较大硬盘容量的目录,那么/var就是在系统运行后才会渐渐占用硬盘容量的目录。 因为/var目录主要针对常态性变动的文件,包括高速缓存(cache)、登录文件(log file)以及某些软件运行所产生的文件, 包括程序文件(lock file, run file),或者例如MySQL数据库的文件等等。常见的次目录有:

CentOS 7 在目录的编排上与过去的版本不同!这里做个汇整。 比较大的差异在于将许多原本应该要在根目录 (/) 里面的目录,将他内部数据全部挪到 /usr 里面去,然后进行链接设置!包括下面这些:

/bin --> /usr/bin

/sbin --> /usr/sbin

/lib --> /usr/lib

/lib64 --> /usr/lib64

/var/lock --> /run/lock

/var/run --> /run

2.3. 文件与目录的默认权限与隐藏权限

除了基本r, w, x权限外,在Linux传统的Ext2/Ext3/Ext4文件系统下,我们还可以设置其他的系统隐藏属性, 这部份可使用 chattr 来设置,而以 lsattr 来查看 ;

最重要的属性就是可以设置其不可修改的特性!让连文件的拥有者都不能进行修改!这个属性可是相当重要的,尤其是在安全机制上面 (security)!

在 CentOS 7.x 当中利用 xfs 作为默认文件系统, 但是 xfs 就没有支持所有的 chattr 的参数了!仅有部份参数还有支持而已!

2.3.1. 文件默认权限设置:umask

新增一个文件或目录时,默认的权限是什么?

这与umask有关 , umask 就是指定目前使用者在创建文件或目录时候的权限默认值”;

那么如何得知或设置 umask 呢?他的指定条件以下面的方式来指定:

查看方式 :
[root@study ~]# umask
0022										# <==与一般权限有关的是后面三个数字!第一个是特殊权限用的
[root@study ~]# umask -S
u=rwx,g=rx,o=rx

设置umask :
umask 002
  1. 若使用者创建为“文件”则默认“没有可执行(x )权限”,亦即只有 rw 这两个项目,也就是最大为 666 分,默认权限如下: -rw-rw-rw-
  2. 若使用者创建为“目录”,则由于 x 与是否可以进入此目录有关,因此默认为所有权限均开放,亦即为 777 分,默认权限如下:drwxrwxrwx

注意 : umask 的分数指的是“该默认值基础上需要减掉的权限" : 要拿掉能写的权限,就是输入 2 分,而如果要拿掉能读的权限,也就是 4 分,那么要拿掉读与写的权限,也就是 6 分 ,...

例如 : umask 为 022 ,所以 user 并没有被拿掉任何权限,不过 group 与 others 的权限被拿掉了 2 (也就是 w 这个权限),那么当使用者:

创建文件时:(-rw-rw-rw-) - (-----w--w-) ==> -rw-r--r--

创建目录时:(drwxrwxrwx) - (d----w--w-) ==> drwxr-xr-x

  1. 关于 umask 与权限的计算方式中,教科书喜欢使用二进制的方式来进行AND 与 NOT 的计算, 不过,使用符号方式来计算~联想上面比较容易一点;
  2. 如果使用文件默认属性 666 与目录默认属性 777 来与 umask 进行相减的计算~这是不好的!以umask 003看 如果使用默认属性相加减,则文件变成:666-003=663,亦即是 -rw-rw--wx ,这可是完全不对的, 明明是去除 x ,但却没有
  3. 关于默认 umask 的设置可以参考 /etc/bashrc 这个文件的内容,不过,不建议修改该文件, 可在 ~/.bashrc设置
2.3.2. 文件隐藏属性

chattr指令只能在Ext2/Ext3/Ext4的 Linux 传统文件系统上面完整生效, 其他的文件系统可能就无法完整支持这个指令了,例如 xfs 仅支持部份参数而已

[root@study ~]# chattr [+-=][ASacdistu] 文件或目录名称
选项与参数:
    + :增加某一个特殊参数,其他原本存在参数则不动。
    - :移除某一个特殊参数,其他原本存在参数则不动。
    = :设置一定,且仅有后面接的参数
    
    A :当设置了 A 这个属性时,若你有存取此文件(或目录)时,他的存取时间 atime 将不会被修改,
    		可避免 I/O 较慢的机器过度的存取磁盘。(目前建议使用文件系统挂载参数处理这个项目)
    S :一般文件是非同步写入磁盘的(原理请参考前一章sync的说明),如果加上 S 这个属性时,
    		当你进行任何文件的修改,该更动会“同步”写入磁盘中。
    a :当设置 a 之后,这个文件将只能增加数据,而不能删除也不能修改数据,只有root 才能设置这属性
    c :这个属性设置之后,将会自动的将此文件“压缩”,在读取的时候将会自动解压缩,
    		但是在储存的时候,将会先进行压缩后再储存(看来对于大文件似乎蛮有用的!)
    d :当 dump 程序被执行的时候,设置 d 属性将可使该文件(或目录)不会被 dump 备份
    i :这个 i 可就很厉害了!他可以让一个文件“不能被删除、改名、设置链接也无法写入或新增数据!”
    		对于系统安全性有相当大的助益!只有 root 能设置此属性
    s :当文件设置了 s 属性时,如果这个文件被删除,他将会被完全的移除出这个硬盘空间,
    		所以如果误删了,完全无法救回来了喔!
    u :与 s 相反的,当使用 u 来设置文件时,如果该文件被删除了,则数据内容其实还存在磁盘中,
    		可以使用来救援该文件喔!
注意1:属性设置常见的是 a 与 i 的设置值,而且很多设置值必须要身为 root 才能设置
注意2:xfs 文件系统仅支持 AadiS 而已

[root@study ~]# lsattr [-adR] 文件或目录
选项与参数:
    -a :将隐藏文件的属性也秀出来;
    -d :如果接的是目录,仅列出目录本身的属性而非目录内的文件名;
    -R :连同子目录的数据也一并列出来!
[root@study tmp]# chattr +aiS attrtest
[root@study tmp]# lsattr attrtest
--S-ia---------- attrtest

隐藏的性质,所以需要以 lsattr 才能看到该属性!其中,认为最重要的当属 +i 与 +a 这个属性了。+i 可以让一个文件无法被更动

2.3.3. 文件特殊权限 SUID, SGID, SBIT

SUID,SGID ,SBIT 涉及程序的概念

上图/tmp 权限怪怪的? 还有,那个 /usr/bin/passwd 也怪怪的?怎么回事啊

还有其他的特殊权限(s 跟 t ), s 与 t与系统的账号 和系统的程序相关

Set UID

  1. 当 s 这个标志出现在文件拥有者的 x 权限上时,例如刚刚提到的 /usr/bin/passwd 这个文件的权限状态:“-rwsr-xr-x”,此时就被称为 Set UID,简称为 SUID 的特殊权限
  2. SUID的权限对于一个文件的特殊功能是什么?基本上SUID有这样的限制与功能:
    1. SUID 权限仅对二进制程序(binary program)有效;
    2. 执行者对该程序需要具有x的可执行权限
    3. 本权限仅在执行该程序的过程中有效
    4. 执行者将具有该程序拥有者的权限
  1. 注意 :
    1. SUID 仅可用在binary program 上不能够用在 shell script 上面!这是因为shell script 只是将很多的 binary 可执行文件叫进来执行而已!
    2. SUID对于目录也是无效的

SUID功能举例说明 :

所有帐号的密码都记录在 /etc/shadow ,文件的权限为:“---------- 1 root root”,意思是这个文件仅有root可读且仅有root可以强制写入而已。

既然这个文件仅有 root 可以修改,那么 dmtsai 这个一般帐号使用 者能否自行修改自己的密码呢? 你可以使用你自己的帐号输入“passwd”这个指令来看看,一般使用者当然可以修改自己的密码了!

明明 /etc/shadow 就不能让 dmtsai 这个一般帐户去存取的,为什么 dmtsai 还能够修改这个文件内的密码呢? 这就是 SUID 的功能 !!

  1. dmtsai 对于 /usr/bin/passwd 这个程序来说是具有 x 权限的,表示 dmtsai 能执行passwd;
  2. passwd 的拥有者是 root 这个帐号;
  3. dmtsai 执行 passwd 的过程中,会“暂时”获得 root 的权限;
  4. /etc/shadow 就可以被 dmtsai 所执行的 passwd 所修改。

但如果 dmtsai 使用 cat 去读取 /etc/shadow 时,他能够读取吗?因为 cat 不具有SUID 的权限,所以 dmtsai 执行 “cat /etc/shadow” 时,是不能读取 /etc/shadow 的。

Set GID :

  1. 当 s 标志在文件拥有者的 x 项目为 SUID,那 s 在群组的 x 时则称为 Set GID ;
  2. SGID 可以针对文件或目录来设置!
    1. 如果是对文件来说,SGID 有如下的功能 :
      1. SGID 对二进制程序有用;
      2. 程序执行者对于该程序来说,需具备 x 的权限;
      3. 执行者在执行的过程中将会获得该程序群组的支持
    1. 一个目录设置了 SGID 的权限后,他将具有如下的功能:
      1. 使用者若对于此目录具有 r 与 x 的权限时,该使用者能够进入此目录;
      2. 使用者在此目录下的有效群组(effective group)将会变成该目录的群组;
      3. 用途:若使用者在此目录下具有 w 的权限(可以新建文件),则使用者所创建的新文件,该新文件的群组与此目录的群组相同。

举例来说,上面的 /usr/bin/locate 这个程序可以去搜寻 /var/lib/mlocate/mlocate.db 这个文件的内容, mlocate.db 的权限如下:

-rwx--s--x. 1 root slocate 40496 Jun 10 2014 /usr/bin/locate

-rw-r-----. 1 root slocate 2349055 Jun 15 03:44 /var/lib/mlocate/mlocate.db

与 SUID 非常的类似,若我使用 dmtsai 这个帐号去执行 locate 时,那 dmtsai 将会取得 slocate 群组的支持, 因此就能够去读取 mlocate.db ;

Sticky Bit
这个 Sticky Bit, SBIT 目前只针对目录有效,对于文件已经没有效果了。SBIT 对于目录的作用是:

  1. 当使用者对于此目录具有 w, x 权限,亦即具有写入的权限时;
  2. 当使用者在该目录下创建文件或目录时,仅有自己与 root 才有权力删除该文件

换句话说:当甲这个使用者于 A 目录是具有群组或其他人的身份,并且拥有该目录 w 的权限, 这表示“甲使用者对该目录内任何人创建的目录或文件均可进行 "删除/更名/搬移" 等动作。” 不过,如果将 A 目录加上了 SBIT 的权限项目时, 则甲只能够针对自己创建的文件或目录进行删除/更名/移动等动作,而无法删除他人的文件。

举例来说,我们的 /tmp 本身的权限是“drwxrwxrwt”, 在这样的权限内容下,任何人都可以在 /tmp 内新增、修改文件,但仅有该文件/目录创建者与 root 能够删除自己的目录或文件。这个特性也是挺重要的啊!你可以这样做个简单的测试:

  1. 以 root 登陆系统,并且进入 /tmp 当中;
  2. touch test,并且更改 test 权限成为 777 ;
  3. 以一般使用者登陆,并进入 /tmp;
  4. 尝试删除 test 这个文件!
    由于 SUID/SGID/SBIT 牵涉到程序

SUID/SGID/SBIT 权限设置

数字体态更改权限的方式为“三个数字”的组合, 那么如果在这三个数字之前再加上一个数字,最前面的那个数字就代表这几个权限 : 4 为 SUID 2 为 SGID 1 为 SBIT

chmod 4755 filename

上面的范例只是练习而已,所以使用同一个文件来设置,你必须了解 SUID 不是用在目录上,而 SBIT 不是用在文件上

怎么会出现大写的 S 与 T 呢? 因为 s 与 t 都是取代 x 这个权限的,但是我们是下达 7666 ,也就是说,user, group 以及 others 都没有 x 这个可执行的标志(因为 666 ),所以,这个 S, T 代表的就是“空的”

也就是说 , SUID 是表示“该文件在执行的时候,具有文件拥有者的权限”,但是文件拥有者都无法执行了,哪里来的权限给其他人使用?当然就是空的

也可以通过符号法来处理!其中 SUID 为 u+s ,而 SGID 为 g+s ,SBIT 则是 o+t

2.3.4. 权限与指令间的关系(重要)
  1. 让使用者能进入某目录成为“可工作目录”的基本权限为何:
    1. 可使用的指令:例如 cd 等变换工作目录的指令;
    2. 目录所需权限:使用者对这个目录至少需要具有 x 的权限
    3. 额外需求:如果使用者想要在这个目录内利用 ls 查阅文件名,则使用者对此目录还需要 r 的权限。
  1. 使用者在某个目录内读取一个文件的基本权限为何?
    1. 可使用的指令:例如本章谈到的 cat, more, less等等
    2. 目录所需权限:使用者对这个目录至少需要具有 x 权限;
    3. 文件所需权限:使用者对文件至少需要具有 r 的权限才行!
  1. 让使用者可以修改一个文件的基本权限为何?
    1. 可使用的指令:例如 nano 或 vi 编辑器等;
    2. 目录所需权限:使用者在该文件所在的目录至少要有 x 权限;
    3. 文件所需权限:使用者对该文件至少要有 r, w 权限
  1. 让一个使用者可以创建一个文件的基本权限为何?
    1. 目录所需权限:使用者在该目录要具有 w,x 的权限,重点在 w !
  1. 让使用者进入某目录并执行该目录下的某个指令之基本权限为何?
    1. 目录所需权限:使用者在该目录至少要有 x 的权限;
    2. 文件所需权限:使用者在该文件至少需要有 x 的权限

2.4. 文件权限与目录配置

注意的是,各种权限设置对 root 是无效的

例如/etc/shadow文件的权限就会成为[ ---------- ] 所有人都不能使用?没关系,root基本上是不受系统的权限所限制的, 所以无论文件权限为何,默认root都可以存取

在Linux里面,任何一个文件都具有“User, Group及 Others”三种身份的个别权限

使用者 ,

群组 ,群组最有用的功能之一,就是当你在团队开发资源的时候

非本群组外的其他人

虽然在同一群组内,但是我们可以设置“权限”, 好让某些使用者个人的信息不被群组的拥有者查询,以保有个人“私人的空间”!而设置群组共享,则可让大家共同分享

每个帐号可以加入的群组个数基本上是没有限制的

链接 : 每个文件都会将他的权限与属性记录到文件系统的i-node中,不过,我们使用的目录树却是使用文件名来记录, 因此每个文件名就会链接到一个i-node ;

文件的容量大小,默认单位为Bytes

如果这个文件被修改的时间距离现在太久了,那么时间部分会仅显示年份而已 , 可以通过“ls -l --full-time”显示出完整的时间格式

  1. 目录与文件的权限意义并不相同,这是因为目录与文件所记录的数据内容不相同所致。
  2. 具有“可执行的权限”以及“具有可执行的程序码”是两回事!
    1. 如 text.txt 具有“可执行的权限”(加入 x 权限即可), 但是这个文件明显的无法执行,因为他不具备可执行的程序码!
    2. 而如果你将 cat 这个可以执行的指令,将他的 x 拿掉,那么 cat 将无法被你执行!
    3. 上述的这种问题最常发生在文件传送的过程中, 文件从网络上传送到你的 Linux系统中,文件的属性与权限确实是会被改变的喔!

2.4.1. 改变文件属性和权限
  1. chgrp :改变文件所属群组 :
    1. 被改变的群组名称必须要/etc/group文件内存在才行,否则就会显示错误!
    2. chgrp 群组名 [-R] dirname/filename ...
  1. chown :改变文件拥有者
    1. 使用者必须是已经存在系统中的帐号,也就是在/etc/passwd 这个文件中有纪录的使用者名称才能改变。
    2. 可以顺便直接修改群组的名称 ;
    3. chown [-R] 帐号名称:群组名称 文件或目录chown [-R] 帐号名称 文件或目录
  1. chmod :改变文件的权限, SUID, SGID, SBIT等等的特性
    1. 数字类型改变文件权限 : 数字代表权限, r:4 w:2 x:1(可认为数字越小越是重要的权限)
      1. chmod [-R] xyz 文件或目录
    1. 符号类型改变文件权限 : u, g, o来代表三种身份的权限!a 则代表 all 亦即全部的身份!那么读写的权限就可以写成r, w, x
    2. chmod u=rwx,go=rx .bashrc
    3. 只想要增加.bashrc这个文件的每个人可写入的权限,即便不知道其属性chmod a+w .bashrc

[-rwxrwx---] 分数则是:

owner = rwx = 4+2+1 = 7

group = rwx = 4+2+1 = 7

others= --- = 0+0+0 = 0

  1. 如果要连目录下的所有次目录或文件同时更改文件拥有者的话,直接加上 -R
  2. 有时候需要变更文件的拥有者的,最常见的例子就是在复制文件给你之外的其他人时
    1. 我们使用最简单的cp指令来说明好了:cp 来源文件 目的文件
    2. 由于复制行为(cp)会复制执行者的属性与权限, 要给其他人所以你就必须要将这个文件的拥有者与群组修改一下

# ***********************************chgrp************************************** #
chgrp 群组名 [-R] dirname/filename ...
选项与参数:
    -R : 进行递回(recursive)的持续变更,亦即连同次目录下的所有文件、目录
    都更新成为这个群组之意。常常用在变更某一目录内所有的文件之情况。
    
# 范例:
[root@study ~]# chgrp users initial-setup-ks.cfg
[root@study ~]# ls -l
-rw-r--r--. 1 root users 1864 May 4 18:01 initial-setup-ks.cfg
[root@study ~]# chgrp testing initial-setup-ks.cfg
chgrp: invalid group: `testing`		# <== 发生错误讯息啰~找不到这个群组名~

# ************************************chown*************************************** #
chown [-R] 帐号名称 文件或目录
chown [-R] 帐号名称:群组名称 文件或目录
选项与参数:
		-R : 进行递回(recursive)的持续变更,亦即连同次目录下的所有文件都变更

事实上,chown也可以使用“.”,亦即在拥有者与群组间加上小数点“ . ”也行! 
不过很多朋友设置帐号时,喜欢在帐号当中加入小数点(例如vbird.tsai这样的帐号格式),
这就会造成系统的误判了! 所以我们比较建议使用冒号“:”来隔开拥有者与群组
# 小数点修改群组
chown user.group file
# 单纯的修改所属群组
chown .sshd initial-setup-ks.cfg  

  
范例:将 initial-setup-ks.cfg 的拥有者改为bin这个帐号:
[root@study ~]# chown bin initial-setup-ks.cfg
[root@study ~]# ls -l
-rw-r--r--. 1 bin users 1864 May 4 18:01 initial-setup-ks.cfg
范例:将 initial-setup-ks.cfg 的拥有者与群组改回为root:
[root@study ~]# chown root:root initial-setup-ks.cfg
[root@study ~]# ls -l
-rw-r--r--. 1 root root 1864 May 4 18:01 initial-setup-ks.cfg

# ***********************************chmod*************************************** #
[root@study ~]# chmod [-R] xyz 文件或目录
选项与参数:
    xyz : 就是刚刚提到的数字类型的权限属性,为 rwx 属性数值的相加。
    -R : 进行递回(recursive)的持续变更,亦即连同次目录下的所有文件都会变更

[root@study ~]# chmod u=rwx,go=rx .bashrc
# 注意!那个 u=rwx,go=rx 是连在一起的,中间并没有任何空白字符!

2.4.2. 目录与文件之权限意义

文件权限对于一般文件与目录文件有何不同呢?

权限对文件的重要性

  1. 注意 : 可执行(x)权限 ,在Windows下面一个文件是否具有执行的能力是借由“ 扩展名 ”来判断的, 例如:.exe, .bat, .com 等等,但是在Linux下面,我们的文件是否能被执行,则是借由是否具有“x”这个权限来决定的跟文件名是没有绝对的关系的
  2. 对一个文件具有w权限时,你可以具有写入/编辑/新增/修改文件的内容的权限, 但并不具备有删除该文件本身的权限 !

权限对目录的重要性

文件是存放实际数据的所在,那么目录主要是储存啥玩意啊?目录主要的内容在记录文件名清单,文件名与目录有强烈的关连

r, w, x对目录的作用

  1. r : 表示具有读取目录结构清单的权限, 表示你可以查询该目录下的文件名数据。 所以你就可以利用 ls 这个指令将该目录的内容列表显示出来
  2. w : 表示你具有异动该目录结构清单的权限,也就是下面这些权限:
    1. 创建新的文件与目录 ;
    2. 删除已存在的文件与目录 (不论该文件的权限为何) ;
    3. 将已存在的文件或目录进行更名 ;
    4. 搬移该目录内的文件,目录位置
    5. 总之,目录的w权限就与该目录下面的文件名异动有关就对了
  1. x : 目录不可以被执行, 目录的x代表的是使用者能否进入该目录成为工作目录的用途 , 所谓的工作目录(work directory) 就是你目前所在的目录 !
    1. 当你登陆Linux时, 你所在的主文件夹就是你当下的工作目录。
    2. 而变换目录的指令是“cd”(change directory)

示例 :

以/dir1/file1 和 /dir2 为例 分别以最小权限达成操作 :

上面的表格当中,很多时候 /dir1 都不必有 r !为啥?我们知道/dir1 是个目录,也是个抽屉!那个抽屉的 r 代表“这个抽屉里面有灯光”, 所以你能看到的抽屉内的所有数据夹名称 (非内容)。但你已经知道里面的数据夹放在哪个地方,那有没有灯光有差嘛?你还是可以摸黑拿到该数据夹的!对吧!

因此,上面很多动作中,你只要具有 x 即可!r 是非必备的!只是,没有 r 的话,使用 [tab] 时,他就无法自动帮你补齐文件名了!

要读一个文件时,你得要具有“这个文件所在目录的 x 权限”才行!所以,通常要开放的目录, 至少会具备 rx 这两个权限

2.5. Linux用户与群组

2.5.1. Linux识别用户
  1. Linux如何识别登陆者的账号的 : Linux不会直接认识你的"账号名称" , 仅认识ID (ID就是一组号码) ;
  2. ID 与账号的对应在 : /etc/passwd
  3. 每个登录的使用者至少都会取得两个ID , 一个是使用者ID(User ID ,简称 UID),一个是群组ID(Group ID, GID)
  4. 每个文件都具有"拥有人与拥有群组" 的属性 : 那么文件如何判别它的拥有者与群组? 就是利用UID和GID
    1. 当要显示文件属性时, 系统会依据/etc/passwd 与 /etc/group的内容 ,找到UID/GID对应的账号与群组名称再显示出来

# 1. 先察看一下,系统里面有没有一个名为 dmtsai 的用户?
[root@study ~]# id dmtsai
uid=1000(dmtsai) gid=1000(dmtsai) groups=1000(dmtsai),10(wheel) <==确定有这个帐号喔!
[root@study ~]# ll -d /home/dmtsai
drwx------. 17 dmtsai dmtsai 4096 Jul 17 19:51 /home/dmtsai
# 瞧一瞧,使用者的字段正是 dmtsai 本身喔!
# 2. 修改一下,将刚刚我们的 dmtsai 的 1000 UID 改为 2000 看看:
[root@study ~]# vim /etc/passwd
....(前面省略)....
dmtsai:x:2000:1000:dmtsai:/home/dmtsai:/bin/bash  # <==修改一下2000部分,由 1000 改过来
[root@study ~]# ll -d /home/dmtsai
drwx------. 17 1000 dmtsai 4096 Jul 17 19:51 /home/dmtsai
# 很害怕吧!怎么变成 1000 了?因为文件只会记录 UID 的数字而已!
# 因为我们乱改,所以导致 1000 找不到对应的帐号,因此显示数字!
# 3. 记得将刚刚的 2000 改回来!
[root@study ~]# vim /etc/passwd
....(前面省略)....
Tips
dmtsai:x:1000:1000:dmtsai:/home/dmtsai:/bin/bash 		# <==“务必一定要”改回来!

# 如果没有将 2000 改回原本的 UID,那么当 dmtsai 下次登陆时将没有办法进入自己的主文件夹! 因为他的 UID 已
# 经改为 2000 ,但是他的主文件夹 (/home/dmtsai) 却记录的是 1000 ,由于权限是700 , 因此他将无法进入原本的主文件夹!

输入账号密码之后,系统做了什么 :

  1. 先找寻/etc/passwd 里是否有你的账号 , 没有跳出; 有则将该账号对的UID与GID(/etc/group)读出来; 另外,该账号的主文件夹与shell设置也一并读出
  2. 再来则是核对密码表 : 这时Linux会进入/etc/shadow 里找到对应的账号与UID ,然后再核对一下你刚刚输入的密码与里面的密码是否相符
  3. 如果一切OK, 就会进入Shell控管的阶段

/etc/passwd 文件结构

该文件构造如下 :

  1. 每一行都代表一个账号, 有几行就代表有几个账号在你的系统中!
  2. 不过特别留意 : 里面很多账号本来就是系统正常运行所必须要的, 可以简称为系统账号, 如 bin,daemon,adm,nobody 等 ; 这些账号不要随意杀掉他
  3. 每一行都有 : 来进行分隔, 一共6个冒号 , 7个字段属性
    1. 账号名称 : 需要用来对应UID
    2. 密码 : 相当于加密,给了一个x
    3. UID : 使用者识别码 ,Linux对于UID有几个限制 :
      1. ID 范围 : 0 (系统管理员) , 1~999 (系统账号) , 1000~60000 (可登录账号)
        1. 根据系统帐号的由来,通常这类帐号又约略被区分为两种:
          1. 1~200:由 distributions 自行创建的系统帐号;
          2. 201~999:若使用者有系统帐号需求时,可以使用的帐号UID。
        1. 事实上目前的 linux 核心 (3.10.x 版)已经可以支持到 4294967295 (2^32-1) 这么大的 UID 号码
      1. 想让其他账号名称也具有root权限 : 将该账号的UID改为0 即可 ; 不过不建议有多个账号的UID是0 ;
      2. 除了0之外,其他的UID权限与特性并没有不一样 ,默认1000以下的数字让给系统作为保留账号是一个习惯 ;
      3. 系统账号存在的原因是 : 由于系统上面启动的网络服务或后台服务希望使用较小的权限去运行, 因此不希望使用root的身份去执行这些服务, 所有我们需要提供这些运行中程序的拥有者账号才行; 这些系统账号通常是不可登录的 ; 所以才会有/sbin/nologin 这个特殊的shell
    1. GID : 分组ID
    2. 使用者信息说明栏 : 只是解释账号意义, 如果你提供 finger的功能时,这个字段可提供很多信息
    3. 主文件夹 : 使用者的主文件夹,root主文件夹在/root ,当登录后就会立即到/root里 ;
      1. 如果你有个账号的使用空间特别的大, 你想要将账号的主文件夹移动到其他的硬盘就可以在这个字段进行修改
    1. Shell : 当使用者登录系统后就会取得一个Shell来与系统的核心沟通以进行使用者的操作任务 ;
      1. 默认shell会使用的bash 就是这个字段指定的
      2. 有一个shell可用来替代成 让账号无法取得shell环境的登录动作: 就是 /sbin/nologin
# /etc/passwd 文件结构
root:x:0:0:root:/root:/bin/bash 
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
...

权限与UID/GID有关, 因此各个程序需要读取/etc/passwd来了解不同账号的权限, 因此/etc/passwd 的权限需设置为 -rw-r--r-- 这样的情况

/etc/shadow文件结构

密码移动到 /etc/shadow , 还加入很多的密码限制参数在 /etc/shadow 里头

虽然这些加密过的密码很难被解出来, 但是“很难”不等于“不会”,所以,这个文件的默认权限是“-rw-------”或者是“----------” , 只有root才可以读写

shadow同样使用 : (冒号)作为分隔符号 , 一共9个字段

  1. 账号名称
  2. 密码 : 真正的密码,是经过编码的密码(加密)
  3. 最近更动密码的日期 : 显示的是数字, 因为计算Linux日期的时间以1970/01/01 作为1 而累加的日期
  4. 密码不可被更动的天数 ; 记录密码被最近一次更改后需要经过几天才可以再被变更
  5. 密码需要重新变更的天数 : 指定在最近一次更改密码后,多少天内需要再次变更密码才行 , 你必须在这个天数内重新设置你的密码,否则这个账号的密码将会"变为过期特性"
  6. 密码需要变更期前的警告天数 : 账号密码快要过期时,系统会依据和这个字段的设置,发送警告给这个张哈
  7. 密码过期后的账号宽限时间 (密码失效日) :
    1. 虽然密码过期但该账号仍可用来进行其他工作, 包括登录系统取得bash , 但是登录时系统会强制你必须重新设置密码才能继续使用, 这就是密码过期特性;
    2. 该字段意思是 密码过期几天后 , 使用者还没有更改密码 ,这个账号的密码就会"失效",也就是该账号再也无法用该密码登录了 ; 注意 密码过期和密码失效 不同
  1. 账号失效日期 : 仍然使用1970年以来的总日数设置 ; 表示 这个账号在此字符规定的日期之后, 将无法再使用 ; 所谓的账号失效就是 : 无论你的密码是否有过期, 这个账号都不能再使用
  2. 保留 : 看以后有没有新功能加入

由于固定的编码系统产生的密码长度必须一致,因此“当你让这个字段的长度改变后,该密码就会失效(算不出

来)”。 很多软件通过这个功能,在此字段前加上 ! 或 * 改变密码字段长度,就会让密码“暂时失效”了。

# 类似这样的文件结构
root:$6$wtbCCce/PxMeE5wm$KE2IfSJr.YLP7Rcai6oa/T7KFhO...:16559:0:99999:7::: 
bin:*:16372:0:99999:7:::
daemon:*:16372:0:99999:7:::
adm:*:16372:0:99999:7:::

# 至于想要知道某个日期的累积日数,可使用如下的程序计算:
 echo $(($(date --date="2015/05/04" +%s)/86400+1))

2015/05/04 为你想要计算的日期,86400 为每一天的秒数, %s 为1970/01/01 以来的累积总秒数。 
由于 bash 仅支持整数,因此最终需要加上 1 补齐1970/01/01 当天

# ********************     查看密码的加密方式     *********************** #
[root@study ~]# authconfig --test | grep hashing
password hashing algorithm is sha512
# 这就是目前的密码加密机制!
用户切换
# 权限高的切换到权限低的不需密码;反之需要	切换为root用户(其他用户);
su(su - 用户名)  # 切换为root用户(其他用户)

su - username 和su username 最大的区别的就是是否切换环境,
带-是同时切换环境,某些命令才可以执行:如logout才有效

logout	注销用户:退出当前用户(在图形界面无效)
当root到其他用户:可以logout回退到root,再logout就会退出系统(注意必须是su -切换才可)

找回密码
# 找回一般用户的密码
管理员帮忙,重新设置你的密码而不需要知道你的旧密码 , 使用 passwd 指令
# root 密码忘记
root 的密码在 /etc/shadow 当中,因此你可以使用各种可行的方法开机进入 Linux再去修改。 
例如重新开机进入单人维护模式后,系统会主动的给予root 权限的 bash 接口,
此时再以 passwd 修改密码即可;
或以 Live CD 开机后挂载根目录去修改 /etc/shadow,将里面的 root 的密码字段清空, 再重新开机后 root 将
不用密码即可登陆!登陆后再赶快以 passwd 指令去设置 root 密码即可。

自己安装的Linux的更改方式 :

找回root密码(不同版本有点不同):服务器修改需要再物理机操作?

1、进入首页:

5秒内快速按下e;或者先按下上下键取消数秒,就会保持在这个界面,再e进入编辑界面

2、找到编辑界面中一Linux16开头的行,移到行末(也就是UTF-8,两者之间有空格)输入init=/bin/sh

3、ctrl+x:开启单用户模式(进入到如图:最末行光标闪烁状态);左侧ctrl不行就按右侧

4、输入:

mount -o remount,rw /

按回车enter

再输入passwd 如图

5、输入密码,再次确认密码

6、输入:

touch /.autorelabel

按回车

再次光标闪烁处输入:

exec /sbin/init

按回车等待(时间可能长点);完成后系统自动重启;新密码生效

2.5.2. 群组
/etc/group文件结构

记录GID 与群组名称的对应 , 文件每一行代表一个群组 , 也是使用 冒号 分隔, 共分为四栏 ,字段意义是:

  1. 群组名称
  2. 群组密码 : 通常不需要设置, 密码移动到/etc/gshadow 去, 因此只会存在一个 "x"
  3. GID : 群组ID
  4. 此群组支持的账号名称 : 一个账号可以加入多个群组 , 某个字段想加入此群组时,将该账号填入这个字段即可
    1. 举例 : 想让 dmtsai 与 alex也加入 root 这个群组 , 那么在第一行最后面加上 dmtsai,alex ; 注意不要有空格 , 使成为“ root:x:0:dmtsai,alex ”就可以

请注意,新版的 Linux 中,初始群组的用户群已经不会加入在第四个字段! 例如我们知道 root 这个帐号的主要群组为 root,但是在上面的范例中, 你已经不会看到 root 这个“用户”的名称在 /etc/group 的 root 那一行的第四个字段内

有效群组与初始群组
  1. 初始群组 : 每个使用者在他的 /etc/passwd 里面的第四栏有所谓的 GID , 那个 GID 就是所谓的“初始群组 (initial group) ”!也就是说,当使用者一登陆系统,立刻就拥有这个群组的相关权限的意思。
    1. 因为是初始群组, 使用者一登陆就会主动取得,不需要在 /etc/group 的第四个字段写入该帐号的
    2. 但是非 initial group 的其他群组可就不同了。举例来说,我将 dmtsai 加入 users 这个群组当中,由于 users 这个群组并非是 dmtsai 的初始群组,因此, 我必须要在 /etc/group 这个文件中,找到 users 那一行,并且将 dmtsai 这个帐号加入第四栏,这样 dmtsai 才能够加入 users 这个群组。
  1. 通常有效群组的作用是在新建文件时分配的群组

假如我同时加入多个群组,那么我在作业的时候,到底是以那个群组为准?

# 有效群组与支持群组的观察
groups  # 在输出的讯息中,可知道当前登录用户属于的所有群组 ,而第一个就是有效群组

# 有效群组的变换,而且是另外以一个 shell 来提供这个功能的
newgrp [群组名称]		# 有限制,想要切换的群组必须是你已经有支持的群组, 就是只能在用户属于的所有群组中选择
exit 				# 记得离开newgrp 环境
/etc/gshadow文件结构

同样冒号分隔 : 和/etc/group 几乎一样 , 四个字段意义为 :

  1. 群组名称
  2. 密码栏 : 如果开头为 ! 或空, 表示无合法密码 , 该群组不具有群组管理员
  3. 群组管理员的账号 (相关信息在gpasswd中)
  4. 有加入该群组支持的所属账号(与 /etc/group 内容相同)

以系统管理员角度来说 ,这个gshadow最大功能就是 创建群组管理员 ;

群组管理员 :

  1. 由于系统上面的账号可能会很多 ,但root可能平时太忙碌, 所以当有使用者想要加入某些群组时, root或许会没有空管理
  2. 此时如果能创建群组管理员 , 那么该群组管理员就能 将那个账号加入自己管理的群组中 !!!
  3. 不过目前有类似 sudo 之类的工具 , 所以这个群组管理员
head -n 4 /etc/gshadow
root:::
bin:::
daemon:::
sys:::

群组与用户的关系
  1. 一个账号可以加入多个群组
  2. 账号拥有所在群组的所有功能 ,如读/写/可执行权限,群组有的,该用户账号
  3. 要创建一个新的文件或者是新的目录,请问一下,新文件的群组是 哪个?这就得要检查一下当时的有效群组了 (effective group)。

假如我同时加入多个群组,那么我在作业的时候,到底是以那个群组为准?

账号管理
用户新增删除
useradd [-u UID] [-g 初始群组] [-G 次要群组] [-mM] [-c 说明栏] [-d 主文件夹绝对路径] [-s shell] 使用者帐号名
	选项与参数:
    -u :后面接的是 UID ,是一组数字。直接指定一个特定的 UID 给这个帐号;
    -g :后面接的那个群组名称就是我们上面提到的 initial group 啦~
    该群组的 GID 会被放置到 /etc/passwd 的第四个字段内。
    -G :后面接的群组名称则是这个帐号还可以加入的群组。
    这个选项与参数会修改 /etc/group 内的相关数据喔!
    -M :强制!不要创建使用者主文件夹!(系统帐号默认值)
    -m :强制!要创建使用者主文件夹!(一般帐号默认值)
    -c :这个就是 /etc/passwd 的第五栏的说明内容啦~可以随便我们设置的啦~
    -d :指定某个目录成为主文件夹,而不要使用默认值。务必使用绝对路径!
    -r :创建一个系统的帐号,这个帐号的 UID 会有限制 (参考 /etc/login.defs)
    -s :后面接一个 shell ,若没有指定则默认是 /bin/bash 的啦~
    -e :后面接一个日期,格式为“YYYY-MM-DD”此项目可写入 shadow 第八字段,
    亦即帐号失效日的设置项目啰;
    -f :后面接 shadow 的第七字段项目,指定密码是否会失效。0为立刻失效,
    -1 为永远不失效(密码只会过期而强制于登陆时重新设置而已。)
# 范例一:完全参考默认值创建一个使用者,名称为 vbird1
[root@study ~]# useradd vbird1
[root@study ~]# ll -d /home/vbird1
drwx------. 3 vbird1 vbird1 74 Jul 20 21:50 /home/vbird1
# 默认会创建使用者主文件夹,且权限为 700 !这是重点!
[root@study ~]# grep vbird1 /etc/passwd /etc/shadow /etc/group
/etc/passwd:vbird1:x:1003:1004::/home/vbird1:/bin/bash
/etc/shadow:vbird1:!!:16636:0:99999:7:::
/etc/group:vbird1:x:1004: 								# <==默认会创建一个与帐号一模一样的群组名

可以简单的使用“ useradd 帐号 ”来创建使用者即可。 CentOS 这些默认值主要会帮我们处理几个项目:

在 /etc/passwd 里面创建一行与帐号相关的数据,包括创建 UID/GID/主文件夹等;

在 /etc/shadow 里面将此帐号的密码相关参数填入,但是尚未有密码;

在 /etc/group 里面加入一个与帐号名称一模一样的群组名称;

在 /home 下面创建一个与帐号同名的目录作为使用者主文件夹,且权限为 700

系统帐号默认都不会主动创建主文件夹的

useradd 的参考文件 : /etc/default/useradd !

为什么"useradd vbird1 ”会主动在 /home/vbird1 创建起使用者的主文件夹?主文件夹内有什么数据且来自哪里?为何默认使用的是 /bin/bash这个 shell ?为何密码字段已经都规范好了 (0:99999:7 那一串)?

useradd -D
GROUP=100 		# <==默认的群组
HOME=/home 		# <==默认的主文件夹所在目录
INACTIVE=-1 	# <==密码失效日,在 shadow 内的第 7 栏
EXPIRE=				# <==帐号失效日,在 shadow 内的第 8 栏
SHELL=/bin/bash 	# <==默认的 shell
SKEL=/etc/skel    # <==使用者主文件夹的内容数据参考目录
CREATE_MAIL_SPOOL=yes   # <==是否主动帮使用者创建邮件信箱(mailbox)
用户与群组的设置
usermod -a -G users dmtsai   # 设置dmtsai的次要群组
grep dmtsai /etc/passwd /etc/group /etc/gshadow

/etc/passwd:dmtsai:x:1000:1000:dmtsai:/home/dmtsai:/bin/bash
/etc/group:wheel:x:10:dmtsai 								# <==次要群组的设置、安装时指定的
/etc/group:users:x:100:dmtsai								# <==次要群组的设置
/etc/group:dmtsai:x:1000: 									# <==因为是初始群组,所以第四字段不需要填入帐号
/etc/gshadow:wheel:::dmtsai									# <==次要群组的设置
/etc/gshadow:users:::dmtsai 								# <==次要群组的设置
/etc/gshadow:dmtsai:!!::

在 /etc/passwd 里面,dmtsai 这个使用者所属的群组为GID=1000 ,搜寻一下 /etc/group 得到 1000 是那个名为 dmtsai 的群组啦!
这就是 initial group。因为是初始群组, 使用者一登陆就会主动取得,不需要在 /etc/group 的第四个字段写入该帐号的!

分为以下几种:

  • root用户:也称超级用户,UID为0,权限最高。
  • 系统用户:也称虚拟用户、伪用户、假用户,是系统自身拥有的用户,UID为1~999,比如bin、daemon、adm、ftp、mail等,不具有登录Linux系统的能力,但却是系统运行不可缺少的用户。
  • 普通用户:UID为1000~60000,可以登录系统,操作自己目录的内容。
  1. /etc/passwd文件:
    1. 是Linux系统识别用户的重要文件,所有的用户都记录在该文件中。
    2. 一行表示一个用户的账户信息,有7个段位,依次为用户名、密码、用户标识号UID、用户所属的主要群组标识号GID、用户名全称、用户主目录、用户使用的Shell类型。
    3. UID是用户的ID值,在系统中每一位用户的UID值都是唯一的。UID是确认用户权限的标识,用户登录系统所处的角色是通过UID来实现的,而不是用户名
  1. /etc/shadow文件:
    1. 是/etc/passwd的影子文件,与/etc/passwd是对应互补的,内容包括用户及被加密的密码以及其他/etc/passwd不能包括的信息,比如用户账户的有效期限等。该文件只有root用户可以读取和操作。
    2. 用户主组、附加组:一个用户账户可以属于多个组群,挑一个作为用户的主组,即用户登录系统后属于该组。
Linu用户管理

2.6. 工作/定时调度

2.6.1. 常见例行调度

你会发现 Linux 会主动的帮我们进行一些工作! 比方说自动的进行线上更新 (on-line update)、自动的进行 updatedb ( locate 指令) 更新文件名数据库、自动的作登录文件分析 (所以 root常常会收到标题为 logwatch 的信件) 等等

常见的例行任务有 :

  1. 进行登录文件的轮替 (log rotate) :
    1. Linux会主动将系统所发生的各种信息都记录下来, 这就是登录文件
    2. 由于系统一直记录登录信息 , 登录文件就会越来越大, 大文件不但占容量还会造成读写性能的困扰 , 因此适当将登录文件挪一挪, 让旧数据与新数据分别存放 ,可比较有效记录登录信息; 这就是log rotate 的任务,也是系统必要的任务
  1. 登录文件分析 logwatch的任务
    1. 若系统发生了软件问题,硬件错误,资源安全问题等 ,绝大部分错误信息都会被记录到登录系统中 ; 因此系统管理员的重要任务之一就是分析登录文件。
    2. 但你不可能手动通过 vim 等软件去检视登录文件,因为数据太复杂了! 我们的 CentOS 提供了一只程序“ logwatch ”来主动分析登录信息,所以你会发现,你的 root 老是会收到标题为 logwatch 的信件,那是正常的!
  1. 创建 locat的数据库
    1. 该指令是通过已经存在的文件名数据库来进行系统上文件名的查询。我们的文件名数据库是放置到 /var/lib/mlocate/ 中。
    2. 系统会主动的进行 updatedb
  1. man page 查询数据库的创建:
    1. 与 locate 数据库类似的,可提供快速查询的 man page db 也是个数据库,
    2. 但如果要使用 man page 数据库时,就得要执行 mandb 才能够创建好啊!而这个 man page 数据库也是通过系统的例行性工作调度来自动执行的!
  1. RPM 软件登录文件的创建:
    1. RPM 是一种软件管理的机制。
    2. 由于系统可能会常常变更软件, 包括软件的新安装、非经常性更新等,都会造成软件文件名的差异。为了方便未来追踪,系统也帮我们将文件名作个排序的记录!有时候系统也会通过调度来帮忙RPM 数据库的重新创建喔!
  1. 移除暂存盘:
    1. 某些软件在运行中会产生一些暂存盘,但是当这个软件关闭时,这些暂存盘可能并不会主动的被移除。 有些暂存盘则有时间性,如果超过一段时间后,这个暂存盘就没有效用了,此时移除这些暂存盘就是一件重要的工作!否则磁盘容量会被耗光。系统通过例行性工作调度执行名为 tmpwatch 的指令来删除这些暂存盘呢!
  1. 与网络服务有关的分析行为: 如果你有安装类似 WWW 服务器软件 (一个名为 apache 的软件),那么你的 Linux 系统通常就会主动的分析该软件的登录文件。 同时某些凭证与认证的网络信息是否过期的问题,我们的 Linux 系统也会很友好的帮你进行自动检查!
  2. 其他安装的软件也可能会有例行任务 ,甚至是自定义的任务

工作调度分为例行(循环)和突发(仅一次)

  1. at : 可以处理仅执行一次就结束调度的指令 ; 不过执行at时 必须要有atd这个服务的支持 ; 某些distributions中,默认可能没有启动, Centos是默认启动的
  2. crontab : 所设置的工作会循环的一直进行下去 ! 可循环的时间为 分钟,小时,每周,每月,每年等 ; crontab除了使用指令外,还可编辑 /etc/crontab 来支持 ; 让crontab生效的服务是crond服务

注意 : at 和 crontab 的调度单位 是 minutes

2.6.2. at

要使用单一动作调度 , 必须有负责这个调度的任务 , 就是 atd

systemctl restart atd			# 重新启动atd 服务
systemctl enable atd			# 让这个服务开机自启动
systemctl status atd			# atd 状态
  atd.service - Job spooling tools
  	Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled) # 是否开机启动
  	Active: active (running) since Thu 2015-07-30 19:21:21 CST; 23s ago # 是否正在运行中
  Main PID: 26503 (atd)
  	CGroup: /system.slice/atd.service
  					└─26503 /usr/sbin/atd -f
  Jul 30 19:21:21 study.centos.vbird systemd[1]: Starting Job spooling tools...
  Jul 30 19:21:21 study.centos.vbird systemd[1]: Started Job spooling tools.

2.6.2.1. at的运行方式

既然是工作调度, 就会有产生工作的方式 , 并将工作排进 行程表中

  1. 产生工作的方式是如何进行的?
    1. 使用 at 指令来产生所要运行的工作 , 并将这个工作以文本文件的方式写入 /var/spool/at目录内 , 该工作便能等待atd这个服务的取用与执行
  1. 并不是所有人都可以进行 at 工作调度, 因为安全问题
    1. 很多主机被所谓的"绑架"后,最常发现的就是他们的系统中多了很多的怪客程序(cracker program) ,这些程序非常可能运用工作调度来执行或归集系统信息,并定时回报给怪客
    2. 那如何达到使用 at 的列管 ? 利用 /etc/at.allow 与 /etc/at.deny 两个文件进行 at 的使用限制
      1. 先找寻 /etc/at.allow 这个文件, 写在这个文件中的使用者才能使用 at , 没有则不能使用 (即使没有写在at.deny)
      2. 如果 /etc/at.allow 不存在, 就寻找 /etc/at.deny 这个文件 , 若写在这个at.deny 使用者不能使用 , 而没有在这个at.deny文件中的使用者, 就可以使用at (注意是 /etc/at.allow 不存在的前提)
      3. 若两个文件都不存在, 只有 root 可以使用at指令
    1. 不希望有某些使用者使用 at 的话,将那个使用者的帐号写入/etc/at.deny 即可!一个帐号写一行
    2. /etc/at.allow 是管理较为严格的方式,而 /etc/at.deny 则较为松散 (因为帐号没有在该文件中,就能够执行 at 了)

2.6.2.2. at 的使用
at [-mldv] TIME
at -c 工作号码		# 列出后面接的该项工作的实际指令内容
选项与参数:
	-m : 当at的工作完成后,即使没有输出讯息,亦以 email通知使用者该工作以完成
	-l : at -l 相当于 atq , 列出目前系统上面所有该使用者的 at 调度
	-d : at -d 相当于 atrm, 可以取消一个在at 调度中的工作列表
	-v : 可以使用较明显的时间格式列出 at 调度中的工作列表
	-c : 可以列出后面接的该项工作的实际指令内容
TIME:时间格式,这里可以定义出“什么时候要进行 at 这项工作”的时间,格式有:
HH:MM ex> 04:00	# 在今日的 HH:MM 时刻进行,若该时刻已超过,则明天的 HH:MM 进行此工作。
HH:MM YYYY-MM-DD ex> 04:00 2015-07-30	# 强制规定在某年某月的某一天的特殊时刻进行该工作!
HH:MM[am|pm] [Month] [Date] ex> 04pm July 30	# 也是一样,强制在某年某月某日的某时刻进行!
HH:MM[am|pm] + number [minutes|hours|days|weeks]
ex> now + 5 minutes ex> 04pm + 3 days
就是说,在某个时间点“再加几个时间后”才进行。



# **************************示例**************************** #
范例一:再过五分钟后,将 /root/.bashrc 寄给 root 自己
[root@study ~]# at now + 5 minutes 				# <==记得单位要加 s 喔!
at> /bin/mail -s "testing at job" root < /root/.bashrc
at> <EOT> <==这里输入 [ctrl] + d 就会出现 <EOF> 的字样!代表结束!
job 2 at Thu Jul 30 19:35:00 2015
# 上面这行信息在说明,第 2 个 at 工作将在 2015/07/30 的 19:35 进行!
# 而执行 at 会进入所谓的 at shell 环境,让你下达多重指令等待运行!
范例二:将上述的第 2 项工作内容列出来查阅
[root@study ~]# at -c 2
#!/bin/sh <==就是通过 bash shell 的啦!
# atrun uid=0 gid=0
# mail root 0
umask 22
....(中间省略许多的环境变量项目)....
cd /etc/cron\.d || {
echo 'Execution directory inaccessible' >&2
exit 1
}
${SHELL:-/bin/sh} << 'marcinDELIMITER410efc26'
/bin/mail -s "testing at job" root < /root/.bashrc # 这一行最重要!
marcinDELIMITER410efc26
# 你可以看到指令执行的目录 (/root),还有多个环境变量与实际的指令内容啦!
范例三:由于机房预计于 2015/08/05 停电,我想要在 2015/08/04 23:00 关机?
Tips
[root@study ~]# at 23:00 2015-08-04
at> /bin/sync
at> /bin/sync
at> /sbin/shutdown -h now
at> <EOT>
job 3 at Tue Aug 4 23:00:00 2015
# at 还可以在一个工作内输入多个指令呢!不错吧!

注意点 :

  1. 事实上,当我们使用 at 时会进入一个 at shell 的环境来让使用者下达工作指令,此时,建议你最好使用绝对路径来下达你的指令
  2. 由于指令的下达与 PATH 变量有关, 同时与当时的工作目录也有关连 (如果有牵涉到文件的话),因此使用绝对路径来下达指令,会是比较一劳永逸的方法。 为什么呢?
    1. 举例来说,你在 /tmp 下达“ at now ”然后输入“ mail -s "test" root < .bashrc ”, 问一下,那个 .bashrc 的文件会是在哪里?答案是“ /tmp/.bashrc ”!因为 at 在运行时,会跑到当时下达 at 指令的那个工作目录的缘故!
    2. 希望“我要在某某时刻,在我的终端机显示出 Hello 的字样”,然后就在 at 里面下达这样的信息“ echo "Hello" ”。等到时间到了,却发现没有任何讯息在屏幕上显示,这是啥原因啊?这是因为 at 的执行与终端机环境无关,而所有 standard output/standard error output 都会传送到执行者的 mailbox 去啦!所以需要echo "Hello" > /dev/tty1 输入到指定文件
2.6.2.3. at 的后台执行

离线继续工作的任务:

由于 at 工作调度的使用上,系统会将该项 at 工作独立出你的 bash 环境中, 直接交给系统的 atd 程序来接管,因此,当你下达了 at 的工作之后就可以立刻离线了, 剩下的工作就完全交给 Linux 管理即可!所以,如果有长时间的网络工作时,使用at 可以让你免除网络断线后的困扰!

2.6.2.4. at工作的管理

万一我下达了 at 之后,才发现指令输入错误,该如何是好?就将他移除!利用 atq 与 atrm !

[root@study ~]# atq
[root@study ~]# atrm (jobnumber)
# 范例一:查询目前主机上面有多少的 at 工作调度?
[root@study ~]# atq
3 Tue Aug 4 23:00:00 2015 a root
# 上面说的是:“在 2015/08/04 的 23:00 有一项工作,该项工作指令下达者为
# root”而且,该项工作的工作号码 (jobnumber) 为 3 号喔!
范例二:将上述的第 3 个工作移除!
[root@study ~]# atrm 3
[root@study ~]# atq
# 没有任何信息,表示该工作被移除了!

如果你是在一个非常忙碌的系统下运行 at , 能不能指定你的工作在系统较闲的时候才进行 : 使用batch指令 ,系统有空时才进行任务

其实 batch 是利用 at 来进行指令的下达!只是加入一些控制参数而已。这个 batch 神奇的地方在于:他会在 CPU 的工作负载小于 0.8 的时候,才进行你所下达的工作任务

范例一:请执行 pi 的计算,然后在系统闲置时,执行 updatdb 的任务
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# echo "scale=100000; 4*a(1)" | bc -lq &
# 然后等待个大约数十秒的时间,之后再来确认一下工作负载的情况!
[root@study ~]# uptime
19:56:45 up 2 days, 19:54, 2 users, load average: 3.93, 2.23, 0.96
[root@study ~]# batch
at> /usr/bin/updatedb
at> <EOT>
job 4 at Thu Jul 30 19:57:00 2015
[root@study ~]# date;atq
Thu Jul 30 19:57:47 CST 2015
4 Thu Jul 30 19:57:00 2015 b root
# 可以看得到,明明时间已经超过了,却没有实际执行 at 的任务!
[root@study ~]# jobs
[1] Running echo "scale=100000; 4*a(1)" | bc -lq &
[2] Running echo "scale=100000; 4*a(1)" | bc -lq &
[3]- Running echo "scale=100000; 4*a(1)" | bc -lq &
[4]+ Running echo "scale=100000; 4*a(1)" | bc -lq &
[root@study ~]# kill -9 %1 %2 %3 %4
# 这时先用 jobs 找出背景工作,再使用 kill 删除掉四个背景工作后,慢慢等待工作负载的下降
[root@study ~]# uptime; atq
20:01:33 up 2 days, 19:59, 2 users, load average: 0.89, 2.29, 1.40
4 Thu Jul 30 19:57:00 2015 b root
[root@study ~]# uptime; atq
20:02:52 up 2 days, 20:01, 2 users, load average: 0.23, 1.75, 1.28
# 在 19:59 时,由于 loading 还是高于 0.8,因此 atq 可以看得到 at job 还是持续再等待当中喔!
# 但是到了 20:01 时, loading 降低到 0.8 以下了,所以 atq 就执行完毕啰!

使用 uptime 可以观察到 1, 5, 15 分钟的“平均工作负载”量,因为是平均值,所以当我们如上表删除掉四个工作后,工作负载不会立即降低, 需要一小段时间让这个 1 分钟平均值慢慢回复到接近 0 啊!当小于 0.8 之后的“整分钟时间”时,atd 就会将 batch 的工作执行掉了!

什么是“整分钟时间”呢?不论是 at 还是下面要介绍的 crontab,他们最小的时间 单位是“分钟”,所以,基本上,他们的工作是“每分钟检查一次”来处理的! 就是整分(秒为 0 的时候),同时,你会发现其实 batch 也是使用 atq/atrm 来管理 的

2.6.3. cron
2.6.3.1. 使用者设置

使用者想要创建循环型工作调度时,使用的是 crontab 这个指令, 不过,为了安全性的问题, 与 at 同样的,我们可以限制使用 crontab 的使用者帐号!使用的限制数据有:

  1. /etc/cron.allow: 将可以使用 crontab 的帐号写入其中,若不在这个文件内的使用者则不可使用 crontab;
  2. /etc/cron.deny: 将不可以使用 crontab 的帐号写入其中,若未记录到这个文件当中的使用者,就可以使用 crontab 。

与 at 很像!同样的,以优先顺序来说, /etc/cron.allow 比 /etc/cron.deny 要优先, 而判断上面,这两个文件只选择一个来限制而已,因此,建议你只要保留一个即可, 免得影响自己在设置上面的判断!一般来说,系统默认是保留 /etc/cron.deny , 你可以将不想让他执行 crontab 的那个使用者写入 /etc/cron.deny 当中,一个帐号一行

当使用者使用 crontab 这个指令来创建工作调度之后,该项工作就会被纪录到 /var/spool/cron/ 里面去了,而且是以帐号来作为判别的!

举例来说, dmtsai 使用 crontab 后, 他的工作会被纪录到 /var/spool/cron/dmtsai 里头去!但请注意,不要使用 vi 直接编辑该文件, 因为可能由于输入语法错误,会导致无法执行 cron !另外, cron 执行的每一项工作都会被纪录到 /var/log/cron 这个登录文件中,所以,如果你的 Linux 不知道有否被植入木马时,也可以搜寻一下 /var/log/cron 这个登录文件!

2.6.3.2. 使用
[root@study ~]# crontab [-u username] [-l|-e|-r]
选项与参数:
-u :只有 root 才能进行这个任务,亦即帮其他使用者创建/移除 crontab 工作调度;
-e :编辑 crontab 的工作内容
-l :查阅 crontab 的工作内容
-r :移除所有的 crontab 的工作内容,若仅要移除一项,请用 -e 去编辑。
范例一:用 dmtsai 的身份在每天的 12:00 发信给自己
[dmtsai@study ~]$ crontab -e
# 此时会进入 vi 的编辑画面让您编辑工作!注意到,每项工作都是一行。
0 12 * * * mail -s "at 12:00" dmtsai < /home/dmtsai/.bashrc
#分 时 日 月 周 |<==============指令串========================>|

默认情况下,任何使用者只要不被列入 /etc/cron.deny 当中,那么他就可以直接下达“ crontab -e ”去编辑自己的例行性命令了

vim中以一个工作一行来编辑,编辑完毕之后输入“ :wq ”储存后离开 vi 就 可以了!而每项工作 (每行) 的格式都是具有六个字段,这六个字段的意义为:

周的数字为 0 或 7 时,都代表“星期天”的意思!!!

特殊字符

那个 crontab 每个人都只有一个文件存在,就是在 /var/spool/cron 里

# 查询使用者当前crontab
[dmtsai@study ~]$ crontab -l		
0 12 * * * mail -s "at 12:00" dmtsai < /home/dmtsai/.bashrc
59 23 1 5 * mail kiki < /home/dmtsai/lover.txt
*/5 * * * * /home/dmtsai/test.sh
30 16 * * 5 mail friend@his.server.name < /home/dmtsai/friend.txt
# 注意,若仅想要移除一项工作而已的话,必须要用 crontab -e 去编辑~
# 如果想要全部的工作都移除,才使用 crontab -r !
[dmtsai@study ~]$ crontab -r
[dmtsai@study ~]$ crontab -l
no crontab for dmtsai

2.6.4. 唤醒停机期间未进行的任务 anacron

anacron并不是取代crontab的 ,其存在目的就是

  1. 处理非24小时一直启动的Linux系统的crontab的执行!
  2. 以及某些原因导致的超时时间而没有被执行的调度工作

anacron 也是每小时被crond执行一次 , 然后anacron再去检测相关的调度任务有没有被执行 ,若有则执行该调度任务 , 执行完毕或无须执行任何调度时, anacron就停止了

anacron 配合 /etc/anacrontab 的设置,可以唤醒停机期间系统未进行的 crontab 任务!

anacron 是一支程序而非一个服务 ! 这支程序在Centos中已经进入crontab的调度 !

anacron 会每个小时被主动执行一次 , anacron的配置文件在/etc/cron.hourly

[root@study ~]# cat /etc/cron.hourly/0anacron
#!/bin/sh
# Check whether 0anacron was run today already
if test -r /var/spool/anacron/cron.daily; then
		day=`cat /var/spool/anacron/cron.daily`
fi
if [ `date +%Y%m%d` = "$day" ]; then
		exit 0;
fi
# 上面的语法在检验前一次执行 anacron 时的时间戳记!
# Do not run jobs when on battery power
if test -x /usr/bin/on_ac_power; then
		/usr/bin/on_ac_power >/dev/null 2>&1
		if test $? -eq 1; then
		exit 0
		fi
fi
/usr/sbin/anacron -s
# 所以其实也仅是执行 anacron -s 的指令!因此我们得来谈谈这支程序!

anacron [-sfn] [job] ...
anacron -u [job]...
选型与参数 :
	-s : 开始一连续的执行各项工作,会依据时间记录文件的数据判断是否进行;
	-f : 强制进行,而不去判断时间记录文件的时间戳记
	-n : 立刻进行未进行的任务,而不延迟等待时间
	-u : 仅更新时间记录文件的时间戳记,不进行任何工作
	job : 由 /etc/anacrontab 定义的各项工作名称

在我们的 CentOS 中,anacron 的进行其实是在每个小时都会被抓出来执行一次,但是为了担心 anacron 误判时间参数,因此 /etc/cron.hourly/ 里面的 anacron 才会在文件名之前加个 0 (0anacron),让 anacron 最先进行!就是为了让时间戳记先更新!以避免 anacron 误判 crontab 尚未进行任何工作的意思。

2.6.4.1. anacron执行流程

根据上面的配置文件内容,我们大概知道 anacron 的执行流程应该是这样的 (以cron.daily 为例):

  1. 由 /etc/anacrontab 分析到 cron.daily 这项工作名称的天数为 1 天;
  2. 由 /var/spool/anacron/cron.daily 取出最近一次执行 anacron 的时间戳记;
  3. 由上个步骤与目前的时间比较,若差异天数为 1 天以上 (含 1 天),就准备进行指令;
  4. 若准备进行指令,根据 /etc/anacrontab 的设置,将延迟 5 分钟 + 3 小时 (看START_HOURS_RANGE 的设置);
  5. 延迟时间过后,开始执行后续指令,亦即“ run-parts /etc/cron.daily ”这串指令;
  6. 执行完毕后, anacron 程序结束

3. 程序管理

一个程序被载入到内存当中运行 , 那么在内存内的那个数据就被成为程序 (process) ;

所有系统上跑的数据都会以程序的型态存在

系统的程序有哪些状态?不同的状态会如何影响系统的运行? 程序之间是否可以互相控管等等的,这些都是我们所必须要知道的项目。 另外与程序有关的还有 SELinux 这个加强文件存取安全性的咚咚,也必须要做个了解

3.1. 什么是程序?

  1. Linux下的所有指令与你能进行的动作都与程序有关 , 系统如何判定你的权限 ? 就是通过UID/GID 以及文件的属性相关性
  2. 触发任何一个事件时, 系统都会将他定义成为一个程序 , 并给与这个程序一个PID , 成为PID ,同时依据启发这个程序的使用者与相关属性关系 ,给与这个PID一组有效的权限设置 ;

什么是触发事件?

3.1.1. process和program

如何产生一个程序? 就是"执行一个程序或指令" 就可以触发一个事件而取得一个PID !

系统是仅认识binary file的 ,当系统工作时 就是需要启动一个binary file , 这个binary file 就是一个程序

每个程序都有三组人马的权限 ;

不同的身份执行这个program时, 系统给与的权限也不同 : 举例来说, root执行touch时 ,取得的是UID/GID=0/0的权限, 而当dmtsai(UID/GID=501/501)执行touch 的权限就和root不同

  1. 程序一般放在实体磁盘 , 通过使用者执行触发 ;
  2. 触发后会载入到内存中成为一个个体,那就是程序 ;
  3. 为了系统可管理这个程序, 因此程序 会给与执行者的权限/属性等参数, 并包括程序所需要的指令码与数据或文件数据等 , 最后再给与一个PID
  4. 系统就是根据PID 来判断该process是否具有权限进行工作 ;

举个更具体的例子 : 操作系统的时候, 是利用连线程序或直接在主机前面登录 ,然后取得shell, 而shell是bash ,这个bash是/bin/bash ,而同时间的每个人登陆都是执行 /bin/bash : 不过每个人取得的权限是不同的, 如下:

注 : 在当前程序中衍生出来的其他程序(即子程序)在一般状态下, 也会沿用这个程序的相关权限 !!!

  1. 每个程序的父程序 通过 PPID (Parent PID)判断
  2. 我们登陆 bash 之后, 就是取得一个名为 bash 的 PID 了 ; 单一的bash接口下 , 同时进行多个工作 ,使用 & ; 如cp file1 file2 &

有时候会发现:“明明我将有问题的程序关闭了,怎么过一阵子他又自动的产生? 而且新产生的那个程序的 PID 与原先的还不一样?”不要怀疑,如果不是 crontab 工作调度的影响,肯定有一支父程序存在,所以你杀掉子程序后, 父程序就会主动再生一支!那怎么办?正所谓这:“擒贼先擒王”,找出那支父程序,然后将他删除就对啦!

3.1.2. 程序调用的流程 fork-and-exec

子程序和父程序的关系比较复杂, 最大的复杂点在于 程序相互之间的调用

在Linux的程序调用 通常称为 fork-and-exec 的流程 ! 程序都会借由父程序以复制(fork)的方式成生一个一模一样的子程序 , 然后被复制出来的子程序再以exec 的方式执行实际要进行的程序 ,最终就成为一个子程序的存在 !

  1. 系统先fork 的方式复制一个与父程序相同的暂存程序 , 这个程序与父程序唯一的差别就是PID不同 , 但这个暂存程序还会多一个PPID的参数 , PPID如前所述, 就是父程序的程序识别码
  2. 然后暂存程序开始以exec 的方式载入实际要执行的程序 ,以下图来讲 ,新的程序名称为qqq ,最终子程序的程序码就会变成qqq了

3.1.3. 系统或网络服务 : 常驻内存的程序
  1. 常驻程序一般被称为 服务 (daemon)
  2. 以 crontab 来说,他的主要执行程序名称应该是 cron 或 at 才对,为啥要加个 d 在后面?而成为 crond, atd 呢?就是因为 Linux 希望我们可以简单的判断该程序是否为 daemon, 所以,一般 daemon 类型的程序都会加上 d 在文件名后头~包括我们会看到的 httpd, vsftpd 等等都是。
  3. 网络服务比较有趣的地方,在于这些程序被执行后,他会启动一个可以负责网络监听的端口 (port) ,以提供外部用户端 (client) 的连线要求。

3.2. 工作管理(job control)/后台运行

  1. 这个工作管理 (job control) 是用在 bash 环境下的,也就是说:“当我们登陆系统取得 bash shell 之后,在单一终端机接口下同时进行多个工作的行为管理 ”。
    1. 举例来说,我们在登陆 bash 后, 想要一边复制文件、一边进行数据搜寻、一边进行编译,还可以一边进行 vim 程序撰写!
  1. 当然我们可以重复登陆那六个命令行的终端机环境中,不过,能不能在一个 bash 内达成? 当然可以!就是使用 job control

进行工作管理的行为中, 其实每个工作都是目前 bash 的子程序,亦即彼此之间是有相关性的。 我们无法以 job control 的方式由 tty1 的环境去管理 tty2 的 bash !

bash 的 job control 必须要注意到的限制是:

  1. 这些工作所触发的程序必须来自于你 shell 的子程序(只管理自己的 bash);
  2. 前景:你可以控制与下达指令的这个环境称为前景的工作 (foreground);
  3. 背景:可以自行运行的工作,你无法使用 [ctrl]+c 终止他,可使用 bg/fg 调用该工作;
  4. 背景中“执行”的程序不能等待 terminal/shell 的输入(input)
3.2.1. 将指令丢到背景中“执行”的 &
将 /etc/ 整个备份成为 /tmp/etc.tar.gz 且不想要等待:
[root@study ~]# tar -zpcf /tmp/etc.tar.gz /etc &
[1] 14432 				# <== [job number] PID
[root@study ~]# tar: Removing leading `/' from member names
# 在中括号内的号码为工作号码 (job number),该号码与 bash 的控制有关。
# 后续的 14432 则是这个工作在系统中的 PID。至于后续出现的数据是 tar 执行的数据流,
# 由于我们没有加上数据流重导向,所以会影响画面!不过不会影响前景的操作!

丢到背景中的工作什么时候完成?完成的时候会显示什么?如果你输入几个指令后,突然出现这个数据:
[1]+ Done tar -zpcf /tmp/etc.tar.gz /etc
# 就代表 [1] 这个工作已经完成 (Done) ,该工作的指令则是接在后面那一串命令行
  1. 工作丢到背景当中要特别注意数据的流向
  2. 包括上面的讯息就有出现错误讯息,导致我的前景被影响。 虽然只要按下 [enter] 就会出现提示字符。但如果我将刚刚那个指令改成:tar -zpcvf /tmp/etc.tar.gz /etc &,多了一个 -v 选项(输出详细过程), 情况会怎样?
  3. 在背景当中执行的指令,如果有 stdout 及 stderr 时,他的数据依旧是输出到屏幕上面的, 所以,我们会无法看到提示字符,当然也就无法完好的掌握前景工作。
  4. 同时由于是背景工作的tar ,此时你怎么按下Ctrl+c 也无法停止屏幕被搞得花花绿绿 , 最佳情况就是利用数据流重导向将输出数据传送至某个文件中。
[root@study ~]# tar -zpcvf /tmp/etc.tar.gz /etc > /tmp/log.txt 2>&1 &
[1] 14547
[root@study ~]#

工作号码 (job number) 只与你这个 bash 环境有关,但是他既然是个指令触
发的,所以当然一定是一个程序, 因此你会观察到有 job number 也搭配一个 PID !
3.2.2. 将目前工作丢到背景中暂停 : Ctrl+z

想个情况:如果我正在使用 vim ,却发现我有个文件不知道放在哪里,需要到bash 环境下进行搜寻,此时是否要结束 vim 呢?当然不需要啊!只要暂时将 vim 给他丢到背景当中等待即可。 例如以下的案例:

[root@study ~]# vim ~/.bashrc
# 在 vim 的一般模式下,按下 [ctrl]-z 这两个按键
[1]+ Stopped vim ~/.bashrc
[root@study ~]# 				# <==顺利取得了前景的操控权!
[root@study ~]# find / -print
....(输出省略)....
# 此时屏幕会非常的忙碌!因为屏幕上会显示所有的文件名。请按下 [ctrl]-z 暂停
[2]+ Stopped find / -print

在 vim 的一般模式下,按下 [ctrl] 及 z 这两个按键,屏幕上会出现 [1] ,表示这是第一个工作, 而那个 + 代表最近一个被丢进背景的工作且目前在背景下默认会被取用的那个工作 (与 fg 这个指令有关 )!而那个 Stopped 则代表目前这个工作的状态。在默认的情况下,使用 [ctrl]-z 丢到背景当中的工作都是“暂停”的状态!

3.2.3. 观察并恢复目前的背景工作 : jobs
一般来说,直接下达 jobs 即可!如果你还想要知道该 job number 的 PID 号码,可以加上 -l 这个参数
[root@study ~]# jobs [-lrs]
    选项与参数:
    -l :除了列出 job number 与指令串之外,同时列出 PID 的号码;
    -r :仅列出正在背景 run 的工作;
    -s :仅列出正在背景当中暂停 (stop) 的工作。
# 范例一:观察目前的 bash 当中,所有的工作,与对应的 PID
[root@study ~]# jobs -l
[1]- 14566 Stopped vim ~/.bashrc
[2]+ 14567 Stopped find / -print

[root@study ~]# fg   			# 恢复当前+的背景工作

仔细看到那个 + - 号喔!那个 + 代表默认的取用工作。 
其实 + 代表最近被放到背景的工作号码, - 代表最近最后第二个被放置到背景中的工作号码。 
而超过最后第三个以后的工作,就不会有 +/- 符号存在了!
“目前我有两个工作在背景当中,两个工作都是暂停的,而如果我仅输入 fg 时,那么那个 [2] 会被拿到前景当中来处理”!

3.2.4. 将背景工作拿到前景来处理:fg

fg (foreground)

[root@study ~]# fg %jobnumber
    选项与参数:
    %jobnumber :jobnumber 为工作号码(数字)。注意,那个 % 是可有可无的!
# 范例一:先以 jobs 观察工作,再将工作取出:
[root@study ~]# jobs -l
[1]- 14566 Stopped vim ~/.bashrc
[2]+ 14567 Stopped find / -print
[root@study ~]# fg 				# <==默认取出那个 + 的工作,亦即 [2]。立即按下[ctrl]-z
[root@study ~]# fg %1 		# <==直接规定取出的那个工作号码!再按下[ctrl]-z
[root@study ~]# jobs -l
[1]+ 14566 Stopped vim ~/.bashrc
[2]- 14567 Stopped find / -print 			# 背景顺序改变了一下

如果输入“ fg - ” 则代表将 - 号的那个工作号码拿出来,上面就是 [2]- 那个工作号码!
3.2.5. 后台下的状态变成前台运行: bg
# 下面的测试要进行的快一点

# 范例一:一执行 find / -perm /7000 > /tmp/text.txt 后,立刻丢到背景去暂停!
[root@study ~]# find / -perm /7000 > /tmp/text.txt
# 此时,请立刻按下 [ctrl]-z 暂停!
[3]+ Stopped find / -perm /7000 > /tmp/text.txt
# 范例二:让该工作在背景下进行,并且观察他!!
[root@study ~]# jobs ; bg %3 ; jobs
[1] Stopped vim ~/.bashrc
[2]- Stopped find / -print
[3]+ Stopped find / -perm /7000 > /tmp/text.txt
[3]+ find / -perm /7000 > /tmp/text.txt &
[1]- Stopped vim ~/.bashrc
[2]+ Stopped find / -print
[3] Running find / -perm /7000 > /tmp/text.txt &   # 那个状态列~以经由 Stopping 变成了Running

3.2.6. 管理背景当中的工作: kill

kill命令用于向进程发送信号,以便控制进程的行为,要将该工作直接移除,或者是将该工作重新启动 : kill

[root@study ~]# kill -signal %jobnumber
[root@study ~]# kill -l
    选项与参数:
    -l :这个是 L 的小写,列出目前 kill 能够使用的讯号 (signal) 有哪些?
    signal :代表给予后面接的那个工作什么样的指示!用 man 7 signal 可知:
        -1 :重新读取一次参数的配置文件 (类似 reload);
        -2 :代表与由键盘输入 [ctrl]-c 同样的动作;
        -9 :立刻强制删除一个工作;
        -15:以正常的程序方式终止一项工作。与 -9 是不一样的。


范例一:找出目前的 bash 环境下的背景工作,并将该工作“强制删除”。
[root@study ~]# jobs
[1]+ Stopped vim ~/.bashrc
[2] Stopped find / -print
[root@study ~]# kill -9 %2; jobs
[1]+ Stopped vim ~/.bashrc
[2] Killed find / -print
# 再过几秒你再下达 jobs 一次,就会发现 2 号工作不见了!因为被移除了!

范例二:找出目前的 bash 环境下的背景工作,并将该工作“正常终止”掉。
[root@study ~]# jobs
[1]+ Stopped vim ~/.bashrc
[root@study ~]# kill -SIGTERM %1
# -SIGTERM 与 -15 是一样的!您可以使用 kill -l 来查阅!
# 不过在这个案例中, vim 的工作无法被结束喔!因为他无法通过 kill 正常终止的意思!

其中,-15和-9是两个常用的信号,-9 这个 signal 通常是用在“强制删除一个不正常的工作”时所使用的, -15 则是以正常步骤结束一项工作(15也是默认值)!

它们的区别如下:

  1. SIGTERM(-15)信号:该信号通知进程正常终止,并允许它完成未完成的任务。当进程收到SIGTERM信号时,它将尝试优雅地退出,并清理临时文件、关闭打开的文件等资源。如果进程成功退出,它将返回一个退出状态码。如果进程还在运行,您可以尝试再次发送SIGTERM信号,或者使用SIGKILL信号强制终止它。
  2. SIGKILL(-9)信号:该信号强制终止进程,并不允许它完成未完成的任务。当进程收到SIGKILL信号时,它将立即终止,并且不会执行任何清理操作。这意味着,进程可能会留下临时文件、打开的文件等资源,需要手动清理。如果进程无法响应SIGTERM信号,您可以尝试发送SIGKILL信号强制终止它。

因此,通常情况下,应该首先尝试发送SIGTERM信号,以便进程有机会优雅地退出,并清理资源。只有在进程无法响应SIGTERM信号时,才应该发送SIGKILL信号强制终止它。

举上面的例子来说, 我用 vim 的时候,不是会产生一个 .filename.swp 的文件吗? 那么,当使用 -15 这个 signal 时, vim 会尝试以正常的步骤来结束掉该 vi 的工作, 所以 .filename.swp 会主动的被移除。但若是使用 -9 这个 signal 时,由于该 vim 工作会被强制移除掉,因此, .filename.swp 就会继续存在文件系统当中

kill 后面接的数字默认会是 PID ,如果想要管理 bash 的工作控制,就得要加上 %数字 了, 这点也得特别留意才行!

3.2.7. 离线管理 nohup
  1. 要注意的是,我们在工作管理当中提到的“背景”指的是在终端机模式下可以避免 [crtl]-c 中断的一个情境, 你可以说那个是 bash 的背景,并不是放到系统的背景去!
  2. 所以,工作管理的背景依旧与终端机有关啦!
  3. 在这样的情况下,如果你是以远端连线方式连接到你的 Linux 主机,并且将工作以 & 的方式放到背景去,请问,在工作尚未结束的情况下你离线了,该工作还会继续进行吗?答案是“否”!不会继续进行,而是会被中断掉。

如果我的工作需要进行一大段时间,我又不能放置在背景下面,那该如何处理呢?

  1. 首先,你可以参考前一章的 at 来处理即可!因为 at 是将工作放置到系统背景, 而与终端机无关。
  2. 如果不想要使用 at 的话,那你也可以尝试使用 nohup 这个指令来处理!这个 nohup 可以让你在离线或登出系统后,还能够让工作继续进行。
[root@study ~]# nohup [指令与参数] 			# <==在终端机前景中工作
[root@study ~]# nohup [指令与参数] & 		# <==在终端机背景中工作

上述指令需要注意的是, nohup 并不支持 bash 内置的指令,因此你的指令必须要是外部指令才行。


# 1. 先编辑一支会“睡着 500 秒”的程序:
[root@study ~]# vim sleep500.sh
#!/bin/bash
/bin/sleep 500s
/bin/echo "I have slept 500 seconds."
# 2. 丢到背景中去执行,并且立刻登出系统:
[root@study ~]# chmod a+x sleep500.sh
[root@study ~]# nohup ./sleep500.sh &
[2] 14812
[root@study ~]# nohup: ignoring input and appending output to `nohup.out' <==会告知这个讯息!
[root@study ~]# exit


如果你再次登陆的话,再使用 pstree 去查阅你的程序,会发现 sleep500.sh 还在
执行中喔!并不会被中断掉!

由于我们的程序最后会输出一个讯息,但是 nohup 与终端机其实无关了, 因此这个讯息的输出就会被导向“ ~/nohup.out ”,
所以你才会看到上述指令中,当你输入 nohup 后, 会出现那个提示讯息

nohup与&的使用场景举例

# 后台运行Java应用的jar包
nohup java -jar sms.jar --server.port=8080 &
  1. 执行nohup命令后回车,输入的数据将被忽略,不会到达任何地方。在nohup命令执行期间,终端不会接收到输入,因此任何输入都不会被处理 .
  2. 如果需要在nohup命令执行期间输入数据,可以将输入重定向到文件中,然后在nohup命令执行完成后再进行处理。
  3. 例如,可以使用以下命令将输入或输出重定向到文件中:
    1. nohup command > output.txt 2>&1 &   ; 该命令将nohup命令的输出和错误信息重定向到output.txt文件中。
    2. 如果需要输入数据,可以将输入数据保存到文件中,然后使用以下命令将文件内容重定向到nohup命令中:nohup command < input.txt > output.txt 2>&1 &
    3. 在命令行中,2表示标准错误输出(stderr),1表示标准输出(stdout),1前面的&表示将其与文件描述符进行区分。因此,2>&1表示将标准错误输出重定向到标准输出。
  4. 具体来说,2>&1将标准错误输出重定向到标准输出,标准错误输出与标准输出合并,使得两者都被重定向到同一个文件中。这样做的目的是将所有的输出信息都保存到同一个文件中,以便于后续查看和分析。

那如何关闭nohup开启的后台进程呢

# 找到 nohup 开启的进程的PID
ps aux | grep nohup  

# 使用kill命令向nohup进程发送SIGTERM信号
kill -15 PID  # 该命令将向nohup进程发送SIGTERM信号,通知它停止运行,并等待一段时间以便它完成未完成的任务。
kill -9 PID   # 如果nohup进程没有响应SIGTERM信号,请使用kill命令发送SIGKILL信号该命令将向nohup进程发送SIGKILL信号,强制终止进程,但可能会导致未完成的任务丢失或损坏。

# 请注意,如果nohup进程是由其他用户启动的,您可能需要使用sudo命令或root权限才能停止它。

3.3. 程序的观察 ps和top

查看正在运行中的程序 : 静态的ps和动态的top , 还能以pstree 查看程序树之间的关系

3.3.1. ps
# 记住一下两种即可
ps -l			# 将目前属于您自己这次登陆的 PID 与相关信息列示出来(只与自己的 bash 有关)
ps aux		# 查看所有系统运行的程序

[root@study ~]# ps aux 				<==观察系统所有的程序数据
[root@study ~]# ps -lA 				<==也是能够观察所有系统的数据
[root@study ~]# ps axjf 			<==连同部分程序树状态
    选项与参数:
        -A :所有的 process 均显示出来,与 -e 具有同样的效用;
        -a :不与 terminal 有关的所有 process ;
        -u :有效使用者 (effective user) 相关的 process ;
        x :通常与 a 这个参数一起使用,可列出较完整信息。
  	输出格式规划:
        l :较长、较详细的将该 PID 的的信息列出;
        j :工作的格式 (jobs format)
        -f :做一个更为完整的输出。

# --------------------------------示例---------------------------------- #

[root@study ~]# ps -l
F S UID PID PPID C PRI NI ADDR 	SZ 		WCHAN 	TTY 		TIME 			CMD
4 S 0 14830 13970 0 80 0 		- 	52686 	poll_s 	pts/0 	00:00:00 	sudo
4 S 0 14835 14830 0 80 0 		- 	50511 	wait 		pts/0 	00:00:00 	su
4 S 0 14836 14835 0 80 0 		- 	29035 	wait 		pts/0 	00:00:00 	bash
0 R 0 15011 14836 0 80 0 		- 	30319 	- 			pts/0 	00:00:00 	ps
# 非必要不要使用 root 直接登陆, 从这个 ps -l 的分析,你也可以发现,
# 其实是使用 sudo 才转成 root 的身份~!

ps -l显示的属性说明 :

  1. F : 代表这个程序旗标(process flags) , 说明这个程序的总结权限 ,常见号码 :
    1. 若为 4 表示此程序的权限为root
    2. 若为1 表示 此子程序进进行复制(fork) 而没有实际执行(exec)
  1. S : 代表这个程序的状态 (STAT) ,主要状态有 :
    1. R(running) : 运行中
    2. S (sleep) : 睡眠 ,可以被唤醒(signal)
    3. D : 不可被唤醒的睡眠状态 , 通常情况是正在等待I/O 的情况 (ex>打印)
    4. T (stop) : 停止状态 , 可能是在工作控制(背景暂停) 或除错 (traced) 状态
    5. Z (Zombie) : 僵尸状态 , 程序已经终止但是无法被移除至内存外
  1. UID/PID/PPID : 代表“此程序被该 UID 所拥有/程序的 PID 号码/此程序的父程序 PID 号码
  2. C : 代表CPU使用率 , 单位百分比
  3. PRI/NI : Priority/Nice 的缩写 , 代表此程序被CPU执行的优先顺序 , 数值越小代表该程序越快被CPU执行
  4. ADDR/SZ/WCHAN : 都与内存有关 ,
    1. ADDR 是 kernel function: 指出该程序在内存的哪个部分 ,若是个running程序,一般显示 "-"
    2. SZ 代表此程序用掉多少内存
    3. WCHAN : 程序是否运行中, 同样 为 "-"是运行中
  1. TTY : 登陆者的终端机位置 , 若为 远程登录则使用动态终端接口 (pts/n) (n是一个数值)
  2. TIME :使用掉的CPU时间 , 注意 : 是此程序实际花费CPU运行的时间 , 而不是系统时间
  3. CMD : 是command的缩写 , 造成此程序触发的是什么指令

# 范例二:列出目前所有的正在内存当中的程序:
[root@study ~]# ps aux
USER 	PID 	%CPU %MEM VSZ 	RSS 	TTY 	STAT START 	TIME COMMAND
root 	1 		0.0 	0.2 60636 7948 	? 		Ss 		Aug04 0:01 /usr/lib/systemd/systemd ...
root 	2 		0.0 	0.0 0 		0		 	? 		S 		Aug04 0:00 [kthreadd]
.....(中间省略).....
root 14830 	0.0 	0.1 210744 3988 pts/0 S 		Aug04 0:00 sudo su -
root 14835 	0.0 	0.1 202044 2996 pts/0 S 		Aug04 0:00 su -
root 14836 	0.0 	0.1 116140 2960 pts/0 S 		Aug04 0:00 -bash
.....(中间省略).....
root 18459 	0.0 	0.0 123372 1380 pts/0 R+ 		00:25 0:00 ps aux

ps aux 与 ps -l 显示的项目并不同 ; 一般来说,ps aux 会依照 PID 的顺序来排序显示

  1. USER : 该 process 属于那个使用者帐号的
  2. PID : 该 process 的程序识别码
  3. %CPU : 该 process 使用掉的 CPU 资源百分比;
  4. %MEM : 该 process 所占用的实体内存百分比;
  5. VSZ : 该 process 使用掉的虚拟内存量 (KBytes)
  6. RSS : 该 process 占用的固定的内存量 (KBytes)
  7. TTY : 该 process 是在那个终端机上面运行,若与终端机无关则显示 ? ;
    1. 另外,tty1-tty6 是本机上面的登陆者程序,若为 pts/0 等等的,则表示为由网络连接进主机的程序。
  1. STAT : 该程序目前的状态,状态显示与 ps -l 的 S 旗标相同 (R/S/T/Z)
  2. START : 被触发启动的时间
  3. TIME : 实际使用CPU运行的时间
  4. COMMAND : 该程序是什么指令
# 范例三:以范例一的显示内容,显示出所有的程序:
[root@study ~]# ps -lA
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 1 0 0 80 0 - 15159 ep_pol ? 00:00:01 systemd
1 S 0 2 0 0 80 0 - 0 kthrea ? 00:00:00 kthreadd
1 S 0 3 2 0 80 0 - 0 smpboo ? 00:00:00 ksoftirqd/0
....(以下省略)....
# 你会发现每个字段与 ps -l 的输出情况相同,但显示的程序则包括系统所有的程序。


# 范例四:列出类似程序树的程序显示:
[root@study ~]# ps axjf
PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND
0 2 0 0 ? -1 S 0 0:00 [kthreadd]
2 3 0 0 ? -1 S 0 0:00 \_ [ksoftirqd/0]
.....(中间省略).....
1 1326 1326 1326 ? -1 Ss 0 0:00 /usr/sbin/sshd -D
1326 13923 13923 13923 ? -1 Ss 0 0:00 \_ sshd: dmtsai [priv]
13923 13927 13923 13923 ? -1 S 1000 0:00 \_ sshd: dmtsai@pts/0
13927 13928 13928 13928 pts/0 18703 Ss 1000 0:00 \_ -bash
13928 13970 13970 13928 pts/0 18703 S 1000 0:00 \_ bash
13970 14830 14830 13928 pts/0 18703 S 0 0:00 \_ sudo su -
14830 14835 14830 13928 pts/0 18703 S 0 0:00 \_ su -
14835 14836 14836 13928 pts/0 18703 S 0 0:00 \_ -bash
14836 18703 18703 13928 pts/0 18703 R+ 0 0:00 \_ ps axjf
.....(后面省略)
  1. 在进行一些测试时,都是以网络连线进虚拟机来测试的,所以,你会发现其实程序之间是有相关性的!
  2. 不过,其实还可以使用 pstree 来达成这个程序树!以上面的例子来看:
    1. 是通过 sshd 提供的网络服务取得一个程序, 该程序提供 bash 给我使用,而我通过 bash 再去执行 ps axjf
    2. 其他各字段的意义请 man ps (虽然真的很难 man 的出来!)

# 范例五:找出与 cron 与 rsyslog 这两个服务有关的 PID 号码?
[root@study ~]# ps aux | egrep '(cron|rsyslog)'
root 742 0.0 0.1 208012 4088 ? Ssl Aug04 0:00 /usr/sbin/rsyslogd -n
root 1338 0.0 0.0 126304 1704 ? Ss Aug04 0:00 /usr/sbin/crond -n
root 18740 0.0 0.0 112644 980 pts/0 S+ 00:49 0:00 grep -E --color=auto (cron|rsyslog)
3.3.2. 僵尸程序

造成僵尸程序的成因是因为该程序应该已经执行完毕,或者是因故应该要终止了,但是该程序的父程序却无法完整的将该程序结束掉,而造成那个程序一直存在内存当中。

如果你发现在某个程序的 CMD 后面还接上 <defunct> 时,就代表该程序是僵尸程序

当系统不稳定的时候就容易造成所谓的僵尸程序,可能是因为程序写的不好,或者是使用者的操作习惯不良等等所造成。

如果你发现系统中很多僵尸程序时,要找出该程序的父程序,然后好好的做个追踪,好好的进行主机的环境最优化

事实上,通常僵尸程序都已经无法控管,而直接是交给 systemd 这支程序来负责了,偏偏 systemd 是系统第一支执行的程序, 他是所有程序的父程序!我们无法杀掉该程序的 (杀掉他,系统就死掉了!),所以,如果产生僵尸程序, 而系统过一阵子还没有办法通过核心非经常性的特殊处理来将该程序删除时,那你只好通过 reboot 的方式来将该程序抹去了

3.3.3. top

动态观察程序变化

[root@study ~]# top [-d 数字] | top [-bnp]
    选项与参数:
        -d :后面可以接秒数,就是整个程序画面更新的秒数。默认是 5 秒;
        -b :以批次的方式执行 top ,还有更多的参数可以使用喔!
        # 通常会搭配数据流重导向来将批次的结果输出成为文件。
        -n :与 -b 搭配,意义是,需要进行几次 top 的输出结果。
        -p :指定某些个 PID 来进行观察监测而已。
        # 在 top 执行过程当中可以使用的按键指令:
            ? :显示在 top 当中可以输入的按键指令;
            P :以 CPU 的使用资源排序显示;
            M :以 Memory 的使用资源排序显示;
            N :以 PID 来排序喔!
            T :由该 Process 使用的 CPU 时间累积 (TIME+) 排序。
            k :给予某个 PID 一个讯号 (signal)
            r :给予某个 PID 重新制订一个 nice 值。
            q :离开 top 软件的按键。

top 默认使用 CPU 使用率 (%CPU) 作为排序的重点

  1. top 主要分为两个画面,上面的画面为整个系统的资源使用状态,基本上总共有六行,显示的内容依序是:
    1. 第一行(top...):这一行显示的信息分别为:
      1. 目前的时间,亦即是 00:53:59 那个项目;
      2. 开机到目前为止所经过的时间,亦即是 up 6:07, 那个项目;
      3. 已经登陆系统的使用者人数,亦即是 3 users, 项目;
      4. 系统在 1, 5, 15 分钟的平均工作负载。我们谈到的 batch 工作方式为 负载小于 0.8 就是这个负载!代表的是 1, 5, 15 分钟,系统平均要负责运行几个程序(工作)的意思。 越小代表系统越闲置,若高于 1 得要注意你的系统程序是否太过繁复了!
    1. 第二行(Tasks...):显示的是目前程序的总量与个别程序在什么状态(running, sleeping, stopped, zombie)。 比较需要注意的是最后的 zombie 那个数值,如果不是0 !好好看看到底是那个 process 变成僵尸了
    2. 第三行(%Cpus...):显示的是 CPU 的整体负载,每个项目可使用 ? 查阅。
      1. 需要特别注意的是 wa 项目,那个项目代表的是 I/O wait, 通常你的系统会变慢都是 I/O 产生的问题比较大!因此这里得要注意这个项目耗用 CPU 的资源!
      2. 另外,如果是多核心的设备,可以按下数字键“1”来切换成不同 CPU 的负载率
    1. 第四行与第五行:表示目前的实体内存与虚拟内存 (Mem/Swap) 的使用情况。
    2. 再次重申,要注意的是 swap 的使用量要尽量的少!如果 swap 被用的很大量,表示系统的实体内存实在不足
    3. 第六行:这个是当在 top 程序当中输入指令时,显示状态的地方。
  1. 至于 top 下半部分的画面,则是每个 process 使用的资源情况。比较需要注意的是
    1. PID :每个 process 的 ID 啦!
    2. USER:该 process 所属的使用者;
    3. PR :Priority 的简写,程序的优先执行顺序,越小越早被执行;
    4. NI :Nice 的简写,与 Priority 有关,也是越小越早被执行;
    5. %CPU:CPU 的使用率;
    6. %MEM:内存的使用率;
    7. TIME+:CPU 使用时间的累加;

3.3.4. pstree
[root@study ~]# pstree [-A|U] [-up]
  选项与参数:
    -A :各程序树之间的连接以 ASCII 字符来连接;
    -U :各程序树之间的连接以万国码的字符来连接。在某些终端接口下可能会有错误;
    -p :并同时列出每个 process 的 PID;
    -u :并同时列出每个 process 的所属帐号名称。

# 范例一:列出目前系统上面所有的程序树的相关性:
[root@study ~]# pstree -A
systemd-+-ModemManager---2*[{ModemManager}] 		# 这行是 ModenManager 与其子程序
|-NetworkManager---3*[{NetworkManager}] 				# 前面有数字,代表子程序的数量!
....(中间省略)....
|-sshd---sshd---sshd---bash---bash---sudo---su---bash---pstree 	# <==我们指令执行的相依性
....(下面省略)....
# 注意一下,为了节省版面,已经删去很多程序了!


# 范例二:承上题,同时秀出 PID 与 users
[root@study ~]# pstree -Aup
systemd(1)-+-ModemManager(745)-+-{ModemManager}(785)
| `-{ModemManager}(790)
|-NetworkManager(870)-+-{NetworkManager}(907)
| |-{NetworkManager}(911)
| `-{NetworkManager}(914)
....(中间省略)....
|-sshd(1326)---sshd(13923)---sshd(13927,dmtsai)---bash(13928)---bash(13970)---
....(下面省略)....
# 在括号 () 内的即是 PID 以及该程序的 owner 喔!一般来说,如果该程序的所有人与父程序同,
# 就不会列出,但是如果与父程序不一样,那就会列出该程序的拥有者!看上面 13927 就转变成 dmtsai 了


一般链接符号可以使用 ASCII 码即可,但有时因为语系问题会主动的以 Unicode 的符号来链接, 但
因为可能终端机无法支持该编码,或许会造成乱码问题。因此可以加上 -A 选项来克服此类线段乱码问题。

由 pstree 的输出我们也可以很清楚的知道,所有的程序都是依附在 systemd 这支程序下面的!仔细看一下,这支程序的 PID 是一号!因为他是由 Linux 核心所主动调用的第一支程序!所以 PID 就是一号了。

这也是我们刚刚提到僵尸程序时有提到,为啥发生僵尸程序需要重新开机? 因为 systemd 要重新启动,而重新启动 systemd 就是reboot

如果子程序挂点或者是老是砍不掉子程序时,该如何找到父程序吗?用这个 pstree

3.3.5. 执行优先级调整

由于 PRI 是核心动态调整的,我们使用者也无权去干涉 PRI !那如果你想要调整程序的优先执行序时,就得要通过 Nice 值了!Nice 值就是上表的 NI 啦!一般来说,PRI 与 NI 的相关性如下:

PRI(new) = PRI(old) + nice

不过你要特别留意到,如果原本的 PRI 是 50 ,并不是我们给予一个 nice = 5 ,就会让 PRI 变成 55 !因为 PRI 是系统“动态”决定的,所以,虽然 nice 值是可以影响PRI ,不过, 最终的 PRI 仍是要经过系统分析后才会决定的

另外, nice 值是有正负的

注意 :

  1. nice 值可调整的范围为 -20 ~ 19 ;
  2. root 可随意调整自己或他人程序的 Nice 值,且范围为 -20 ~ 19 ;
  3. 一般使用者仅可调整自己程序的 Nice 值,且范围仅为 0 ~ 19 (避免一般用户抢占系统资源);
  4. 一般使用者仅可将 nice 值越调越高,例如本来 nice 为 5 ,则未来仅能调整到大于 5 ;

如何给予某个程序 nice 值

  1. 一开始执行程序就立即给予一个特定的 nice 值:用 nice 指令;
  2. 调整某个已经存在的 PID 的 nice 值:用 renice 指令。

整个 nice 值是可以在父程序 --> 子程序之间传递的!父程序被修改子程序也会改变

另外,除了 renice 之外,其实那个 top 同样的也是可以调整 nice 值的!

1. nice :新执行的指令即给予新的 nice 值
  [root@study ~]# nice [-n 数字] command
      选项与参数:
      -n :后面接一个数值,数值的范围 -20 ~ 19。
  
  # 范例一:用 root 给一个 nice 值为 -5 ,用于执行 vim ,并观察该程序!
  [root@study ~]# nice -n -5 vim &
  [1] 19865
  [root@study ~]# ps -l
  F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
  4 S 0 14836 14835 0 90 10 - 29068 wait pts/0 00:00:00 bash
  4 T 0 19865 14836 0 85 5 - 37757 signal pts/0 00:00:00 vim
  0 R 0 19866 14836 0 90 10 - 30319 - pts/0 00:00:00 ps
  # 原本的 bash PRI 为 90 ,所以 vim 默认应为 90。不过由于给予 nice 为 -5 ,
  # 因此 vim 的 PRI 降低了!RPI 与 NI 各减 5 !但不一定每次都是正好相同喔!因为核心会动态调整
  [root@study ~]# kill -9 %1 				# <==测试完毕将 vim 关闭

2. renice :已存在程序的 nice 重新调整
  [root@study ~]# renice [number] PID
    选项与参数:
    PID :某个程序的 ID 啊!

  # 范例一:找出自己的 bash PID ,并将该 PID 的 nice 调整到 -5
  [root@study ~]# ps -l
  F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
  4 S 0 14836 14835 0 90 10 - 29068 wait pts/0 00:00:00 bash
  0 R 0 19900 14836 0 90 10 - 30319 - pts/0 00:00:00 ps
  [root@study ~]# renice -5 14836
  14836 (process ID) old priority 10, new priority -5
  [root@study ~]# ps -l
  F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
  4 S 0 14836 14835 0 75 -5 - 29068 wait pts/0 00:00:00 bash
  0 R 0 19910 14836 0 75 -5 - 30319 - pts/0 00:00:00 ps

由上面这个范例当中我们也看的出来,虽然修改的是 bash 那个程序,但是该程
序所触发的 ps 指令当中的 nice 也会继承而为 -5

3.4. 系统资源的观察

在测试过程中还是有读/写/执行很多的文件嘛!这些文件就会被系统暂时高速缓存下来,等待下次运行时可以更快速的取出之意!也就是说,系统是“很有效率的将所有的内存用光光”,目的是为了让系统的存取性能加速啦!

而需要注意的反而是 swap 的量。一般来说, swap 最好不要被使用,尤其 swap 最好不要被使用超过 20% 以上, 如果您发现 swap 的用量超过 20% ,那么,最好还是买实体内存来插吧!因为, Swap 的性能跟实体内存实在差多, 而系统会使用到 swap , 绝对是因为实体内存不足了才会这样做的

Linux 系统为了要加速系统性能,所以会将最常使用到的或者是最近使用到的文件数据高速缓存 (cache) 下来, 这样未来系统要使用该文件时,就直接由内存中搜寻取出,而不需要重新读取硬盘,速度上面当然就加快了! 因此,实体内存被用光是正常的!!!

3.4.1. free 观察内存
[root@study ~]# free [-b|-k|-m|-g|-h] [-t] [-s N -c N]
  选项与参数:
    -b :直接输入 free 时,显示的单位是 KBytes,我们可以使用 b(Bytes), m(MBytes)
    			k(KBytes), 及 g(GBytes) 来显示单位喔!也可以直接让系统自己指定单位 (-h)
    -t :在输出的最终结果,显示实体内存与 swap 的总量。
    -s :可以让系统每几秒钟输出一次,不间断的一直输出的意思!对于系统观察挺有效!
    -c :与 -s 同时处理~让 free 列出几次的意思~

# 范例一:显示目前系统的内存容量
[root@study ~]# free -m
			total used 	free shared buff/cache available
Mem: 	2848 	346 	1794 		8 	706 				2263
Swap: 1023 	0 		1023

3.4.2. uname:查阅系统与核心相关信息
[root@study ~]# uname [-asrmpi]
选项与参数:
    -a :所有系统相关的信息,包括下面的数据都会被列出来;
    -s :系统核心名称
    -r :核心的版本
    -m :本系统的硬件名称,例如 i686 或 x86_64 等;
    -p :CPU 的类型,与 -m 类似,只是显示的是 CPU 的类型!
    -i :硬件的平台 (ix86)

# 范例一:输出系统的基本信息
[root@study ~]# uname -a
Linux study.centos.vbird 3.10.0-229.el7.x86_64 #1 SMP Fri Mar 6 11:36:42 UTC 2015
x86_64 x86_64 x86_64 GNU/Linux

上面范例一的状态来说,我的 Linux 主机使用的核心名称为 Linux,而主机名称为 study.centos.vbird,核心的版本为 3.10.0-
229.el7.x86_64 ,该核心版本创建的日期为 2015-3-6,适用的硬件平台为 x86_64 以上等级的硬件平台喔

3.4.3. uptime:观察系统启动时间与工作负载

就是显示出目前系统已经开机多久的时间,以及 1, 5, 15 分钟的平均负载

[root@study ~]# uptime
02:35:27 up 7:48, 3 users, load average: 0.00, 0.01, 0.05

3.4.4. netstat :追踪网络或插槽档

基本上, netstat 的输出分为两大部分,分别是网络与系统自己的程序相关性部分:

[root@study ~]# netstat -[atunlp]
    选项与参数:
      -a :将目前系统上所有的连线、监听、Socket 数据都列出来
      -t :列出 tcp 网络封包的数据
      -u :列出 udp 网络封包的数据
      -n :不以程序的服务名称,以埠号 (port number) 来显示;
      -l :列出目前正在网络监听 (listen) 的服务;
      -p :列出该网络服务的程序 PID

# 范例一:列出目前系统已经创建的网络连线与 unix socket 状态
[root@study ~]# netstat
Active Internet connections (w/o servers)		# <==与网络较相关的部分
Proto 	Recv-Q	 Send-Q 	Local Address 			Foreign Address	 			State
tcp 		0 				0				 172.16.15.100:ssh 	172.16.220.234:48300 	ESTABLISHED
Active UNIX domain sockets (w/o servers)		# <==与本机的程序自己的相关性(非网络)
Proto 	RefCnt 	Flags 	Type 	State 			I-Node 	Path
unix 		2 			[ ] 		DGRAM 						1902 		@/org/freedesktop/systemd1/notify
unix 		2			  [ ]		  DGRAM 						1944 		/run/systemd/shutdownd
....(中间省略)....
unix		3 			[ ] 		STREAM CONNECTED 	25425 	@/tmp/.X11-unix/X0
unix	  3 			[ ] 		STREAM CONNECTED 	28893
unix 		3 			[ ] 		STREAM CONNECTED 	21262

我们看上面仅有一条连线的数据,他的意义是:“通过 TCP 封包的连线,远端的
172.16.220.234:48300 连线到本地端的 172.16.15.100:ssh ,这条连线状态是创建(ESTABLISHED) 的状态

在上面的结果当中,显示了两个部分,分别是网络的连线以及 linux 上面的 socket 程序相关性部分。 我们先来看看网际网络连线情况的部分:

  1. Proto :网络的封包协定,主要分为 TCP 与 UDP 封包,相关数据请参考服务器篇;
  2. Recv-Q:非由使用者程序链接到此 socket 的复制的总 Bytes 数;
  3. Send-Q:非由远端主机传送过来的 acknowledged 总 Bytes 数;
  4. Local Address :本地端的 IP:port 情况
  5. Foreign Address:远端主机的 IP:port 情况
  6. State :连线状态,主要有创建(ESTABLISED)及监听(LISTEN)
  1. 除了网络上的连线之外,其实 Linux 系统上面的程序是可以接收不同程序所发送来的信息,那就是 Linux 上头的插槽档 (socket file), 即 socket 文件
  2. socket file 可以沟通两个程序之间的信息因此程序可以取得对方传送过来的数据
  3. 由于有 socket file,因此类似 X Window 这种需要通过网络连接的软件,目前新版的 distributions 就以 socket 来进行窗口接口的连线沟通了。
  4. 上表中 socket file 的输出字段有:
    1. Proto :一般就是 unix 啦;
    2. RefCnt:连接到此 socket 的程序数量;
    3. Flags :连线的旗标;
    4. Type :socket 存取的类型。主要有确认连线的 STREAM 与不需确认的 DGRAM 两种;
    5. State :若为 CONNECTED 表示多个程序之间已经连线创建。
    6. Path :连接到此 socket 的相关程序的路径!或者是相关数据输出的路径

以上表的输出为例,最后那三行在 /tmp/.xx 下面的数据,就是 X Window 窗口接口的相关程序啦!而 PATH 指向的就是这些程序要交换数据的插槽文件

netstat 可以帮我们进行什么任务呢? 很多!我们先来看看,利用 netstat 去看看我们的哪些程序有启动哪些网络的“后门”呢?

# 范例二:找出目前系统上已在监听的网络连线及其 PID
[root@study ~]# netstat -tulnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address 	State 	PID/Program name
tcp 	0 		 0 			0.0.0.0:22 		0.0.0.0:* 				LISTEN 	1326/sshd
tcp 	0 		 0		  127.0.0.1:25 	0.0.0.0:* 				LISTEN 	2349/master
tcp6  0			 0 			:::22 				:::* 							LISTEN 	1326/sshd
tcp6  0			 0 			::1:25 				:::* 							LISTEN 	2349/master
udp 	0			 0 			0.0.0.0:123 	0.0.0.0:* 								751/chronyd
udp 	0			 0 			127.0.0.1:323 0.0.0.0:* 								751/chronyd
udp 	0			 0 			0.0.0.0:57808 0.0.0.0:* 								743/avahi-daemon: r
udp 	0			 0 			0.0.0.0:5353 	0.0.0.0:* 								743/avahi-daemon: r
udp6  0			 0 			:::123 				:::* 											751/chronyd
udp6  0			 0 			::1:323 			:::* 											751/chronyd
# 除了可以列出监听网络的接口与状态之外,最后一个字段还能够显示此服务的
# PID 号码以及程序的指令名称!例如上头的 1326 就是该 PID

# 范例三:将上述的 0.0.0.0:57808 那个网络服务关闭的话?
[root@study ~]# kill -9 743
[root@study ~]# killall -9 avahi-daemon

我的主机目前到底开了几个门(ports)!其实,不论主机提供什么样的服务, 一定必须要有相对应的 program 在主机上面执行才行啊! 举例来说,我们鸟园的 Linux 主机提供的就是 WWW 服务,那么我的主机当然有一个程序在提供 WWW 的服务!那就是 Apache 这个软件所提供的! 如何关闭啊? 就关掉该程序所触发的那个程序就好了!

3.4.5. dmesg :分析核心产生的讯息

系统在开机的时候,核心会去侦测系统的硬件,你的某些硬件到底有没有被捉到,那就与这个时候的侦测有关。 但是这些侦测的过程要不是没有显示在屏幕上,就是很飞快的在屏幕上一闪而逝!能不能把核心侦测的讯息捉出来瞧瞧? 可以的,那就使用 dmesg 吧!

所有核心侦测的讯息,不管是开机时候还是系统运行过程中,反正只要是核心产生的讯息,都会被记录到内存中的某个保护区段。 dmesg 这个指令就能够将该区段的讯息读出来的!因为讯息实在太多了,所以执行时可以加入这个管线指令“ | more ”来使画面暂停

# 范例一:输出所有的核心开机时的信息
[root@study ~]# dmesg | more
# 范例二:搜寻开机的时候,硬盘的相关信息为何?
[root@study ~]# dmesg | grep -i vda
[ 0.758551] vda: vda1 vda2 vda3 vda4 vda5 vda6 vda7 vda8 vda9
[ 3.964134] XFS (vda2): Mounting V4 Filesystem
....(下面省略)....
3.4.6. vmstat :侦测系统资源变化

如果你想要动态的了解一下系统资源的运行,那么这个 vmstat 确实可以玩一玩!

vmstat 可以侦测“ CPU / 内存 / 磁盘输入输出状态 ”等等,如果你想要了解一部繁忙的系统到底是哪个环节最累人, 可以使用 vmstat 分析看看。下面是常见的选项与参数说明

[root@study ~]# vmstat [-a] [延迟 [总计侦测次数]] 			<==CPU/内存等信息
[root@study ~]# vmstat [-fs] 													<==内存相关
[root@study ~]# vmstat [-S 单位] 											<==设置显示数据的单位
[root@study ~]# vmstat [-d] 													<==与磁盘有关
[root@study ~]# vmstat [-p 分区] 											<==与磁盘有关
    选项与参数:
        -a :使用 inactive/active(活跃与否) 取代 buffer/cache 的内存输出信息;
        -f :开机到目前为止,系统复制 (fork) 的程序数;
        -s :将一些事件 (开机至目前为止) 导致的内存变化情况列表说明;
        -S :后面可以接单位,让显示的数据有单位。例如 K/M 取代 Bytes 的容量;
        -d :列出磁盘的读写总量统计表
        -p :后面列出分区,可显示该分区的读写总量统计表


范例一:统计目前主机 CPU 状态,每秒一次,共计三次!
[root@study ~]# vmstat 1 3
procs ------------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 1838092 1504 722216 0 0 4 1 6 9 0 0 100 0 0
0 0 0 1838092 1504 722200 0 0 0 0 13 23 0 0 100 0 0
0 0 0 1838092 1504 722200 0 0 0 0 25 46 0 0 100 0 0

4. 特殊文件与程序

曾经谈到特殊权限的 SUID/SGID/SBIT ,到底这些权限对于你的“程序”是如何影响的? 此外,程序可能会使用到系统资源,举例来说,磁盘就是其中一项资源。哪天你在 umount 磁盘时,系统老是出现“ device is busy ”的字样~到底是怎么回事

4.1. 具有 SUID/SGID 权限的指令执行状态

SUID 的权限其实与程序的相关性非常的大!为什么呢?先来看看 SUID 的程序是如何被一般使用者执行,且具有什么特色呢?

  1. SUID 权限仅对二进制程序(binary program)有效;
  2. 执行者对于该程序需要具有 x 的可执行权限;
  3. 本权限仅在执行该程序的过程中有效 (run-time);
  4. 执行者将具有该程序拥有者 (owner) 的权限。

所以说,整个 SUID 的权限会生效是由于“具有该权限的程序被触发”,而我们知道一个程序被触发会变成程序, 所以啰,执行者可以具有程序拥有者的权限就是在该程序变成程序的那个时

举个例子 : 为啥执行了 passwd 后你就具有 root 的权限呢?不都是一般使用者执行的吗? 这是因为你在触发 passwd 后,会取得一个新的程序与 PID,该 PID 产生时通过SUID 来给予该 PID 特殊的权限设置啦!我们使用 dmtsai 登陆系统且执行 passwd 后,通过工作控制来理解一下!

从上表的结果我们可以发现,底线的部分是属于 dmtsai 这个一般帐号的权限,特殊字体的则是 root 的权限!

但你看到了, passwd 确实是由 bash 衍生出来的!不过就是权限不一样!通过这样的解析,你也会比较清楚为何不同程序所产生的权限不同了吧!这是由于“SUID 程序运行过程中产生的程序”的关系

那么既然 SUID/SGID 的权限是比较可怕的,该如何查询整个系统的SUID/SGID 的文件呢?使用 find 即可!

find / -perm /6000

4.2. /proc/* 代表的意义

我们之前提到的所谓的程序都是在内存当中嘛!而内存当中的数据又都是写入到 /proc/* 这个目录下的,我们当然可以直接观察 /proc 这个目录当中的文件

/proc 这个目录的话,应该会发现他有点像这样:

基本上,目前主机上面的各个程序的 PID 都是以目录的型态存在于 /proc 当中

举例来说,我们开机所执行的第一支程序 systemd 他的 PID 是 1 , 这个 PID 的所有相关信息都写入在 /proc/1/* 当中!若我们直接观察 PID 为 1 的数据好了

[root@study ~]# ll /proc/1
dr-xr-xr-x. 2 root root 0 Aug 4 19:25 attr
-rw-r--r--. 1 root root 0 Aug 4 19:25 autogroup
-r--------. 1 root root 0 Aug 4 19:25 auxv
-r--r--r--. 1 root root 0 Aug 4 18:46 cgroup
--w-------. 1 root root 0 Aug 4 19:25 clear_refs
-r--r--r--. 1 root root 0 Aug 4 18:46 cmdline 			# <== 就是指令串,这个程序被启动的指令串;
-r--------. 1 root root 0 Aug 4 18:46 environ 			# <== 一些环境变量
lrwxrwxrwx. 1 root root 0 Aug 4 18:46 exe
....(以下省略)....

[root@study ~]# cat /proc/1/cmdline
/usr/lib/systemd/systemd--switched-root--system--deserialize24
就是这个指令、选项与参数启动 systemd 的啦!这还是跟某个特定的 PID 有关的内容

针对整个 Linux 系统相关的参数呢?那就是在 /proc 目录下面的文件啦!相关的文件与对应的内容是这样的:

4.3. 查询已打开文件或已执行程序打开的文件

fuser:借由文件(或文件系统)找出正在使用该文件的程序

有的时候我想要知道我的程序到底在这次启动过程中打开了多少文件,可以利用fuser 来观察啦!

举例来说,你如果卸载时发现系统通知:“ device is busy ”,那表示这个文件系统正在忙碌中, 表示有某支程序有利用到该文件系统啦!那么你就可以利用fuser 来追踪啰!fuser 语法有点像这样:

[root@study ~]# fuser [-umv] [-k [i] [-signal]] file/dir
选项与参数:
  -u :除了程序的 PID 之外,同时列出该程序的拥有者;
  -m :后面接的那个文件名会主动的上提到该文件系统的最顶层,对 umount 不成功很有效!
  -v :可以列出每个文件与程序还有指令的完整相关性!
  -k :找出使用该文件/目录的 PID ,并试图以 SIGKILL 这个讯号给予该 PID;
  -i :必须与 -k 配合,在删除 PID 之前会先询问使用者意愿!
  -signal:例如 -1 -15 等等,若不加的话,默认是 SIGKILL (-9) 啰!

# 范例一:找出目前所在目录的使用 PID/所属帐号/权限 为何?
[root@study ~]# fuser -uv .
				USER PID 	 ACCESS COMMAND
/root:  root 13888 ..c.. (root)bash
				root 31743 ..c.. (root)bash

看到输出的结果没?他说“.”下面有两个 PID 分别为 13888, 31743 的程序,该程序属于 root 且指令为 bash 。 比较有趣的是那个 ACCESS 的项目,那个项目代表的意义为:

c :此程序在当前的目录下(非次目录);

e :可被触发为执行状态;

f :是一个被打开的文件;

r :代表顶层目录 (

root directory);

F :该文件被打开了,不过在等待回应中;

m :可能为分享的动态函数库;

那如果你想要查阅某个文件系统下面有多少程序正在占用该文件系统时,那个 - m 的选项就很有帮助了!

让我们来做几个简单的测试,包括实体的文件系统挂载与 /proc 这个虚拟文件系统的内容, 看看有多少的程序对这些挂载点或其他目录的使用状态吧!

通过这个 fuser 我们可以找出使用该文件、目录的程序,借以观察的啦!他的重点与 ps, pstree 不同。 fuser 可以让我们了解到某个文件(或文件系统) 目前正在被哪些程序所利用

4.4. lsof :列出被程序所打开的文件文件名

相对于 fuser 是由文件或者设备去找出使用该文件或设备的程序,

反过来说,如何查出某个程序打开或者使用的文件与设备呢, 就是lsof

[root@study ~]# lsof [-aUu] [+d]
    选项与参数:
    -a :多项数据需要“同时成立”才显示出结果时!
    -U :仅列出 Unix like 系统的 socket 文件类型;
    -u :后面接 username,列出该使用者相关程序所打开的文件;
    +d :后面接目录,亦即找出某个目录下面已经被打开的文件!
    范例一:列出目前系统上面所有已经被打开的文件与设备:
[root@study ~]# lsof
COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root cwd DIR 253,0 4096 128 /
systemd 1 root rtd DIR 253,0 4096 128 /
systemd 1 root txt REG 253,0 1230920 967763 /usr/lib/systemd/systemd
....(下面省略)....
# 注意到了吗?是的,在默认的情况下, lsof 会将目前系统上面已经打开的
# 文件全部列出来~所以,画面多的吓人啊!您可以注意到,第一个文件 systemd 执行的
# 地方就在根目录,而根目录,嘿嘿!所在的 inode 也有显示出来喔!


范例二:仅列出关于 root 的所有程序打开的 socket 文件
[root@study ~]# lsof -u root -a -U
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root 3u unix 0xffff8800b7756580 0t0 13715 socket
systemd 1 root 7u unix 0xffff8800b7755a40 0t0 1902 @/org/freedesktop/systemd1/notify
systemd 1 root 9u unix 0xffff8800b7756d00 0t0 1903 /run/systemd/private
.....(中间省略).....
Xorg 4496 root 1u unix 0xffff8800ab107480 0t0 25981 @/tmp/.X11-unix/X0
Xorg 4496 root 3u unix 0xffff8800ab107840 0t0 25982 /tmp/.X11-unix/X0
Xorg 4496 root 16u unix 0xffff8800b7754f00 0t0 25174 @/tmp/.X11-unix/X0
.....(下面省略).....
# 注意到那个 -a 吧!如果你分别输入 lsof -u root 及 lsof -U ,会有啥信息?
# 使用 lsof -u root -U 及 lsof -u root -a -U ,呵呵!都不同啦!
# -a 的用途就是在解决同时需要两个项目都成立时啊! ^_^
范例三:请列出目前系统上面所有的被启动的周边设备
[root@study ~]# lsof +d /dev
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
systemd 1 root 0u CHR 1,3 0t0 1028 /dev/null
systemd 1 root 1u CHR 1,3 0t0 1028 /dev/null
# 看吧!因为设备都在 /dev 里面嘛!所以啰,使用搜寻目录即可啊!
范例四:秀出属于 root 的 bash 这支程序所打开的文件
[root@study ~]# lsof -u root | grep bash
ksmtuned 781 root txt REG 253,0 960384 33867220 /usr/bin/bash
bash 13888 root cwd DIR 253,0 4096 50331777 /root
bash 13888 root rtd DIR 253,0 4096 128 /
bash 13888 root txt REG 253,0 960384 33867220 /usr/bin/bash
bash 13888 root mem REG 253,0 106065056 17331169 /usr/lib/locale/locale-archive
....(下面省略)

4.5. pidof :找出某支正在执行的程序的 PID

[root@study ~]# pidof [-sx] program_name
  选项与参数:
  -s :仅列出一个 PID 而不列出所有的 PID
  -x :同时列出该 program name 可能的 PPID 那个程序的 PID

# 范例一:列出目前系统上面 systemd 以及 rsyslogd 这两个程序的 PID
[root@study ~]# pidof systemd rsyslogd
1 742
# 理论上,应该会有两个 PID 才对。上面的显示也是出现了两个 PID 喔。
# 分别是 systemd 及 rsyslogd 这两支程序的 PID 啦。

通过这个 pidof 指令,并且配合 ps aux 与正则表达式,就可以很轻易的找到您所想要的程序内容了
如果要找的是 bash ,那就 pidof bash ,立刻列出一堆 PID 号码了

5. 系统服务daemons

5.1. 什么是 daemon 与服务 (service)

系统为了某些功能必须要提供一些服务 (不论是系统本身还是网络方面),这个服务就称为 service 。 但是 service 的提供总是需要程序的运行吧!否则如何执行呢?所以达成这个 service 的程序我们就称呼他为 daemon

不必去区分什么是 daemon 与 service !事实上,你可以将这两者视为相同!因为达成某个服务是需要一支 daemon 在背景中运行, 没有这支 daemon就不会有 service !

从 CentOS 7.x 这一版之后,传统的 init 已经被舍弃,取而代之的是 systemd

5.2. daemon 的主要分类

从 CentOS 7.x 以后,Red Hat 系列的 distribution 放弃沿用多年的 System V 开机启动服务的流程,就是 init 启动脚本的方法, 改用 systemd 这个启动服务管理机制

systemd 有什么好处?

  1. 平行处理所有服务,加速开机流程: 旧的 init 启动脚本是“一项一项任务依序启动”的模式,因此不相依的服务也是得要 一个一个的等待。但目前我们的硬件主机系统与操作系统几乎都支持多核心架构 了, 没道理未相依的服务不能同时启动啊!systemd 就是可以让所有的服务同时启动,因此你会发现到,系统启动的速度变快了!
  2. 一经要求就回应的 on-demand 启动方式: systemd 全部就是仅有一只 systemd 服务搭配 systemctl 指令来处理,无须其他额外 的指令来支持。不像 systemV 还要 init, chkconfig, service... 等等指令。 此外, systemd 由于常驻内存,因此任何要求 (on-demand) 都可以立即处理后续的 daemon 启动的任务。
  3. 服务相依性的自我检查: 由于 systemd 可以自订服务相依性的检查,因此如果 B 服务是架构在 A 服务上面启 动的,那当你在没有启动 A 服务的情况下仅手动启动 B 服务时, systemd 会自动帮你启动 A 服务喔!这样就可以免去管理员得要一项一项服务去分析的麻烦~(如果读者不是新手,应该会有印象,当你没有启动网络, 但却启动 NIS/NFS 时,那个开机时的 timeout 甚至可达到 10~30 分钟...)
  4. 依 daemon 功能分类: systemd 旗下管理的服务非常多,包山包海啦~为了厘清所有服务的功能,因此,首先 systemd 先定义所有的服务为一个服务单位 (unit),并将该 unit 归类到不同的服务类型 (type) 去。 旧的 init 仅分为 stand alone 与 super daemon 实在不够看,systemd 将服务单位 (unit) 区分为 service, socket, target, path, snapshot, timer 等多种不同的类型(type), 方便管理员的分类与记忆。
  5. 将多个 daemons 集合成为一个群组: 如同 systemV 的 init 里头有个 runlevel 的特色,systemd 亦将许多的功能集合成为一 个所谓的 target 项目,这个项目主要在设计操作环境的创建, 所以是集合了许多的 daemons,亦即是执行某个 target 就是执行好多个 daemon 的意思!
  6. 向下相容旧有的 init 服务脚本:基本上, systemd 是可以相容于 init 的启动脚本的,因此,旧的 init 启动脚本也能够通过 systemd 来管理,只是更进阶的 systemd 功能就没有办法支持就是了。

虽然如此,不过 systemd 也是有些地方无法完全取代 init 的!包括:

  1. 在 runlevel 的对应上,大概仅有 runlevel 1, 3, 5 有对应到 systemd 的某些 target 类型而已,没有全部对应;
  2. 全部的 systemd 都用 systemctl 这个管理程序管理,而 systemctl 支持的语法有限制,不像 /etc/init.d/daemon 就是纯脚本可以自订参数,systemctl 不可自订参数。;
  3. 如果某个服务启动是管理员自己手动执行启动,而不是使用 systemctl 去启动的(例如你自己手动输入 crond 以启动 crond 服务),那么 systemd 将无法侦测到该服务,而无法进一步管理。
  4. systemd 启动过程中,无法与管理员通过 standard input 传入讯息!因此,自行撰写systemd 的启动设置时,务必要取消互动机制~(连通过启动时传进的标准输入讯息也要避免!)

5.2.1. systemd 的配置文件放置目录

基本上, systemd 将过去所谓的 daemon 执行脚本通通称为一个服务单位(unit),而每种服务单位依据功能来区分时,就分类为不同的类型 (type)。

基本的类型有包括系统服务、数据监听与交换的插槽档服务 (socket)、储存系统状态的快照 类型、提供不同类似执行等级分类的操作环境 (target) 等等

配置文件都放置在下面的目录中:

  1. /usr/lib/systemd/system/:每个服务最主要的启动脚本设置,有点类似以前的 /etc/init.d 下面的文件;
  2. /run/systemd/system/:系统执行过程中所产生的服务脚本,这些脚本的优先序要比 /usr/lib/systemd/system/ 高!
  3. /etc/systemd/system/:管理员依据主机系统的需求所创建的执行脚本,其实这个目录有点像以前 /etc/rc.d/rc5.d/Sxx 之类的功能!执行优先序又比 /run/systemd/system/ 高喔!

到底系统开机会不会执行某些服务其实是看 /etc/systemd/system/ 下面的设置,所以该目录下面就是一大堆链接文件。而实际执行的 systemd 启动脚本配置文件, 其实都是放置在 /usr/lib/systemd/system/ 下面的

5.2.2. systemd 的 unit 类型分类说明

那 /usr/lib/systemd/system/ 以下的数据如何区分上述所谓的不同的类型 (type) 呢?看扩展名!举例来说,我们来瞧瞧上一章谈到的 vsftpd 这个范例的启动脚本设置, 还有 crond 与纯文本模式的 multi-user 设置:

vsftpd 与 crond 其实算是系统服务 (service),而 multi-user 要算是执行环境相关的类型 (target type)。

几种比较常见的 systemd 的服务类型如下

5.3. 通过 systemctl 管理服务

systemd 这个启动服务的机制,主要是通过一只名为 systemctl 的指令来处理的!跟以前 systemV 需要 service / chkconfig / setup / init 等指令来协助不同, systemd就是仅有 systemctl 这个指令来处理而已

5.3.1. systemctl 管理单一服务(service unit)的启动/开机启动与观察状态
[root@study ~]# systemctl [command] [unit]
    command 主要有:
      start :立刻启动后面接的 unit
      stop :立刻关闭后面接的 unit
      restart :立刻关闭后启动后面接的 unit,亦即执行 stop 再 start 的意思
      reload :不关闭后面接的 unit 的情况下,重新载入配置文件,让设置生效
      enable :设置下次开机时,后面接的 unit 会被启动
      disable :设置下次开机时,后面接的 unit 不会被启动
      status :目前后面接的这个 unit 的状态,会列出有没有正在执行、开机默认执行否、登录等信息等!
      is-active :目前有没有正在运行中
      is-enable :开机时有没有默认要启用这个 unit


# 范例一:看看目前 atd 这个服务的状态为何?
[root@study ~]# systemctl status atd.service
atd.service - Job spooling tools
	Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled)
	Active: active (running) since Mon 2015-08-10 19:17:09 CST; 5h 42min ago
Main PID: 1350 (atd)
	CGroup: /system.slice/atd.service
					└─1350 /usr/sbin/atd -f
Aug 10 19:17:09 study.centos.vbird systemd[1]: Started Job spooling tools.
# 重点在第二、三行喔~
# Loaded:这行在说明,开机的时候这个 unit 会不会启动,enabled 为开机启动,disabled 开机不会启动
# Active:现在这个 unit 的状态是正在执行 (running) 或没有执行 (dead)
# 后面几行则是说明这个 unit 程序的 PID 状态以及最后一行显示这个服务的登录文件信息!
# 登录文件信息格式为:“时间” “讯息发送主机” “哪一个服务的讯息” “实际讯息内容”
# 所以上面的显示讯息是:这个 atd 默认开机就启动,而且现在正在运行的意思!

# 范例二:正常关闭这个 atd 服务
[root@study ~]# systemctl stop atd.service
[root@study ~]# systemctl status atd.service
atd.service - Job spooling tools
	Loaded: loaded (/usr/lib/systemd/system/atd.service; enabled)
	Active: inactive (dead) since Tue 2015-08-11 01:04:55 CST; 4s ago
Process: 1350 ExecStart=/usr/sbin/atd -f $OPTS (code=exited, status=0/SUCCESS)
Main PID: 1350 (code=exited, status=0/SUCCESS)
Aug 10 19:17:09 study.centos.vbird systemd[1]: Started Job spooling tools.
Aug 11 01:04:55 study.centos.vbird systemd[1]: Stopping Job spooling tools...
Aug 11 01:04:55 study.centos.vbird systemd[1]: Stopped Job spooling tools.
# 目前这个 unit 下次开机还是会启动,但是现在是没在运行的状态中!同时,
# 最后两行为新增加的登录讯息,告诉我们目前的系统状态喔!

  1. 上面关掉了 atd 的方式是对的!不应该使用 kill 的方式来关掉一个正常的服务否则 systemctl 会无法继续监控该服务的!那就比较麻烦。而使用 systemtctl status atd 的输出结果中,
  2. 第 2, 3 两行很重要~因为那个是告知我们该 unit 下次开机会不会默认启动,以及目前启动的状态!最下面是这个unit 的登录文件~如果你的这个 unit 曾经出错过,观察这个地方也是相当重要的!

基本上有几个常见的状态:

  1. active (running):正有一只或多只程序正在系统中执行的意思,举例来说,正在执行中的 vsftpd 就是这种模式。
  2. active (exited):仅执行一次就正常结束的服务目前并没有任何程序在系统中执行
    1. 举例来说,开机或者是挂载时才会进行一次的 quotaon 功能,就是这种模式!quotaon 不须一直执行~只须执行一次之后,就交给文件系统去自行处理啰!通常用 bash shell 写的小型服务,大多是属于这种类型(无须常驻内存)。
  1. active (waiting):正在执行当中,不过还再等待其他的事件才能继续处理。
    1. 举例来说,打印的伫列相关服务就是这种状态!虽然正在启动中,不过,也需要真的有伫列进来 (打印工作) 这样他才会继续唤醒打印机服务来进行下一步打印的功能。
  1. inactive:这个服务目前没有运行的意思。

既然 daemon 目前的状态就有这么多种了,那么 daemon 的默认状态有没有可能除了 enable/disable 之外,还有其他的情况呢?当然有!

  1. enabled:这个 daemon 将在开机时被执行
  2. disabled:这个 daemon 在开机时不会被执行
  3. static:这个 daemon 不可以自己启动 (enable 不可),不过可能会被其他的 enabled 的服务来唤醒 (相依属性的服务)
  4. mask:这个 daemon 无论如何都无法被启动!因为已经被强制注销 (非删除)。可通过 systemctl unmask 方式改回原本状态

练习

找到系统中名为 chronyd 的服务,观察此服务的状态 systemctl status chronyd.service , .service结尾

# 1. 先看看 cups 的服务是开还是关?
[root@study ~]# systemctl status cups.service
cups.service - CUPS Printing Service
	Loaded: loaded (/usr/lib/systemd/system/cups.service; enabled)
	Active: inactive (dead) since Tue 2015-08-11 19:19:20 CST; 3h 29min ago
# 竟然是 enable 但是却是 inactive 相当特别!
# 2. 那就直接关闭,同时确认没有启动喔!
[root@study ~]# systemctl stop cups.service
[root@study ~]# systemctl disable cups.service
rm '/etc/systemd/system/multi-user.target.wants/cups.path'
rm '/etc/systemd/system/sockets.target.wants/cups.socket'
rm '/etc/systemd/system/printer.target.wants/cups.service'
# 也是非常特别!竟然一口气取消掉三个链接文件!也就是说,这三个文件可能是有相依性的问题!

[root@study ~]# netstat -tlunp | grep cups
# 现在应该不会出现任何数据!因为根本没有 cups 的任务在执行当中~所以不会有 port 产生

# 3. 尝试启动 cups.socket 监听用户端的需求喔!
[root@study ~]# systemctl start cups.socket
[root@study ~]# systemctl status cups.service cups.socket cups.path
cups.service - CUPS Printing Service
	Loaded: loaded (/usr/lib/systemd/system/cups.service; disabled)
	Active: inactive (dead) since Tue 2015-08-11 22:57:50 CST; 3min 41s ago
cups.socket - CUPS Printing Service Sockets
	Loaded: loaded (/usr/lib/systemd/system/cups.socket; disabled)
	Active: active (listening) since Tue 2015-08-11 22:56:14 CST; 5min ago
cups.path - CUPS Printer Service Spool
	Loaded: loaded (/usr/lib/systemd/system/cups.path; disabled)
	Active: inactive (dead)
# 确定仅有 cups.socket 在启动,其他的并没有启动的状态!

# 4. 尝试使用 lp 这个指令来打印看看?
[root@study ~]# echo "testing" | lp
lp: Error - no default destination available. # 实际上就是没有打印机!所以有错误也没关系!
[root@study ~]# systemctl status cups.service
cups.service - CUPS Printing Service
	Loaded: loaded (/usr/lib/systemd/system/cups.service; disabled)
	Active: active (running) since Tue 2015-08-11 23:03:18 CST; 34s ago
[root@study ~]# netstat -tlunp | grep cups
tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 25881/cupsd
tcp6 0 0 ::1:631 :::* LISTEN 25881/cupsd
# 见鬼!竟然 cups 自动被启动了!明明我们都没有驱动他啊!怎么回事啊?

  1. 很多服务彼此之间是有相依性的!cups 是一种打印服务,这个打印服务会启用 port 631 来提供网络打印机的打印功能。
  2. 但是其实我们无须一直启动 631 端口吧?因此,多了一个名为 cups.socket 的服务,这个服务可以在“用户有需要打印时,才会主动唤醒 cups.service ”的意思!
  3. 因此,如果你仅是 disable/stop cups.service 而忘记了其他两个服务的话,那么当有用户向其他两个 cups.path, cups.socket 提出要求时, cups.service 就会被唤醒!所以,你关掉也没用

强迫服务注销 (mask) 的练习

比较正规的作法是,要关闭 cups.service 时,连同其他两个会唤醒 service 的 cups.socket 与 cups.path 通通关闭,那就没事了! 比较不正规的作法是,那就强迫 cups.service 注销吧!通过 mask 的方式来将这个服务注销看看!

[root@study ~]# systemctl stop cups.service
[root@study ~]# systemctl mask cups.service
ln -s '/dev/null' '/etc/systemd/system/cups.service'
# 其实这个 mask 注销的动作,只是让启动的脚本变成空的设备而已!
[root@study ~]# systemctl status cups.service
cups.service
	Loaded: masked (/dev/null)
	Active: inactive (dead) since Tue 2015-08-11 23:14:16 CST; 52s ago

[root@study ~]# systemctl start cups.service
Failed to issue method call: Unit cups.service is masked. # 再也无法唤醒!

来整个启动的脚本配置文件被链接到/dev/null 这个空设备

取消注销呢?当然就是 unmask

[root@study ~]# systemctl unmask cups.service
rm '/etc/systemd/system/cups.service'
[root@study ~]# systemctl status cups.service
cups.service - CUPS Printing Service
	Loaded: loaded (/usr/lib/systemd/system/cups.service; disabled)
	Active: inactive (dead) since Tue 2015-08-11 23:14:16 CST; 4min 35s ago
# 好在有恢复正常
5.3.2. 通过 systemctl 观察系统上所有的服务
[root@study ~]# systemctl [command] [--type=TYPE] [--all]
  command:
      list-units :			# 依据 unit 列出目前有启动的 unit。若加上 --all 才会列出没启动的。
      list-unit-files :# 依据 /usr/lib/systemd/system/ 内的文件,将所有文件列表说明。
  --type=TYPE:					# 就是之前提到的 unit type,主要有 service, socket, target 等


# 范例一:列出系统上面有启动的 unit
[root@study ~]# systemctl			# 默认就是 list-units 的意思!
UNIT 											LOAD 		ACTIVE SUB 		DESCRIPTION
proc-sys-fs-binfmt_mis... loaded active waiting Arbitrary Executable File Formats File System
sys-devices-pc...:0:1:... loaded active plugged QEMU_HARDDISK
sys-devices-pc...0:1-0... loaded active plugged QEMU_HARDDISK
sys-devices-pc...0:0-1... loaded active plugged QEMU_DVD-ROM
.....(中间省略).....
vsftpd.service loaded active running Vsftpd ftp daemon
.....(中间省略).....
cups.socket loaded failed failed CUPS Printing Service Sockets
.....(中间省略).....
LOAD = Reflects whether the unit definition was properly loaded.
ACTIVE = The high-level unit activation state, i.e. generalization of SUB.
SUB = The low-level unit activation state, values depend on unit type.
141 loaded units listed. Pass --all to see loaded but inactive units, too.
To show all installed unit files use 'systemctl list-unit-files'.
# 列出的项目中,主要的意义是:
# UNIT :项目的名称,包括各个 unit 的类别 (看扩展名)
# LOAD :开机时是否会被载入,默认 systemctl 显示的是有载入的项目而已喔!
# ACTIVE :目前的状态,须与后续的 SUB 搭配!就是我们用 systemctl status 观察时,active 的项目!
# DESCRIPTION :详细描述啰
# cups 比较有趣,因为刚刚被我们玩过,所以 ACTIVE 竟然是 failed 的喔!被玩死了!
# 另外,systemctl 都不加参数,其实默认就是 list-units 的意思!

# 范例二:列出所有已经安装的 unit 有哪些?
[root@study ~]# systemctl list-unit-files
UNIT FILE 														STATE
proc-sys-fs-binfmt_misc.automount 		static
dev-hugepages.mount 									static
dev-mqueue.mount 											static
proc-fs-nfsd.mount 										static
.....(中间省略).....
systemd-tmpfiles-clean.timer 					static
336 unit files listed.

STATE 状态就是前谈到的开机是否会载入的那个状态项目!主要有 enabled / disabled / mask / static
[root@study ~]# systemctl list-units --type=service --all
# 只剩下 *.service 的项目才会出现喔!

# 范例一:查询系统上是否有以 cpu 为名的服务?
[root@study ~]# systemctl list-units --type=service --all | grep cpu
cpupower.service loaded inactive dead Configure CPU power related settings
# 确实有喔!可以改变 CPU 电源管理机制的服务哩!

5.3.3. systemctl 配置文件相关目录简介
  1. 服务的管理是通过 systemd,而 systemd 的配置文件大部分放置于 /usr/lib/systemd/system/ 目录内,
  2. 但是 Red Hat 官方文件指出, 该目录的文件主要是原本软件所提供的设置,建议不要修改!而要修改的位置应该放置于 /etc/systemd/system/ 目录内 ;

举例来说,如果你想要额外修改 vsftpd.service 的话, 他们建议要放置到哪些地方呢?

  1. /usr/lib/systemd/system/vsftpd.service:官方释出的默认配置文件;
  2. /etc/systemd/system/vsftpd.service.d/custom.conf:
    1. 在 /etc/systemd/system 下面创建与配置文件相同文件名目录,但是要加上 .d 的扩展名。
    2. 然后在该目录下创建配置文件即可。另外,配置文件最好附文件名取名为 .conf 较佳!
    3. 在这个目录下的文件会“累加其他设置”进入 /usr/lib/systemd/system/vsftpd.service 内!
  1. /etc/systemd/system/vsftpd.service.wants/*:此目录内的文件为链接文件,设置相依服务的链接。
    1. 意思是启动了 vsftpd.service 之后,最好再加上这目录下面建议的服务。
  1. /etc/systemd/system/vsftpd.service.requires/*:此目录内的文件为链接文件,设置相依服务的链接。
    1. 意思是在启动 vsftpd.service 之前,需要事先启动哪些服务的意思。

5.3.4. systemctl 配置文件的设置项目简介

了解一下配置文件本身的内容!让我们先来瞧一瞧 sshd.service 的内容好了

[root@study ~]# cat /usr/lib/systemd/system/sshd.service
[Unit] # 这个项目与此 unit 的解释、执行服务相依性有关
Description=OpenSSH server daemon
After=network.target sshd-keygen.service
Wants=sshd-keygen.service
[Service] # 这个项目与实际执行的指令参数有关
EnvironmentFile=/etc/sysconfig/sshd
ExecStart=/usr/sbin/sshd -D $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=42s
[Install] # 这个项目说明此 unit 要挂载哪个 target 下面
WantedBy=multi-user.target

大概能够将整个设置分为三个部份,就是:
[Unit]: unit 本身的说明,以及与其他相依 daemon 的设置,包括在什么服务之后才启动此 unit 之类的设置值;
[Service], [Socket], [Timer], [Mount], [Path]... :不同的 unit type 就得要使用相对应的设
				置项目。我们拿的是 sshd.service 来当范本,所以这边就使用 [Service] 来设置。
				这个项目内主要在规范服务启动的脚本、环境配置文件文件名、重新启动的方式等等。
[Install]:这个项目就是将此 unit 安装到哪个 target 里面去的意思!

配置文件内有些设置规则 :

  1. 设置项目通常是可以重复的,例如我可以重复设置两个 After 在配置文件中,不过,后面的设置会取代前面的!因此,如果你想要将设置值归零, 可以使用类似“ After= ”的设置,亦即该项目的等号后面什么都没有,就将该设置归零了(reset)。
  2. 如果设置参数需要有“是/否”的项目(布尔值, boolean),你可以使用 1, yes, true, on 代表启动,用 0, no, false, off 代表关闭!随你喜好选择!
  3. 空白行、开头为 # 或 ; 的那一行,都代表注解!

示例

vsftpd 服务因为某些原因,所以你可能需要使用到两个端口,分别是正常的 21 以及特殊的 555 !

这两个 port 都启用的情况下,你可能就得要使用到两个配置文件以及两个启动脚本设置 :

  1. 默认的 port 21:使用 /etc/vsftpd/vsftpd.conf 配置文件,以及/usr/lib/systemd/system/vsftpd.service 设置脚本;
  2. 特殊的 port 555:使用 /etc/vsftpd/vsftpd2.conf 配置文件,以及 /etc/systemd/system/vsftpd2.service 设置脚本。
# 1. 先创建好所需要的配置文件
[root@study ~]# cd /etc/vsftpd
[root@study vsftpd]# cp vsftpd.conf vsftpd2.conf
[root@study vsftpd]# vim vsftpd.conf
#listen_port=555
[root@study vsftpd]# diff vsftpd.conf vsftpd2.conf
128c128
< #listen_port=555
---
> listen_port=555
# 注意这两个配置文件的差别喔!只有这一行不同而已!

# 2. 开始处理启动脚本设置
[root@study vsftpd]# cd /etc/systemd/system
[root@study system]# cp /usr/lib/systemd/system/vsftpd.service vsftpd2.service
[root@study system]# vim vsftpd2.service
[Unit]
Description=Vsftpd second ftp daemon
After=network.target
[Service]
Type=forking
ExecStart=/usr/sbin/vsftpd /etc/vsftpd/vsftpd2.conf
[Install]
WantedBy=multi-user.target
# 重点在改了 vsftpd2.conf 这个配置文件喔!

# 3. 重新载入 systemd 的脚本配置文件内容
[root@study system]# systemctl daemon-reload
[root@study system]# systemctl list-unit-files --all | grep vsftpd
vsftpd.service enabled
vsftpd2.service disabled
vsftpd@.service disabled
vsftpd.target disabled
[root@study system]# systemctl status vsftpd2.service
vsftpd2.service - Vsftpd second ftp daemon
Loaded: loaded (/etc/systemd/system/vsftpd2.service; disabled)
Active: inactive (dead)

[root@study system]# systemctl restart vsftpd.service vsftpd2.service
[root@study system]# systemctl enable vsftpd.service vsftpd2.service
[root@study system]# systemctl status vsftpd.service vsftpd2.service
vsftpd.service - Vsftpd ftp daemon
	Loaded: loaded (/usr/lib/systemd/system/vsftpd.service; enabled)
	Active: active (running) since Wed 2015-08-12 22:00:17 CST; 35s ago
Main PID: 12670 (vsftpd)
	CGroup: /system.slice/vsftpd.service
					└─12670 /usr/sbin/vsftpd /etc/vsftpd/vsftpd.conf
Aug 12 22:00:17 study.centos.vbird systemd[1]: Started Vsftpd ftp daemon.
vsftpd2.service - Vsftpd second ftp daemon
	Loaded: loaded (/etc/systemd/system/vsftpd2.service; enabled)
	Active: active (running) since Wed 2015-08-12 22:00:17 CST; 35s ago
Main PID: 12672 (vsftpd)
	CGroup: /system.slice/vsftpd2.service
					└─12672 /usr/sbin/vsftpd /etc/vsftpd/vsftpd2.conf
[root@study system]# netstat -tlnp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1340/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 2387/master
tcp6 0 0 :::555 :::* LISTEN 12672/vsftpd
tcp6 0 0 :::21 :::* LISTEN 12670/vsftpd
tcp6 0 0 :::22 :::* LISTEN 1340/sshd
tcp6 0 0 ::1:25 :::* LISTEN 2387/master

以上很简单的将你的 systemd 所管理的 vsftpd 做了另一个服务

5.3.5. 使用Systemd管理应用进程

Systemd是Linux系统的一个进程管理器,可以将应用进程作为Systemd服务运行。首先创建一个myproject.service文件,例如:

[Unit]
Description=My Project
[Service]
User=username
ExecStart=/usr/bin/java -jar /path/to/myproject.jar
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target

其中,username是Linux服务器的用户名,/path/to/myproject.jar是应用jar包的路径。 然后将myproject.service文件复制到/etc/systemd/system目录下,并使用以下命令启动Systemd服务:

plaintextCopy code
sudo systemctl start myproject

这将启动应用进程,并作为Systemd服务运行。你可以使用以下命令查看服务状态:

plaintextCopy code
sudo systemctl status myproject

如果应用进程意外关闭,Systemd会自动重启进程。你可以使用以下命令停止Systemd服务:

plaintextCopy code
sudo systemctl stop myproject

示例

来仿真自己作一个服务!假设我要作一只可以备份自己系统的服务,这只脚本我放在 /backups 下面,内容有点像这样:

[root@study ~]# vim /backups/backup.sh
#!/bin/bash
source="/etc /home /root /var/lib /var/spool/{cron,at,mail}"
target="/backups/backup-system-$(date +%Y-%m-%d).tar.gz"
[ ! -d /backups ] && mkdir /backups
tar -zcvf ${target} ${source} &> /backups/backup.log
[root@study ~]# chmod a+x /backups/backup.sh
[root@study ~]# ll /backups/backup.sh
-rwxr-xr-x. 1 root root 220 Aug 13 01:57 /backups/backup.sh
# 记得要有可执行的权限才可以喔!


# 设计一只名为 backup.service 的启动脚本设置
[root@study ~]# vim /etc/systemd/system/backup.service
[Unit]
Description=backup my server
Requires=atd.service
[Service]
Type=simple
ExecStart=/bin/bash -c " echo /backups/backup.sh | at now"
[Install]
WantedBy=multi-user.target
# 因为 ExecStart 里面有用到 at 这个指令,因此, atd.service 就是一定要的服务!
[root@study ~]# systemctl daemon-reload
[root@study ~]# systemctl start backup.service
[root@study ~]# systemctl status backup.service
backup.service - backup my server
Loaded: loaded (/etc/systemd/system/backup.service; disabled)
Active: inactive (dead)
Aug 13 07:50:31 study.centos.vbird systemd[1]: Starting backup my server...
Aug 13 07:50:31 study.centos.vbird bash[20490]: job 8 at Thu Aug 13 07:50:00 2015
Aug 13 07:50:31 study.centos.vbird systemd[1]: Started backup my server.
# 为什么 Active 是 inactive 呢?这是因为我们的服务仅是一个简单的 script 啊!
# 因此执行完毕就完毕了,不会继续存在内存中喔!

5.3.6. 以系统服务启动说明

步骤:
1. 创建服务文件,以 .service 结尾, 一般是在/etc/systemd/system/ 目录下,也可以放在其它目录
2. 编写服务文件
3. 重新加载Systemd配置,使新的服务文件生效
  systemctl daemon-reload
4. 设置开机自启动
  systemctl enable zookeeper && systemctl enable kafka
5. 启动服务,查看状态
  systemctl start zookeeper && systemctl start kafka
  systemctl status zookeeper && systemctl status kafka
[Unit]
Requires=network.target
After=network.target
[Service]
Type=simple
LimitNOFILE=1048576
ExecStart=/usr/local/kafka/bin/zookeeper-server-start.sh /usr/local/kafka/config/zookeeper.properties
ExecStop=/usr/local/kafka/bin/zookeeper-server-stop.sh
Restart=Always
[Install]
WantedBy=multi-user.target

说明:


[Unit]是Systemd服务文件中的一个节(section),它用于定义服务单元(unit)的元数据和配置信息。
在[Unit]节下可以包含多个字段,这些字段对于服务的管理和控制非常重要。
下面是一些常见字段的解释和作用:
- Description:描述字段,用于提供对服务的简要描述。
- After:依赖字段,指定服务启动的顺序。在指定的目标(target)或服务启动之后,才会启动当前服务。
- Requires:依赖字段,指定服务的强制依赖关系。如果被依赖的服务未启动,当前服务将无法启动。
- Wants:依赖字段,指定服务的非强制依赖关系。如果被依赖的服务未启动,当前服务仍然可以启动。
- Before:依赖字段,指定服务启动的顺序。在指定的目标(target)或服务启动之前,当前服务将先启动。
- After/Wants/Requires/Before等字段可以指定其他服务、目标或者特定的Systemd单元。
[Unit]节中的字段可以根据实际需要进行配置,用于控制服务的启动顺序、依赖关系和描述信息等。这些配置信息对于服务的管理和运行非常重要,可以确保服务按照正确的顺序和条件进行启动和停止。


[Service]是Systemd服务文件中的一个节(section),用于定义服务的运行参数和行为。
在[Service]节下可以包含多个属性字段,这些字段对于服务的管理和配置非常重要。
下面是一些常见的属性字段及其说明:
- ExecStart:指定服务的启动命令,可以是一个可执行文件的路径或者一个命令行。例如: `ExecStart=/usr/bin/my_service` 
- Restart:定义服务在异常退出时的重启策略。常见的取值包括 `always` (总是重启)、 `on-failure` (仅在非正常退出时重启)和 `no` (不重启)。
- RestartSec:定义服务重启之间的等待时间,单位为秒。例如: `RestartSec=5s` 表示在服务异常退出后等待5秒再进行重启。
- User:指定服务运行的用户。可以是用户名或者用户ID。例如: `User=myuser` 。
- Group:指定服务运行的组。可以是组名或者组ID。例如: `Group=mygroup` 。
- WorkingDirectory:指定服务的工作目录,即服务启动时所在的目录。例如: `WorkingDirectory=/path/to/my_service` 。
- Environment:定义服务的环境变量。可以使用多个Environment字段来设置多个环境变量。例如: `Environment=VAR1=value1` 。
- ExecReload:定义服务的重新加载命令。当执行 `systemctl reload my_service` 时,将会运行该命令。
- ExecStop:定义服务的停止命令。当执行 `systemctl stop my_service` 时,将会运行该命令。
以上是一些常用的[Service]节下的属性字段,可以根据具体需求进行配置和扩展。这些属性字段可以控制服务的运行参数、启动行为和环境设置,确保服务按照预期的方式进行管理和运行。


[Install]是Systemd服务文件中的一个节(section),用于定义服务的安装和启动方式。
在[Install]节下可以包含多个属性字段,这些字段对于服务的安装和启动非常重要。
下面是一些常见的属性字段及其说明:
- WantedBy:指定服务所依赖的目标(target)。当目标被激活时,服务将会自动启动。例如: `WantedBy=multi-user.target` 。
- RequiredBy:指定服务所必需的目标。只有当目标被激活时,服务才能启动。例如: `RequiredBy=network.target` 。
- Alias:为服务定义一个别名,可以通过别名来启动或停止服务。例如: `Alias=my_service` 。
以上是一些常用的[Install]节下的属性字段,用于定义服务的安装和启动方式。通过指定服务所依赖的目标和定义别名,可以方便地管理和控制服务的启动和停止。

5.3.7. systemctl 针对 timer 的配置文件(定时启动服务)

某些服务你想要定期执行,或者是开机后执行,或者是什么服务启动多久后执行等等的。

在过去,我们大概都是使用 crond 这个服务来定期处理, 不过,既然现在有一直常驻在内存当中的 systemd ,加上这 systemd 有个协力服务,名为 timers.target 的家伙,这家伙可以协助定期处理各种任务

  1. 优点 :
    1. 由于所有的 systemd 的服务产生的信息都会被纪录 (log),因此比 crond 在 debug 上面要更清楚方便的多;
    2. 各项 timer 的工作可以跟 systemd 的服务相结合;
    3. 各项 timer 的工作可以跟 control group (cgroup,用来取代 /etc/secure/limit.conf 的功 能)结合,来限制该工作的资源利用
  1. 缺点:
    1. systemd 的 timer 并没有 email 通知的功能 (除非自己写一个),
    2. 也没有类似 anacron 的一段时间内的随机取样功能 (random_delay)

基本上,想要使用 systemd 的 timer 功能,你必须要有几个要件:

  1. 系统的 timer.target 一定要启动
  2. 要有个 sname.service 的服务存在 (sname 是你自己指定的名称)
  3. 要有个 sname.timer 的时间启动服务存在

6. 软件安装: 源代码与Tarball

6.1. 编译器与可执行文件

6.1.1. 二进制文件

Linux 系统上真正认识的可执行文件其实是二进制文件( binary program),例如 /usr/bin/passwd, /bin/touch 这些个文件即为二进制程序码。

shell scripts 不是也可以执行吗?其实 shell scripts 只是利用 shell (例如 bash) 这支程序的功能进行一些判断式,而最终执行的除了 bash 提供的功能外,仍是调用一些已经编译好的二进制程序来执行的

# 先以系统的文件测试看看:
[root@study ~]# file /bin/bash
/bin/bash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked
(uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=0x7e60e35005254...stripped
# 如果是系统提供的 /etc/init.d/network 呢?
[root@study ~]# file /etc/init.d/network
/etc/init.d/network: Bourne-Again shell script, ASCII text executable

binary 而且是可以执行的时候,他就会显示可执行文件类别(ELF 64-bit LSB executable), 同时会说明是否使用动态函数库 (shared libs),而如果是一般的 script ,那他就会显示出 text executables 之类的字样!

事实上,network 的数据显示出 Bourne-Again ... 那一行,是因为你的 scripts上面第一行有宣告 #!/bin/bash 的缘故,如果你将 script 的第一行拿掉,那么不管 /etc/init.d/network 的权限为何,他其实显示的是 ASCII 文本文件的信息!

如何写二进制程序 ?

首先,我们必须要写程序,使用 vim 来进行程序的撰写,写完的程序就是所谓的原始程序码!这个程序码文件其实就是一般的纯文本文件。再来就是要将这个文件“编译”成为操作系统看的懂得 binary program ,经过编译器的编译与链接之后,就会产生一支可以执行的 binary program

用外部函数 :

有的时候,我们会在程序当中“引用、调用” 其他的外部副程序,或者是利用其他软件提供的“函数功能”,这个时候,我们就必须要编译的过程当中, 将该函数库给他加进去,如此一来,编译器就可以将所有的程序码与函数库作一个链接 (Link) 以产生正确的可执行文件 .

6.1.2. 函数库

分为动态与静态函数库 ;

函数库 : 类似副程序的角色 , 可以被调来执行的一段功能函数 ;

Linux 的核心提供很多的核心相关函数库与外部参数, 这些核心功能在设计硬件的驱动程序的时候是相当有用的信息,这些核心相关信息大多放置在 /usr/include, /usr/lib, /usr/lib64 里面

6.2. make 与 configure

  1. 使用类似gcc的编译器来进行编译的过程并不简单 , 因为一套软件并不会仅有一支程序, 而是一堆程序码文件 ; 所以除了每个主程序与副程序均需要写上一笔编译过程的指令外, 还需要写上最终的链接程序 .
  2. 如果程序码有数百MB的数据量,编译指令会写到疯掉 , 这时候就可以使用make 指令进行编译功能的指令简化 !
  3. make是一支程序 , 会去找 Makefile , Makefile 怎末写?
    1. 通常软件开发商都会写一支侦测程序来侦测使用者的作业环境 , 以及该作业环境是否有软件开发商所需要的其他功能 , 该侦测程序侦测完毕后, 就会主动创建这个Makefile 的规则文件 ;
    2. 通常这个侦测程序的文件名为 configure 或 config
  1. 那为什么要侦测作业环境呢?不是曾经提过其实每个 Linux distribution 都使用同样的核心吗?
    1. 但你得要注意, 不同版本的核心所使用的系统调用可能不相同,而且每个软件所需要的相依的函数库也不相同, 同时,软件开发商不会仅针对 Linux 开发,而是会针对整个 Unix-Like 做开发
    2. 所以他也必须要侦测该操作系统平台有没有提供合适的编译器才行 , 所以当然要侦测环境
  1. 侦测程序会侦测的数据 :
    1. 是否有合适的编译器
    2. 是否已存在本软件所需的函数库 ,或其他相依赖软件
    3. 操作系统平台是否合适本软件 , 包括Linux核心版本
    4. 核心的表头定义文件(header include) 是否存在 (驱动程序必须要的侦测)

make 与 configure 运行流程的相关性 你要进行的任务其实只有两个:

  1. 执行configure来创建Makefile ,这个步骤一定要成功
  2. 成功之后再以 make 调用所需的数据来编译即可

6.3. 什么是Tarball的软件

  1. 文本文件在网络上其实是很浪费带宽的一种文件格式!所以,如果能够将这些源代码通过文件的打包与压缩技术来将文件的数量与容量减小, 不但让使用者容易下载,软件开发商的网站带宽也能够节省很多很多啊!这就是 Tarball 文件的由来 .
  2. Tarball 的意思就是包 , 所谓的 Tarball 文件,其实就是将软件的所有源代码文件先以 tar 打包,然后再以压缩技术来压缩,通常最常见的就是以 gzip 来压缩了。
    1. 因为利用了 tar 与 gzip 的功能,所以 tarball 文件一般的扩展名就会写成 *.tar.gz 或者是简写为 *.tgz ;
    2. 由于近来bzip2 与 xz 的压缩率较佳,所以 Tarball 渐渐的以 bzip2 及 xz 的压缩技术来取代 gzip ,因此文件名也会变成 *.tar.bz2, *.tar.xz 之类
  1. 所以说 ,Tarball 是一个软件包, 你将他解压缩之后,里面的文件通常就会有
    1. 原始程序吗文件
    2. 侦测程序文件 (可能是configure 或 config等文件名)
    3. 本软件的简易说明与安装说明 (INSTALL 或 README)
6.3.1. 安装与升级软件

更新方法 :

  1. 直接以源代码通过编译来安装与升级 :
    1. 就是直接以 Tarball 在自己的机器上面进行侦测、编译、 安装与设置等等动作来升级 : 安装过程中有很高的弹性, 但是比较麻烦
  1. 直接以编译好的binary program 来安装与升级 , 预编译好程序的机制存在于衡多distribution
    1. 包括 Red Hat系统(含Fedora/CentOS系统) 发展的RPM软件管理机制与yum线上更新模式 ; Debian使用的dpkg软件管理机制与APT线上更新模式
    2. CentOS系统是依循标椎的Linux distribution, 所以可以使用Tarball直接进行编译的安装与升级 ;

一个软件的Tarball是如何安装的 ? 基本流程如下 :

  1. 将Tarball 由厂商网页下载下来 ;
  2. 将Tarball解开 , 产生很多源代码文件
  3. 开始以gcc进行源代码编译(会产生目标文件object files) ;
  4. 然后以gcc进行函数库、主、副程序的链接 , 以形成主要的binary file ;
  5. 将上述的binary file 以及相关的配置文件安装至自己的主机上面 ;

上面第 3,4步骤可以使用 make 指令简化

6.3.2. 传统语言进行编译的范例

如果尚未安装 gcc 的话,请先参考 RPM 安装法 。 如果你已经有网络了,那么直接使用“ yum groupinstall "Development Tools" ” 预先安装好所需的所有软件即可

[root@study ~]# vim hello.c 		# <==用 C 语言写的程序扩展名建议用 .c
#include <stdio.h>
int main(void)
{
	printf("Hello World\n");
}

[root@study ~]# gcc hello.c
[root@study ~]# ll hello.c a.out
-rwxr-xr-x. 1 root root 8503 Sep 4 11:33 a.out <==此时会产生这个文件名
-rw-r--r--. 1 root root 71 Sep 4 11:32 hello.c
[root@study ~]# ./a.out
Hello World 				# <==成果出现了!

在默认的状态下,如果我们直接以 gcc 编译源代码,并且没有加上任何参数,则
可执行文件的文件名会被自动设置为 a.out 这个文件名称! 所以你就能够直接执行./a.out 这个可执行文件
a.out 就是编译成功的可执行 binary program

如果想要产生目标文件(object file)来进行其他的动作 ,而且可执行文件的文件名也不要用默认的 a.out ,可以将上面第2个步骤改成这样:

gcc -c hello.c
ll hello.*
-rw-r--r--. 1 root root 71 Sep 4 11:32 hello.c
-rw-r--r--. 1 root root 1496 Sep 4 11:34 hello.o		# <==就是被产生的目标文件

gcc -o hello hello.o
ll hello*
-rwxr-xr-x. 1 root root 8503 Sep 4 11:35 hello 	# <==这就是可可执行文件! -o 的结果
-rw-r--r--. 1 root root 71 Sep 4 11:32 hello.c
-rw-r--r--. 1 root root 1496 Sep 4 11:34 hello.o

./hello
Hello World   # 输出结果

这个步骤主要是利用 hello.o 这个目标文件制作出一个名为 hello 的可执行文件

通过这个动作后,我们可以得到 hello及 hello.o 两个文件,真正可以执行的是 hello这个 binary program !
或许觉得只要一个动作作出 a.out 就好了,干嘛还要先制作目标文件再做成可执行文件呢?
6.3.3. 主、副程序链接 :副程序的编译

如果我们在一个主程序里又调用了另一个副程序呢 ?这是很常见的一个程序写法 , 因为可以简化整个程序的易读性!

下面中我们以 thanks.c 这个程序去调用 thanks_2.c这个副程序 ,如下:

vim thanks.c

#include <stdio.h>
int main(void)
{
printf("Hello World\n");
thanks_2();
}
# 上面的 thanks_2(); 那一行就是调用副程序啦!

vim thanks_2.c

#include <stdio.h>
void thanks_2(void)
{
printf("Thank you!\n");
}

# 2. 开始将源代码编译成为可执行的 binary file :
[root@study ~]# gcc -c thanks.c thanks_2.c
[root@study ~]# ll thanks*
-rw-r--r--. 1 root root 75 Sep 4 11:43 thanks_2.c
-rw-r--r--. 1 root root 1496 Sep 4 11:43 thanks_2.o		 # <==编译产生的!
-rw-r--r--. 1 root root 91 Sep 4 11:42 thanks.c
-rw-r--r--. 1 root root 1560 Sep 4 11:43 thanks.o 		 # <==编译产生的!
[root@study ~]# gcc -o thanks thanks.o thanks_2.o
[root@study ~]# ll thanks*
-rwxr-xr-x. 1 root root 8572 Sep 4 11:44 thanks 			# <==最终结果会产生这玩意儿
# 3. 执行一下这个文件:
[root@study ~]# ./thanks
Hello World
Thank you!

  1. 知道为什么要制作出目标文件了吗?
    1. 由于我们的源代码文件有时并非仅只有一个文件,所以我们无法直接进行编译。 这个时候就需要先产生目标文件,然后再以链接制作成为 binary 可执行文件。
    2. 另外 ,如果有一天,你更新了 thanks_2.c 这个文件的内容,则你只要重新编译 thanks_2.c 来产生新的 thanks_2.o , 然后再以链接制作出新的binary 可执行文件即可!而不必重新编译其他没有更动过的源代码文件

如果你想要让程序在执行的时候具有比较好的性能,或者是其他的除错功能时, 可以在编译的过程里面加入适当的参数,例如下面的例子:

[root@study ~]# gcc -O -c thanks.c thanks_2.c				#  <== -O 为产生最优化的参数
[root@study ~]# gcc -Wall -c thanks.c thanks_2.c
thanks.c: In function ‘main’:
thanks.c:5:9: warning: implicit declaration of function ‘thanks_2’ [-Wimplicit-function-declaration]
thanks_2();
^
thanks.c:6:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
# -Wall 为产生更详细的编译过程信息。上面的讯息为警告讯息 (warning) 所以不用理会也没有关系

至于更多的 gcc 额外参数功能,就得要 man gcc, 参数非常多

6.3.4. 调用外部函数库:加入链接的函数库

想要计算出三角函数里面的 sin (90度角):
# 要注意的是,大多数的程序语言都是使用径度而不是一般我们在计算的“角度”, 180 度角约等于 3.14 径度
[root@study ~]# vim sin.c
#include <stdio.h>
#include <math.h>
int main(void)
{
float value;
value = sin ( 3.14 / 2 );
printf("%f\n",value);
}

[root@study ~]# gcc sin.c
# 新的 GCC 会主动将函数抓进来给你用,所以只要加上 include <math.h> 就好了!
  1. 新版的 GCC 会主动帮你将所需要的函数库抓进来编译,所以不会出现怪异的错误讯息!
  2. 事实上,数学函数库使用的是 libm.so 这个函数库,你最好在编译的时候将这个函数库纳进去比较好~
  3. 另外要注意, 这个函数库放置的地方是系统默认会去找的 /lib, /lib64 ,所以你无须使用下面的 -L 去加入搜寻的目录! 而 libm.so 在编译的写法上,使用的是 -lm (lib 简写为 l 喔!)

特别注意,使用 gcc 编译时所加入的那个 -lm 是有意义的,他可以拆开成两部份来看:

  1. -l : 是"加入某个函数库(library)" 的意思
  2. m : 是 libm.so这个函数库, 其中 lib 与扩展名 (.a 或 .so)不需要写

所以 -lm 表示使用 libm.so (或 libm.a) 这个函数库的意思~至于那个 -L后面接的路径呢?这表示: “我要的函数库 libm.so 请到 /lib 或 /lib64 里面搜寻!”

要注意的是,由于 Linux 默认是将函数库放置在 /lib 与 /lib64 当中,所以你没有写 -L/lib 与 -L/lib64 也没有关系的!不过,万一哪天你使用的函数库并非放置在这两个目录下,那么 -L/path 就很重要了!否则会找不到函数库

[root@study ~]# gcc sin.c -lm -L/lib -L/lib64			# <==重点在 -lm
[root@study ~]# ./a.out														# <==尝试执行新文件!
1.000000

sin.c 当中第一行“ #include <stdio.h>”,这行说的是要将一些定义数据由 stdio.h 这个文件读入,这包括 printf 的相关设置。这个文件其实是放置在 /usr/include/stdio.h 的

那么万一这个文件并非放置在这里呢?那么我们就可以使用下面的方式来定义出要读取的 include 文件放置的目录 :

gcc sin.c -lm -I/usr/include

6.3.5. gcc的简易用法
# 仅将源代码编译成为目标文件,并不制作链接等功能:
[root@study ~]# gcc -c hello.c
# 会自动的产生 hello.o 这个文件,但是并不会产生 binary 可执行文件。
# 在编译的时候,依据作业环境给予最优化执行速度
[root@study ~]# gcc -O hello.c -c
# 会自动的产生 hello.o 这个文件,并且进行最优化喔!
# 在进行 binary file 制作时,将链接的函数库与相关的路径填入
[root@study ~]# gcc sin.c -lm -L/lib -I/usr/include
# 这个指令较常下达在最终链接成 binary file 的时候,
# -lm 指的是 libm.so 或 libm.a 这个函数库文件;
# -L 后面接的路径是刚刚上面那个函数库的搜寻目录;
# -I 后面接的是源代码内的 include 文件之所在目录。
# 将编译的结果输出成某个特定文件名
[root@study ~]# gcc -o hello hello.c
# -o 后面接的是要输出的 binary file 文件名
# 在编译的时候,输出较多的讯息说明
[root@study ~]# gcc -o hello hello.c -Wall
# 加入 -Wall 之后,程序的编译会变的较为严谨一点,所以警告讯息也会显示出来!

比较重要的大概就是这一些。另外,我们通常称 -Wall 或者 -O 这些非必要的参数为旗标 (FLAGS),
因为我们使用的是 C 程序语言,所以有时候也会简称这些旗标为 CFLAGS ,这些变量偶尔会被使用的喔!
尤其是在后头会介绍的 make 相关的用法时,更是重要的很呐

6.3.6. make进行宏编译

假设我的可执行文件里面包含了四个源代码文件,分别是 main.c haha.c sin_value.c cos_value.c 这四个文件
# 1. 先进行目标文件的编译,最终会有四个 *.o 的文件名出现:
[root@study ~]# gcc -c main.c
[root@study ~]# gcc -c haha.c
[root@study ~]# gcc -c sin_value.c
[root@study ~]# gcc -c cos_value.c
# 2. 再进行链接成为可执行文件,并加入 libm 的数学函数,以产生 main 可执行文件:
[root@study ~]# gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 3. 本程序的执行结果,必须输入姓名、360 度角的角度值来计算:
[root@study ~]# ./main
Please input your name: VBird <==这里先输入名字
Please enter the degree angle (ex> 90): 30 <==输入以 360 度角为主的角度
Hi, Dear VBird, nice to meet you. <==这三行为输出的结果喔!
The Sin is: 0.50
The Cos is: 0.87

现在这个目录下创建一个名为 makefile 的文件 ,内容如下 :

# 1. 先编辑 makefile 这个规则档,内容只要作出 main 这个可执行文件
[root@study ~]# vim makefile
main: main.o haha.o sin_value.o cos_value.o
				gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 注意:第二行的 gcc 之前是 <tab> 按键产生的空格喔!
# 2. 尝试使用 makefile 制订的规则进行编译的行为:
[root@study ~]# rm -f main *.o 				# <==先将之前的目标文件去除
[root@study ~]# make
cc 		-c -o main.o main.c
cc 		-c -o haha.o haha.c
cc 		-c -o sin_value.o sin_value.c
cc 		-c -o cos_value.o cos_value.c
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 此时 make 会去读取 makefile 的内容,并根据内容直接去给他编译相关的文件!
# 3. 在不删除任何文件的情况下,重新执行一次编译的动作:
[root@study ~]# make
make: `main' is up to date.
# 看到了吧!是否很方便呢!只会进行更新 (update) 的动作而已


或许你认为:“如果我创建一个 shell script 来将上面的所有动作都集结在一起,不是具有同样的效果吗?
效果当然不一样,以上面的测试为例,我们仅写出main 需要的目标文件,结果 make 会主动的去判断每个目标文件
相关的源代码文件,并直接予以编译,最后再直接进行链接的动作

如果我们更动过某些源代码文件,则 make 也可以主动的判断哪一个源代码与相关的目标文件文件有更新过并仅更新该文件,如此一来,将可大大的节省很多编译的时间 .

make 有这些好处:

  1. 简化编译时所需要下达的指令;
  2. 若在编译完成之后,修改了某个源代码文件,则 make 仅会针对被修改了的文件进行编译,其他的 object file 不会被更动;
  3. 最后可以依照相依性来更新 (update) 可执行文件

6.3.7. makefile 的基本语法与变量
# 语法
标的(target) : 目标文件1 目标文件2
<tab>		gcc -o 欲创建的可执行文件 目标文件1 目标文件2

# 变量语法
1. 变量与变量内容以“=”隔开,同时两边可以具有空格;
2. 变量左边不可以有 <tab> ;
3. 变量与变量内容在“=”两边不能具有“:”;
4. 在习惯上,变量最好是以“大写字母”为主;
5. 运用变量时,以 ${变量} 或 $(变量) 使用;
6. 在该 shell 的环境变量是可以被套用的,例如提到的 CFLAGS 这个变量!
7. 在命令行界面也可以给予变量

环境变量取用的规则是这样的:
1. make 命令行后面加上的环境变量为优先;
2. makefile 里面指定的环境变量第二;
3. shell 原本具有的环境变量第三

此外,还有一些特殊的变量需要了解的:
$@:代表目前的标的(target)

# *************************************示例*********************************** #

[root@study ~]# vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
main: ${OBJS}
gcc -o main ${OBJS} ${LIBS}
clean:
rm -f main ${OBJS}

由于 gcc 在进行编译的行为时,会主动的去读取 CFLAGS 这个环境变量,所以,
你可以直接在 shell 定义出这个环境变量,也可以在 makefile 文件里面去定义,更可以
在命令行当中给予

[root@study ~]# CFLAGS="-Wall" make clean main
# 这个动作在上 make 进行编译时,会去取用 CFLAGS 的变量内容!
或者
[root@study ~]# vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
CFLAGS = -Wall
main: ${OBJS}
gcc -o main ${OBJS} ${LIBS}
clean:
rm -f main ${OBJS}

[root@study ~]# vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
CFLAGS = -Wall
main: ${OBJS}
gcc -o $@ ${OBJS} ${LIBS}			#  <==那个 $@ 就是 main !
clean:
rm -f main ${OBJS}

那个标的 (target) 就是我们想要创建的信息,而目标文件就是具有相关性的 object files ,那创建可执行文件的语法就是以 <tab> 按键开头的那一行!特别给他留意,“命令列必须要以 tab 按键作为开头”才行!他的规则基本上是这样的:

  1. 在 makefile 当中的 # 代表注解;
  2. <tab> 需要在命令行 (例如 gcc这个编译器指令) 的第一个字符 ;
  3. 标的(target ) 与相依文件(就是目标文件) 之间需以 " : "隔开

# *******************************示例*************************** #
# 如果我想要有两个以上的执行动作时,例如下达一个指令就直接清除掉所有的目标文件与可执行文件
# 1. 先编辑 makefile 来创建新的规则,此规则的标的名称为 clean :
vim makefile
main: main.o haha.o sin_value.o cos_value.o
      	gcc -o main mian.o haha.o sin_value.o cos_value.o -lm
clean:
      	rm -f main mian.o haha.o sin_value.o cos_value.o 
# 2. 以新的标的 (clean) 测试看看执行 make 的结果
[root@study ~]# make clean 								# <==就是这里!通过 make 以 clean 为标的
rm -rf main main.o haha.o sin_value.o cos_value.o

如此一来,我们的 makefile 里面就具有至少两个标的,分别是 main 与 clean
而如果想要先清除目标文件再编译 main 这个程序的话,就可以这样输入:“make clean main”

[root@study ~]# make clean main
rm -rf main main.o haha.o sin_value.o cos_value.o
cc -c -o main.o main.c
cc -c -o haha.o haha.c
cc -c -o sin_value.o sin_value.c
cc -c -o cos_value.o cos_value.c
gcc -o main main.o haha.o sin_value.o cos_value.o -lm

6.4. Tarball的管理与安装的指令

整个安装的基础动作大多是这样的:

  1. 取得原始文件:将 tarball 文件在 /usr/local/src 目录下解压缩;
  2. 取得步骤流程:进入新创建的目录下面,去查阅 INSTALL与 README 等相关文件内容 (很重要的步骤!);
  3. 相依属性软件安装:根据 INSTALL/README 的内容察看并安装好一些相依的软件(非必要);
  4. 创建 makefile:以自动侦测程序 (configure 或 config) 侦测作业环境,并创建Makefile 这个文件;
  5. 编译:以 make 这个程序并使用该目录下的 Makefile 做为他的参数配置文件,来进行 make (编译或其他) 的动作;
  6. 安装:以 make 这个程序,并以 Makefile 这个参数配置文件,依据 install 这个标的(target) 的指定来安装到正确的路径!

大部分的 tarball 软件之安装的指令下达方式:

  1. ./configure
    1. 这个步骤就是在创建 Makefile 这个文件啰!通常程序开发者会写一支 scripts 来检查你的 Linux 系统、相关的软件属性等等,这个步骤相当的重要, 因为未来你的安装信息都是这一步骤内完成的!
    2. 另外,这个步骤的相关信息应该要参考一下该目下的 README 或 INSTALL相关的文件!
  1. make clean
    1. make 会读取 Makefile 中关于 clean 的工作。
    2. 这个步骤不一定会有,但是希望执行一下,因为他可以去除目标文件!因为谁也不确定源代码里面到底有没有包含上次编译过的目标文件 (*.o) 存在,所以当然还是清除一下比较妥当的。 至少等一下新编译出来的可执行文件我们可以确定是使用自己的机器所编译完成的嘛!
  1. make
    1. make 会依据 Makefile 当中的默认工作进行编译的行为!
    2. 编译的工作主要是进行 gcc来将源代码编译成为可以被执行的 object files ,但是这些 object files 通常还需要一些函数库之类的 link 后,才能产生一个完整的可执行文件!使用 make 就是要将源代码编译成为可以被执行的可执行文件,而这个可执行文件会放置在目前所在的目录之下, 尚未被安装到预定安装的目录中
  1. make install
    1. 通常这就是最后的安装步骤了,make 会依据 Makefile 这个文件里面关于 install 的项目,将上一个步骤所编译完成的数据给他安装到预定的目录中,就完成安装

其中只要一个步骤无法成功,那么后续的步骤就完全没有办法进行的

如果安装成功, 并且是安装在独立的一个目录中,例如 /usr/local/packages 这个目录中好了,那么你就必需手动的将这个软件的 man page 给他写入 /etc/man_db.conf 里面去

6.5. 一般 Tarball 软件安装的建议事项 (如何移除?升级?)

为什么前一个小节里面, Tarball 要在 /usr/local/src 里面解压缩呢

  1. 在默认的情况下,原本的 Linux distribution 释出安装的软件大多是在 /usr 里面的,而使用者自行安装的软件则建议放置在 /usr/local 里 , 而源代码和安装软件区分开就放到了src下
  2. 我们晓得几乎每个软件都会提供线上说明的服务,那就是 info 与 man 的功能。在默认的情况下, man 会去搜寻 /usr/local/man 里面的说明文档, 因此,如果我们将软件安装在 /usr/local 下面的话,那么自然安装完成之后, 该软件的说明文档就可以被找到了

6.5.1. Linux distribution 默认的安装软件的路径
  1. 让我们先来看一看 Linux distribution 默认的安装软件的路径会用到哪些?我们以 apache 这个软件来说明:

/etc/httpd

/usr/lib

/usr/bin

/usr/share/man

发现软件的内容大致上是摆在 etc, lib, bin, man 等目录当中,分别代表“配置文件、函数库、可执行文件、线上说明文档”。

  1. 那么你是以 tarball 来安装时呢?如果是放在默认的 /usr/local 里面,由于 /usr/local 原本就默认这几个目录了,所以你的数据就会被放在:

/usr/local/etc

/usr/local/bin

/usr/local/lib

/usr/local/man

但是如果你每个软件都选择在这个默认的路径下安装的话, 那么所有的软件的文件都将放置在这四个目录当中,因此,如果你都安装在这个目录下的话, 那么未来再想要升级或移除的时候,就会比较难以追查文件的来源;

  1. 而如果你在安装的时候选择的是单独的目录,例如我将 apache 安装在 /usr/local/apache 当中,那么你的文件目录就会变成:

/usr/local/apache/etc

/usr/local/apache/bin

/usr/local/apache/lib

/usr/local/apache/man

单一软件的文件都在同一个目录之下,那么要移除该软件就简单的多了!只要将该目录移除即可视为该软件已经被移除 ; rm -rf /usr/local/apache

实际安装的时候还是得视该软件的 Makefile 里头的 install 信息才能知道到底他的安装情况为何的。因为例如sendmail 的安装就很麻烦 ;

这个方式虽然有利于软件的移除,但我们在执行某些指令的时候,与该指令是否在 PATH 这个环境变量所记录的路径有关,以上面为例, /usr/local/apache/bin 肯定是不在 PATH 里面的,所以执行 apache 的指令就得要利用绝对路径了,否则就得将这个 /usr/local/apache/bin 加入 PATH 里面。另外,那个 /usr/local/apache/man 也需要加入 man page 搜寻的路径当中 !

除此之外, Tarball 在升级的时候也是挺困扰的,怎么说呢?我们还是以 apache 来说明。WWW 服务器为了考虑互动性,所以通常会将 PHP+MySQL+Apache 一起安装起来 ,果真如此的话,那么每个软件在安装的时候“都有一定的顺序与程序!” 因为他们三者之间具有相关性,所以安装时必需要三者同时考虑到他们的函数库与相关的编译参数。

假设今天我只要升级 PHP 呢?有的时候因为只有涉及动态函数库的升级,那么我只要升级 PHP 即可!其他的部分或许影响不大。但是如果今天 PHP 需要重新编译的模块比较多,那么可能会连带的,连 Apache 这个程序也需要重新编译过才行!真是有点给他头痛的!

没办法由于 Tarball 在升级与安装上面具有这些特色,亦即 Tarball 在反安装上面具有比较高的难度 (如果你没有好好规划的话~),所以,为了方便 Tarball 的管理,建议使用者:

  1. 最好将 tarball 的原始数据解压缩到 /usr/local/src 当中;
  2. 安装时,最好安装到 /usr/local 这个默认路径下;
  3. 考虑未来的反安装步骤,最好可以将每个软件单独的安装在 /usr/local 下面;
  4. 为安装到单独目录的软件之 man page 加入 man path 搜寻:
    1. 如果你安装的软件放置到 /usr/local/software/ ,那么 man page 搜寻的设置中,可能就得要在 /etc/man_db.conf 内的 40~50 行左右处,写入如下的一行:MANPATH_MAP /usr/local/software/bin /usr/local/software/man , 这样才可以使用 man 来查询该软件的线上文件

时至今日,老实说,真的不太需要有 tarball 的安装了!CentOS/Fedora 有个RPM 补遗计划,就是俗称的 EPEL 计划,相关网址说明如下:Extra Packages for Enterprise Linux (EPEL) :: Fedora Docs, 一般学界会用到的软件都在里头~ 除非你要用的软件是专属软件 (要钱的) 或者是比较冷门的软件,否则都有好心的网友帮我们打包好了

6.5.2. 示例

利用时间服务器 (network time protocol) ntp 这个软件来测试安装 :

假设 ntp-4.*.*.tar.gz 这个文件放置在 /root 这个目录下;

源代码请解开在 /usr/local/src 下面;

我要安装到 /usr/local/ntp 这个目录中;

1. 解压缩下载的 tarball ,并参阅 README/INSTALL 文件
[root@study ~]# cd /usr/local/src				# <==切换目录
[root@study src]# tar -zxvf /root/ntp-4.2.8p3.tar.gz <==解压缩到此目录
ntp-4.2.8p3/ <==会创建这个目录喔!
ntp-4.2.8p3/CommitLog
....(下面省略)....
[root@study src]# cd ntp-4.2.8p3
[root@study ntp-4.2.8p3]# vi INSTALL <==记得 README 也要看一下!
# 特别看一下 28 行到 54 行之间的安装简介!可以了解如何安装的流程喔!

2. 检查 configure 支持参数,并实际创建 makefile 规则档
[root@study ntp*]# ./configure --help | more						# <==查询可用的参数有哪些
--prefix=PREFIX install architecture-independent files in PREFIX
--enable-all-clocks + include all suitable non-PARSE clocks:
--enable-parse-clocks - include all suitable PARSE clocks:
# 上面列出的是比较重要的,或者是你可能需要的参数功能!
[root@study ntp*]# ./configure --prefix=/usr/local/ntp \
> --enable-all-clocks --enable-parse-clocks <==开始创建makefile
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
....(中间省略)....
checking for gcc... gcc <==也有找到 gcc 编译器了!
....(中间省略)....
config.status: creating Makefile				# <==现在知道这个重要性了吧?
config.status: creating config.h
config.status: creating evconfig-private.h
config.status: executing depfiles commands
config.status: executing libtool commands

一般来说 configure 设置参数较重要的就是那个 --prefix=/path 了,--prefix 后面接
的路径就是“这个软件未来要安装到那个目录去”如果你没有指定 --prefix=/path 这个参
数,通常默认参数就是 /usr/local 至于其他的参数意义就得要参考 ./configure --help 了!
这个动作完成之后会产生 makefile 或 Makefile 这个文件,最后需要成功的创建起Makefile 才行

3. 最后开始编译与安装
[root@study ntp*]# make clean; make
[root@study ntp*]# make check
[root@study ntp*]# make install
# 将数据给他安装在 /usr/local/ntp 下面

6.5.3. 利用 patch 更新源代码

“更新源代码”常常是只有更改部分文件的小部分内容而已, ?也就是说, 旧版本到新版本间没有更动过的文件就不要理他,仅将有修订过的文件部分来处理即可 ;

比对文件的指令,那就是 diff,这个指令可以将“两个文件之间的差异性列出来”!

那我们也知道新旧版本的文件之间, 其实只有修改一些程序码而已,那么我们可以通过 diff 比对出新旧版本之间的文字差异,然后再以相关的指令来将旧版的文件更新: 那就是 patch这个指令

来举个案例解释一下 : 假设我们刚刚计算三角函数的程序 (main) 历经多次改版, 0.1 版仅会简单的输出,0.2 版的输出就会含有角度值,因此这两个版本的内容不相同。如下所示,两个文件的意义为:

http://linux.vbird.org/linux_basic/0520source/main-0.1.tgz :main 的 0.1 版;

http://linux.vbird.org/linux_basic/0520source/main_0.1_to_0.2.patch :main 由 0.1 升级到 0.2 的 patch file;

下载并解压缩到你的 /root 下面。你会发现系统产生一个名为 main-0.1 的目录。 该目录内含有五个文件,就是刚刚的程序加上一个 Makefile 的规则文件。你可以到该目录下去看看 Makefile 的内容, 在这一版当中含有 main 与 clean 两个标的功能而已。至于 0.2 版则加入了 install 与 uninstall 的规则设置 ;

1. 测试旧版程序的功能
[root@study ~]# tar -zxvf main-0.1.tgz
[root@study ~]# cd main-0.1
[root@study main-0.1]# make clean main
[root@study main-0.1]# ./main
version 0.1
Please input your name: VBird
Please enter the degree angle (ex> 90): 45
Hi, Dear VBird, nice to meet you.
The Sin is: 0.71
The Cos is: 0.71

2. 查阅 patch file 内容
[root@study main-0.1]# vim ~/main_0.1_to_0.2.patch
diff -Naur main-0.1/cos_value.c main-0.2/cos_value.c
--- main-0.1/cos_value.c 2015-09-04 14:46:59.200444001 +0800
+++ main-0.2/cos_value.c 2015-09-04 14:47:10.215444000 +0800
@@ -7,5 +7,5 @@
{
float value;
....(下面省略)....


-Naur 后面代表使用 diff 去比较时,被比较的两个文件所在路径,这个路径非常的重要!因为 patch 的基本语法如下:
patch -p数字 < patch_file

特别留意那个“ -p数字”,那是与 patch_file 里面列出的文件名有关的信息。假如在 patch_file 第一行写的是这样:

*** /home/guest/example/expatch.old

那么当我下达“ patch -p0 < patch_file ”时,则更新的文件是“ /home/guest/example/expatch.old ”,如果“ patch -p1 < patch_file”,则更新的文件 为“home/guest/example/expatch.old”,如果“patch -p4 < patch_file”则更新“expatch.old”,也就是说, -pxx 那个 xx 代表“拿掉几个斜线(/)”的意思 ;

根据刚刚上头的数据,我们可以发现比较的文件是在 main-0.1/xxx 与 main-0.2/xxx , 所以说,如果你是在 main-0.1 下面,并且想要处理更新时,就得要拿掉一个目录 (因为并没有 main-0.2 的目录存在, 我们是在当前的目录进行更新的!),因此使用的是 -p1 才对

更新源代码,并且重新编译程序
[root@study main-0.1]# patch -p1 < ../main_0.1_to_0.2.patch
patching file cos_value.c
patching file main.c
patching file Makefile
patching file sin_value.c
# 请注意,目前所在目录是在 main-0.1 下面喔!注意与 patch 文件的相对路径!
# 虽然有五个文件,但其实只有四个文件有修改过喔!上面显示有改过的文件!
[root@study main-0.1]# make clean main
[root@study main-0.1]# ./main
version 0.2
Please input your name: VBird
Please enter the degree angle (ex> 90): 45
Hi, Dear VBird, nice to meet you.
The sin(45.000000) is: 0.71
The cos(45.000000) is: 0.71
# 你可以发现,输出的结果中版本变了,输出信息多了括号 () 喔!
[root@study main-0.1]# make install <==将他安装到 /usr/local/bin 给大家用
cp -a main /usr/local/bin
[root@study main-0.1]# main <==直接输入指令可执行!
[root@study main-0.1]# make uninstall <==移除此软件!
rm -f /usr/local/bin/main

只不过更新了源代码并非软件就更新!你还是得要将该软件进行编译后,才会是最终正确的软件!因为 patch 的功能主要仅只是更新源代码文件而已!

我们的 patch 是可以还原的!通过“ patch -R < ../main_0.1_to_0.2.patch ”就可以还原

如果我有一个很旧版的软件,这个软件已经更新到很新的版本,例如核心,那么我可以使用 patch file 来更新吗?

答:

这个问题挺有趣的,首先,你必须要确定旧版本与新版本之间“确实有释出patch file ”才行,以 kernel 2.2.xx 及 2.4.xx 来说,这两者基本上的架构已经不同了,所以两者间是无法以 patch file 来更新的。不过, 2.4.xx 与 2.4.yy 就可以更新了。不过,因为 kernel 每次推出的 patch 文件都仅针对前一个版本而已,所以假设要由 kernel 2.4.20 升级到 2.4.26 ,就必须要使用 patch 2.4.21, 2.4.22, 2.4.23, 2.4.24, 2.4.25, 2.4.26 六个文件来“依序更新”才行喔!当然,如果有朋友帮你比对过 2.4.20 与 2.4.26 ,那你自然就可以使用该 patch file 来直接一次更新

6.6. 函数库管理

6.6.1. 动态与静态函数库
  1. 很多的软件之间都会互相取用彼此提供的函数库来进行特殊功能的运行,如很多需要验证身份的程序都习惯利用 PAM 这个模块提供的验证机制来实作,而很多网络连线机制则习惯利用 SSL 函数库来进行连线加密的机制
  2. 函数库又依照是否被编译到程序内部而分为动态与静态函数库

静态函数库的特色:

  1. 扩展名:(扩展名为 .a) 这类的函数库通常扩展名为 libxxx.a 的类型;
  2. 编译行为: 这类函数库在编译的时候会直接整合到执行程序当中,所以利用静态函数库编译成 的文件会比较大一些;
  3. 独立执行的状态: 这类函数库最大的优点,就是编译成功的可执行文件可以独立执行,而不需要再 向外部要求读取函数库的内容 (请参照动态函数库的说明)。
  4. 升级难易度: 虽然可执行文件可以独立执行,但因为函数库是直接整合到可执行文件中, 因此 若函数库升级时,整个可执行文件必须要重新编译才能将新版的函数库整合到程序 当中。 也就是说,在升级方面,只要函数库升级了,所有将此函数库纳入的程序都需要重新编译!

动态函数库的特色:

  1. 扩展名:(扩展名为 .so)这类函数库通常扩展名为 libxxx.so 的类型;
  2. 编译行为: 动态函数库与静态函数库的编译行为差异挺大的。 与静态函数库被整个捉到程序中不同的,动态函数库在编译的时候,在程序里面只有一个“指向 (Pointer)”的位置而已。也就是说,动态函数库的内容并没有被整合到可执行文件当中,而是当可执行文件要使用到函数库的机制时, 程序才会去读取函数库来使用。由于可执行文件当中仅具有指向动态函数库所在的指标而已, 并不包含函数库的内容,所以他的文件会比较小一点。
  3. 独立执行的状态: 这类型的函数库所编译出来的程序不能被独立执行, 因为当我们使用到函数库的机制时,程序才会去读取函数库,所以函数库文件“必须要存在”才行,而且,函数库的“所在目录也不能改变”,因为我们的可可执行文件里面仅有“指标”亦即当要取用该动态函数库时, 程序会主动去某个路径下读取,呵呵!所以动态函数库可不能随意移动或删除,会影响很多相依的程序软件喔!
  4. 升级难易度: 虽然这类型的可执行文件无法独立运行,然而由于是具有指向的功能, 所以,当函数库升级后,可执行文件根本不需要进行重新编译的行为,因为可执行文件会直接指向新的函数库文件 (前提是函数库新旧版本的文件名相同喔!)。

绝大多数的函数库都放置在:/lib64, /lib 目录下!此外,Linux 系统里面很多的函数库其实 kernel 就提供了,那么 kernel 的函数库放在哪里?就是在 /lib/modules 里面

注意 : 不同版本的核心提供的函数库差异性是挺大的,所以 kernel 2.4.xx 版本的系统不要想将核心换成 2.6.xx !很容易由于函数库的不同而导致很多原本可以执行的软件无法顺利运行

6.6.2. ldconfig 与 /etc/ld.so.conf

目前的 Linux 大多是将函数库做成动态函数库之后,那有没有办法增加函数库的读取性能? 我们知道内

存的存取速度是硬盘的好几倍,所以,如果我们将常用到的动态函数库先载入内存当中(高速缓存, cache),如此一来,当软件要取用动态函数库时,就不需要从头由硬盘里面读出!这样不就可以增进动态函数库的读取速度?没错,是这样的!这个时候就需要 ldconfig 与 /etc/ld.so.conf 的协助了。

如何将动态函数库载入高速缓存内存当中呢?

  1. 首先,我们必须要在 /etc/ld.so.conf 里面写下“ 想要读入高速缓存内存当中的动态函数库所在的目录”,注意,是目录而不是文件;
  2. 接下来则是利用 ldconfig 这个可执行文件将 /etc/ld.so.conf 的数据读入高速缓存当中;
  3. 同时也将数据记录一份在 /etc/ld.so.cache 这个文件当中呐!

事实上, ldconfig 还可以用来判断动态函数库的链接信息呢!赶紧利用 CentOS 来测试看看。假设你想要将目前你系统下的 mariadb 函数库加入到高速缓存当中时,可以这样做:

[root@study ~]# ldconfig [-f conf] [ -C cache]
[root@study ~]# ldconfig [-p]
选项与参数:
    -f conf :那个 conf 指的是某个文件名称,也就是说,使用 conf 作为 libarary
    函数库的取得路径,而不以 /etc/ld.so.conf 为默认值
    -C cache:那个 cache 指的是某个文件名称,也就是说,使用 cache 作为高速缓存暂存
    的函数库数据,而不以 /etc/ld.so.cache 为默认值
    -p :列出目前有的所有函数库数据内容 (在 /etc/ld.so.cache 内的数据!)
    
# 范例一:假设我的 Mariadb 数据库函数库在 /usr/lib64/mysql 当中,如何读进 cache ?
[root@study ~]# vim /etc/ld.so.conf.d/vbird.conf
/usr/lib64/mysql							# <==这一行新增的啦!
[root@study ~]# ldconfig 			# <==画面上不会显示任何的信息,不要太紧张!正常的!
[root@study ~]# ldconfig -p
924 libs found in cache `/etc/ld.so.cache'
p11-kit-trust.so (libc6,x86-64) => /lib64/p11-kit-trust.so
libzapojit-0.0.so.0 (libc6,x86-64) => /lib64/libzapojit-0.0.so.0
....(下面省略)....
# 函数库名称 => 该函数库实际路径

通过上面的动作,我们可以将 Mariadb 的相关函数库给他读入高速缓存当中,这样可以加快函数库读取的效率呢!

在某些时候,你可能会自行加入某些 Tarball 安装的动态函数库,而你想要让这些动态函数库的相关链接可以被读入到高速缓存当中, 这个时候你可以将动态函数库所在的目录名称写入 /etc/ld.so.conf.d/yourfile.conf 当中,然后执行 ldconfig 就可以

6.6.3. 程序的动态函数库解析: ldd

如何判断某个可执行的 binary 文件含有什么动态函数库呢?很简单,利用 ldd 就可以

[root@study ~]# ldd [-vdr] [filename]
    选项与参数:
      -v :列出所有内容信息;
      -d :重新将数据有遗失的 link 点秀出来!
      -r :将 ELF 有关的错误内容秀出来!
      
范例一:找出 /usr/bin/passwd 这个文件的函数库数据
[root@study ~]# ldd /usr/bin/passwd
....(前面省略)....
    libpam.so.0 => /lib64/libpam.so.0 (0x00007f5e683dd000) 						#	<==PAM 模块
    libpam_misc.so.0 => /lib64/libpam_misc.so.0 (0x00007f5e681d8000)
    libaudit.so.1 => /lib64/libaudit.so.1 (0x00007f5e67fb1000) 				#	<==SELinux
    libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f5e67d8c000) 		#	<==SELinux
....(下面省略)....
# 我们前言的部分不是一直提到 passwd 有使用到 pam 的模块吗!怎么知道?
# 利用 ldd 察看一下这个文件,看到 libpam.so 了吧?这就是 pam 提供的函数库
范例二:找出 /lib64/libc.so.6 这个函数的相关其他函数库!
[root@study ~]# ldd -v /lib64/libc.so.6
		/lib64/ld-linux-x86-64.so.2 (0x00007f7acc68f000)
		linux-vdso.so.1 => (0x00007fffa975b000)
  
		Version information: 			# <==使用 -v 选项,增加显示其他版本信息!
		/lib64/libc.so.6:
							ld-linux-x86-64.so.2 (GLIBC_2.3) => /lib64/ld-linux-x86-64.so.2
							ld-linux-x86-64.so.2 (GLIBC_PRIVATE) => /lib64/ld-linux-x86-64.so.2

未来如果你常常升级安装 RPM 的软件时 (下一章节会介绍),应该常常会发现那个“ 相依属性”的问题吧!没错!我们可以先以 ldd 来视察“相依函数库”之间的相关性!以先取得了解

例如上面的例子中,我们检查了 libc.so.6 这个在 /lib64 当中的函数库,结果发现他其实还跟 ld-linux-x86-64.so.2有关!所以我们就需要来了解一下,那个文件到底是什么软件的函数库呀?使用 -v 这个参数还可以得知该函数库来自于哪一个软件!像上面的数据中,就可以得到该 libc.so.6 其实可以支持 GLIBC_2.3 等的版本!

6.7. 检验软件正确性

判断我们下载的文件本身有没有问题 , 就要通过 每个文件独特的指纹验证数据了 :

因为每个文件的内容与文件大小都不相同, 所以如果一个文件被修改之后,必然会有部分的信息不一样!利用这个特性,我们可以使用 MD5/sha1 或更严密的 sha256 等指纹验证机制来判断该文件有没有被更动过!

有md5sum, sha1sum, sha256sum 这几文件指纹

6.7.1. md5sum / sha1sum / sha256sum

目前有多种机制可以计算文件的指纹码,我们选择使用较为广泛的 MD5, SHA1 或 SHA256 加密机制来处理

如何确认我们下载的文件是正确没问题的呢?

[root@study ~]# md5sum/sha1sum/sha256sum [-bct] filename
[root@study ~]# md5sum/sha1sum/sha256sum [--status|--warn] --check filename
选项与参数:
    -b :使用 binary 的读档方式,默认为 Windows/DOS 文件型态的读取方式;
    -c :检验文件指纹;
    -t :以文字体态来读取文件指纹。

    
范例一:将刚刚的ntp文件下载后,测试看看指纹码
[root@study ~]# md5sum ntp-4.2.8p3.tar.gz
b98b0cbb72f6df04608e1dd5f313808b ntp-4.2.8p3.tar.gz
# 看!显示的编码是否与上面相同呢?赶紧测试看看!

7. 软件安装 RPM, SRPM 与 YUM

厂商先在他们的系统上面编译好了我们使用者所需要的软件, 然后将这个编译好的可执行的软件直接释出给使用者来安装

7.1. Linux 界的两大主流: RPM 与 DPKG

目前在 Linux 界软件安装方式最常见的有两种,分别是:

dpkg

这个机制最早是由 Debian Linux 社群所开发出来的,通过 dpkg 的机制, Debian 提供的软件就能够简单的安装起来,同时还能提供安装后的软件信息,实在非常不错。 只要是衍生于 Debian 的其他 Linux distributions 大多使用 dpkg 这个机制来管理软件的, 包括 B2D, Ubuntu 等等。

RPM

这个机制最早是由 Red Hat 这家公司开发出来的,后来实在很好用,因此很多distributions 就使用这个机制来作为软件安装的管理方式。包括 Fedora, CentOS, SuSE 等等知名的开发商都是。

不论 dpkg/rpm 这些机制或多或少都会有软件属性相依的问题,那该如何解决呢?

其实前面谈到过每个软件文件都有提供相依属性的检查, 那么如果我们将相依属性的数据做成列表,等到实际软件安装时,若发生有相依属性的软件状况时,例如安装 A 需要先安装 B 与 C ,而安装 B 则需要安装 D 与 E 时,那么当你要安装 A ,通过相依属性列表,管理机制自动去取得 B, C, D, E 来同时安装, 不就解决了属性相依的问题吗?

目前新的 Linux 开发商都有提供这样的“线上升级”机制,通过这个机制, 原版光盘就只有第一次安装时需要用到而已,其他时候只要有网络,你就能够取得原本开发商所提供的任何软件了呢!

在 dpkg 管理机制上就开发出 APT 的线上升级机制,RPM 则依开发商的不同,有 Red Hat 系统的 yum , SuSE 系统的 Yast Online Update (YOU) 等

7.2. 什么是 RPM 与 SRPM

RPM 全名是“ RedHat Package Manager ”简称则为 RPM 啦!顾名思义,当初这个软件管理的机制是由 Red Hat 这家公司发展出来的。 RPM 是以一种数据库记录的方式来将你所需要的软件安装到你的 Linux 系统的一套管理机制。

  1. 他最大的特点就是将你要安装的软件先编译过, 并且打包成为 RPM 机制的包装文件,通过包装好的软件里头默认的数据库记录, 记录这个软件要安装的时候必须具备的相依属性软件
  2. 当安装在你的 Linux 主机时, RPM 会先依照软件里头的数据查询Linux 主机的相依属性软件是否满足, 若满足则予以安装,若不满足则不予安装。
  3. 那么安装的时候就将该软件的信息整个写入 RPM 的数据库中,以便未来的查询、验证与反安装!这样一来的优点是:
    1. 由于已经编译完成并且打包完毕,所以软件传输与安装上很方便 (不需要再重新编译);
    2. 由于软件的信息都已经记录在 Linux 主机的数据库上,很方便查询、升级与反安装

该软件文件几乎只能安装在原本默认的硬件与操作系统版本中, 所以,通常不同的 distribution 所释出的 RPM 文件,并不能用在其他的distributions 上。

更有甚者,相同 distribution 的不同版本之间也无法互通,例如 CentOS 6.x 的RPM 文件就无法直接套用在 CentOS 7.x !因此,这样可以发现这些软件管理机制的问题是:

  1. 软件文件安装的环境必须与打包时的环境需求一致或相当;
  2. 需要满足软件的相依属性需求;
  3. 反安装时需要特别小心,最底层的软件不可先移除,否则可能造成整个系统的问题

如果我真的想要安装其他 distributions 提供的好用的 RPM 软件文件时?用 SRPM

  1. SRPM 是什么呢?他是 Source RPM 的意思,也就是这个 RPM 文件里面含有源代码哩!特别注意的是,这个 SRPM 所提供的软件内容“并没有经过编译”, 它提供的是源代码!
  2. SRPM 的扩展名是以 ***.src.rpm 这种格式来命名的

既然 SRPM 提 供的是源代码,那么为什么我们不使用 Tarball 直接来安装就好了?

  1. 这是因为 SRPM 虽然内容是源代码, 但是他仍然含有该软件所需要的相依性软件说明、以及所有 RPM 文件所提供的数据。
  2. 同时,他与 RPM 不同的是,他也提供了参数配置文件 (就是configure 与 makefile)。所以,如果我们下载的是 SRPM ,那么要安装该软件时,你就必须要:
    1. 先将该软件以 RPM 管理的方式编译,此时 SRPM 会被编译成为 RPM 文件;然后将编译完成的 RPM 文件安装到 Linux 系统当中
  1. 通常一个软件在释出的时候,都会同时释出该软件的 RPM 与 SRPM 。
  2. 我们现在知道 RPM 文件必须要在相同的 Linux 环境下才能够安装,而 SRPM 既然是源代码的格式,自然我们就可以通过修改 SRPM 内的参数配置文件,然后重新编译产生能适合我们 Linux 环境的 RPM 文件,

7.2.1. 什么是 i386, i586, i686, noarch, x86_64

那么我们怎么知道这个软件的版本、适用的平台、编译释出的次数呢?只要通过文件名就可以知道了!例如 rp-pppoe-3.11-5.el7.x86_64.rpm 这的文件的意义为:

除了后面适合的硬件平台与扩展名外,主要是以“-”来隔开各个部分,这样子可以很清楚的发现该软件的名称、 版本信息、打包次数与操作的硬件平台

7.2.2. RPM 属性相依的克服方式: YUM 线上升级

RPM 软件文件内部会记录相依属性的数据, 那想一想,要是我将这些相依属性的软件先列表, 在有要安装软件需求的时候,先到这个列表去找,同时与系统内已安装的软件相比较,没安装到的相依软件就一口气同时安装起来, 那不就解决了相依属性的问题了吗?有没有这种机制啊?有!那就是 YUM 机制的由来!

CentOS :

  1. 先将释出的软件放置到 YUM 服务器内,
  2. 然后分析这些软件的相依属性问题,将软件内的记录信息写下来 (header)。
  3. 然后再将这些信息分析后记录成软件相关性的清单列表。这些列表数据与软件所在的本机或网络位置可以称呼为容器或软件仓库或软件库 (repository)。
  4. 当用户端有软件安装的需求时,用户端主机会主动的向网络上面的 yum 服务器的软件库网址下载清单列表, 然后通过清单列表的数据与本机 RPM 数据库已存在的软件数据相比较,就能够一口气安装所有需要的具有相依属性的软件了。

7.3. RPM 软件管理程序: rpm

RPM 的使用其实不难,只要使用 rpm 这个指令 ; 最好还是得要知道一下,到底 RPM 类型的文件他们是将软件的相关文件放置在哪里呢?还有,我们说的那个 RPM 的数据库又是放置在哪里呢?

事实上 , yum 就可以直接用来进行安装的动作,基本上 rpm这个指令真的就只剩下查询与检验的功能!

7.3.1. RPM 默认安装的路径

RPM 文件安装完毕后,该软件相关的信息就会被写入 /var/lib/rpm/ 目录下的数据库文件中 ;未来如果我们有任何软件升级的需求,版本之间的比较就是来自于这个数据库, 而如果你想要查询系统已经安装的软件,也是从这里查询的!目前的 RPM 也提供数码签章信息, 这些数码签章也是在这个目录内记录的

7.3.2. RPM 安装 (install)

因为安装软件是 root 的工作,因此你得要是 root 的身份才能够操作 rpm 这指令的。 用 rpm 来安装很简单!

假设我要安装一个文件名为 rp-pppoe-3.11- 5.el7.x86_64.rpm 的文件,那么我可以这样:(假设原版光盘已经放在 /mnt 下面了)

[root@study ~]# rpm -i /mnt/Packages/rp-pppoe-3.11-5.el7.x86_64.rpm
不过,这样的参数其实无法显示安装的进度,所以,通常我们会这样下达安装指令:
[root@study ~]# rpm -ivh package_name
选项与参数:
    -i :install 的意思
    -v :察看更细部的安装信息画面
    -h :以安装信息列显示安装进度
    
范例一:安装原版光盘上的 rp-pppoe 软件
[root@study ~]# rpm -ivh /mnt/Packages/rp-pppoe-3.11-5.el7.x86_64.rpm
Preparing... ################################# [100%]
Updating / installing...
1:rp-pppoe-3.11-5.el7 ################################# [100%]

范例二、一口气安装两个以上的软件时:
[root@study ~]# rpm -ivh a.i386.rpm b.i386.rpm *.rpm
# 后面直接接上许多的软件文件!
范例三、直接由网络上面的某个文件安装,以网址来安装:
[root@study ~]# rpm -ivh http://website.name/path/pkgname.rpm

如果我们在安装的过程当中发现问题,或者已经知道会发生的问题, 而还是“执意”要安装这个软件时,可以使用如下的参数“强制”安装上去:

7.3.3. RPM 升级与更新 (upgrade/freshen)

使用 RPM 来升级真是太简单了!就以 -Uvh 或 -Fvh 来升级即可,而 -Uvh 与 -Fvh 可以用的选项与参数,跟 install 是一样的。不过, -U 与 -F 的意义还是不太一样的,基本的差别是这样的

- Uvh 后面接的软件即使没有安装过,则系统将予以直接安装; 若后面接的软件有安装过旧版,则系统自动更新至新版;

- Fvh 如果后面接的软件并未安装到你的 Linux 系统上,则该软件不会被安装;亦即只有已安装至你 Linux 系统内的软件会被“升级”!

7.3.4. RPM 查询 (query)

RPM 在查询的时候,其实查询的地方是在 /var/lib/rpm/ 这个目录下的数据库文件 !另外, RPM 也可以查询未安装的 RPM 文件内的信息!那如何去查询呢? 我们先来谈谈可用的选项有哪些?

[root@study ~]# rpm -qa [软件名称]									# <==已安装软件
[root@study ~]# rpm -q[licdR] 已安装的软件名称 		#	<==已安装软件
[root@study ~]# rpm -qf 存在于系统上面的某个文件名 	#	<==已安装软件
[root@study ~]# rpm -qp[licdR] 未安装的某个文件名称 # <==查阅RPM文件
选项与参数:
	查询已安装软件的信息:
    -q :仅查询,后面接的软件名称是否有安装;
    -qa :列出所有的,已经安装在本机 Linux 系统上面的所有软件名称;
    -qi :列出该软件的详细信息 (information),包含开发商、版本与说明等;
    -ql :列出该软件所有的文件与目录所在完整文件名 (list);
    -qc :列出该软件的所有配置文件 (找出在 /etc/ 下面的文件名而已)
    -qd :列出该软件的所有说明文档 (找出与 man 有关的文件而已)
    -qR :列出与该软件有关的相依软件所含的文件 (Required 的意思)
    -qf :由后面接的文件名称,找出该文件属于哪一个已安装的软件;
    -q --scripts:列出是否含有安装后需要执行的脚本档,可用以 debug 喔!
	查询某个 RPM 文件内含有的信息:
		-qp[icdlR]:注意 -qp 后面接的所有参数以上面的说明一致。
  							但用途仅在于找出某个 RPM 文件内的信息,而非已安装的软件信息!注意!

在查询的部分,所有的参数之前都需要加上 -q 才是所谓的查询!查询主要分为两部分,

  1. 一个是查已安装到系统上面的的软件信息,这部份的信息都是由 /var/lib/rpm/所提供。
  2. 另一个则是查某个 rpm 文件内容, 等于是由 RPM 文件内找出一些要写入数据库内的信息就是了,这部份就得要使用 -qp (p 是 package 的意思)。

那就来看看几个简单的范例吧!

范例一:找出你的 Linux 是否有安装 logrotate 这个软件?
[root@study ~]# rpm -q logrotate
logrotate-3.8.6-4.el7.x86_64
[root@study ~]# rpm -q logrotating
package logrotating is not installed
# 注意到,系统会去找是否有安装后面接的软件名称。注意,不必要加上版本喔!
# 至于显示的结果,一看就知道有没有安装啦!
范例二:列出上题当中,属于该软件所提供的所有目录与文件:
[root@study ~]# rpm -ql logrotate
/etc/cron.daily/logrotate
/etc/logrotate.conf
....(以下省略)....
# 可以看出该软件到底提供了多少的文件与目录,也可以追踪软件的数据。
范例三:列出 logrotate 这个软件的相关说明数据:
[root@study ~]# rpm -qi logrotate
Name : logrotate # 软件名称
Version : 3.8.6 # 软件的版本
Release : 4.el7 # 释出的版本
Architecture: x86_64 # 编译时所针对的硬件等级
Install Date: Mon 04 May 2015 05:52:36 PM CST # 这个软件安装到本系统的时间
Group : System Environment/Base # 软件是放再哪一个软件群组中
Size : 102451 # 软件的大小
License : GPL+ # 释出的授权方式
Signature : RSA/SHA256, Fri 04 Jul 2014 11:34:56 AM CST, Key ID 24c6a8a7f4a80eb5
Source RPM : logrotate-3.8.6-4.el7.src.rpm # 这就是 SRPM 的文件名
Build Date : Tue 10 Jun 2014 05:58:02 AM CST # 软件编译打包的时间
Build Host : worker1.bsys.centos.org # 在哪一部主机上面编译的
Relocations : (not relocatable)
Packager : CentOS BuildSystem <http://bugs.centos.org>
Vendor : CentOS
URL : https://fedorahosted.org/logrotate/
Summary : Rotates, compresses, removes and mails system log files
Description : # 这个是详细的描述!
The logrotate utility is designed to simplify the administration of
log files on a system which generates a lot of log files. Logrotate
allows for the automatic rotation compression, removal and mailing of
log files. Logrotate can be set to handle a log file daily, weekly,
monthly or when the log file gets to a certain size. Normally,
logrotate runs as a daily cron job.
Install the logrotate package if you need a utility to deal with the
log files on your system.
# 列出该软件的 information (信息),里面的信息可多着呢,包括了软件名称、
# 版本、开发商、SRPM文件名称、打包次数、简单说明信息、软件打包者、
# 安装日期等等!如果想要详细的知道该软件的数据,用这个参数来了解一下
范例四:分别仅找出 logrotate 的配置文件与说明文档
[root@study ~]# rpm -qc logrotate
[root@study ~]# rpm -qd logrotate
范例五:若要成功安装 logrotate ,他还需要什么文件的帮忙?
[root@study ~]# rpm -qR logrotate
/bin/sh
config(logrotate) = 3.8.6-4.el7
coreutils >= 5.92
....(以下省略)....
# 由这里看起来,呵呵~还需要很多文件的支持才行喔!
范例六:由上面的范例五,找出 /bin/sh 是那个软件提供的?
[root@study ~]# rpm -qf /bin/sh
bash-4.2.46-12.el7.x86_64
# 这个参数后面接的可是“文件”呐!不像前面都是接软件喔!
# 这个功能在查询系统的某个文件属于哪一个软件所有的。
范例七:假设我有下载一个 RPM 文件,想要知道该文件的需求文件,该如何?
[root@study ~]# rpm -qpR filename.i386.rpm
# 加上 -qpR ,找出该文件需求的数据!

在查询本机上面的 RPM 软件相关信息时, 不需要加上版本的名称,只要加上软件名称即可!因为他会由 /var/lib/rpm 这个数据库里面去查询, 所以我们可以不需要加上版本名称。

但是查询某个 RPM 文件就不同了,我们必须要列出整个文件的完整文件名才行

1. 我想要知道我的系统当中,以 c 开头的软件有几个,如何实做?
2. 我的 WWW 服务器为 Apache ,我知道他使用的 RPM 软件文件名为 httpd。现在,
		我想要知道这个软件的所有配置文件放置在何处,可以怎么作?
3. 承上题,如果查出来的设置文件已经被我改过,但是我忘记了曾经修改过哪些地方,所以想要直接重新安装一次该软件,该如何作?
4. 如果我误砍了某个重要文件,例如 /etc/crontab,偏偏不晓得他属于哪一个软件,该怎么办?
答:
1. rpm -qa | grep ^c | wc -l
2. rpm -qc httpd
3. 假设该软件在网络上的网址为:
http://web.site.name/path/httpd-x.x.xx.i386.rpm
则我可以这样做:
rpm -ivh http://web.site.name/path/httpd-x.x.xx.i386.rpm --replacepkgs
4. 虽然已经没有这个文件了,不过没有关系,因为 RPM 有记录在
/var/lib/rpm 当中的数据库啊!所以直接下达:
rpm -qf /etc/crontab
就可以知道是那个软件啰!重新安装一次该软件即可!

7.3.5. RPM验证与数码签章(Verify/signature)
7.3.5.1. RPM验证文件改动

验证 (Verify) 的功能主要在于提供系统管理员一个有用的管理机制!作用的方式是“使用 /var/lib/rpm 下面的数据库内容来比对目前 Linux 系统的环境下的所有软件文件 ”; (注意是软件文件)

也就是说, 当你有数据不小心遗失, 或者是因为你误杀了某个软件的文件,或者是不小心不知道修改到某一个软件的文件内容, 就用这个简单的方法来验证一下原本的文件系统, 好让你了解这一阵子到底是修改到哪些文件数据

[root@study ~]# rpm -Va
[root@study ~]# rpm -V 已安装的软件名称
[root@study ~]# rpm -Vp 某个 RPM 文件的文件名
[root@study ~]# rpm -Vf 在系统上面的某个文件
选项与参数:
    -V :后面加的是软件名称,若该软件所含的文件被更动过,才会列出来;
    -Va :列出目前系统上面所有可能被更动过的文件;
    -Vp :后面加的是文件名称,列出该软件内可能被更动过的文件;
    -Vf :列出某个文件是否被更动过~
    
范例一:列出你的 Linux 内的 logrotate 这个软件是否被更动过?
[root@study ~]# rpm -V logrotate
# 如果没有出现任何讯息,恭喜你,该软件所提供的文件没有被更动过。
# 如果有出现任何讯息,才是有出现状况啊!
范例二:查询一下,你的 /etc/crontab 是否有被更动过?
[root@study ~]# rpm -Vf /etc/crontab
.......T. c /etc/crontab
# 瞧!因为有被更动过,所以会列出被更动过的信息类型!

我怎么知道到底我的文件被更动过的内容是什么?

 # 例如,我们检查一下 logrotate 这个软件:
 [root@study ~]# rpm -ql logrotate
/etc/cron.daily/logrotate
/etc/logrotate.conf
/etc/logrotate.d
/usr/sbin/logrotate
/usr/share/doc/logrotate-3.8.6
/usr/share/doc/logrotate-3.8.6/CHANGES
/usr/share/doc/logrotate-3.8.6/COPYING
/usr/share/man/man5/logrotate.conf.5.gz
/usr/share/man/man8/logrotate.8.gz
/var/lib/logrotate.status
# 共有 10 个文件啊!现在请修改 /etc/logrotate.conf 内的 rotate 变成 5
[root@study ~]# rpm -V logrotate
..5....T. c /etc/logrotate.conf

你会发现在文件名之前有个 c ,然后就是一堆奇怪的文字了。那个 c 代表的是 configuration , 就是配置文件的意思。至于最前面的几个信息是:

S :(file Size differs) 文件的容量大小是否被改变

M :(Mode differs) 文件的类型或文件的属性 (rwx) 是否被改变?如是否可执行等参数已被改变

5 :(MD5 sum differs) MD5 这一种指纹码的内容已经不同

D :(Device major/minor number mis-match) 设备的主/次代码已经改变

L:(readLink(2) path mis-match) Link 路径已被改变

U :(User ownership differs) 文件的所属人已被改变

G :(Group ownership differs) 文件的所属群组已被改变

T :(mTime differs) 文件的创建时间已被改变

P :(caPabilities differ) 功能已经被改变

当一个配置文件所有信息都被改动过,显示的就是 : SM5DLUGTP c filename

至于那个 c 代表的是“ Config file ”的意思,也就是文件的类型,文件类型有下面这几类:

c :配置文件 (config file)

d :文件数据文件 (documentation)

g :鬼文件~通常是该文件不被某个软件所包含,较少发生!(ghost file)

l :授权文件 (license file)

r :读我文件 (read me)

之前的主机曾经由于安装一套软件,导致被攻击成为跳板。 会发现的原因是系统中只要出现 *.patch 的扩展名时,使用 ls -l 就是显示不出来该文件名 (该文件名确实存在)。 找了好久,用了好多工具都找不出问题,最终利用 rpm -Va 找出来,原来好多 binary program 被更动过,连 init 都被恶搞!此时,赶紧重新安装 Linux 并移除那套软件,之后就比较正常了。所以说,这个 rpm -Va 是个好功能 !

[root@iZ2ze2ih1s2cnwpi660rubZ ~]# ll
total 1
-rw-r--r-- 1 root root   64 Aug 26 15:50 hello.c
[root@iZ2ze2ih1s2cnwpi660rubZ ~]# rpm -Vf hello.c 
file /root/hello.c is not owned by any package

# rpm不会显示非rpm管理的文件的改动问题

7.3.5.2. 数码签章 (digital signature)
  1. 谈完了软件的验证后,不知道你有没有发现一个问题,那就是,验证只能验证软件内的信息与 /var/lib/rpm/ 里面的数据库信息而已,如果该软件文件所提供的数据本身就有问题,那你使用验证的手段也无法确定该软件的正确性 ;
  2. 在Tarball 与文件的验证方面,我们可以使用前一章谈到的 md5 指纹码来检查, 不过,连指纹码也可能会被窜改的嘛!那怎办?我们可以通过数码签章来检验软件的来源的
  3. 就像你自己的签名一样,我们的软件开发商原厂所推出的软件也会有一个厂商自己的签章系统!只是这个签章被数码化了而已。厂商可以数码签章系统产生一个专属于该软件的签章并将该签章的公钥 (public key) 释出
  4. 当你要安装一个 RPM 文件时:
    1. 首先你必须要先安装原厂释出的公钥文件
    2. 实际安装原厂的 RPM 软件时, rpm 指令会去读取 RPM 文件的签章信息,与本机系统内的签章信息比对,
    3. 若签章相同则予以安装,若找不到相关的签章信息时,则给予警告并且停止安装。

CentOS 使用的数码签章系统为 GNU 计划的 GnuPG (GNU Privacy Guard, GPG)。 GPG 可以通过杂凑运算,算出独一无二的专属金钥系统或者是数码签章系统,(GNU Privacy Guard (GPG) 官方网站的介绍:http://www.gnupg.org/)

CentOS 的数码签章位于:
[root@study ~]# ll /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
-rw-r--r--. 1 root root 1690 Apr 1 06:27 /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
[root@study ~]# cat /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1.4.5 (GNU/Linux)

mQINBFOn/0sBEADLDyZ+DQHkcTHDQSE0a0B2iYAEXwpPvs67cJ4tmhe/iMOyVMh9
Yw/vBIF8scm6T/vPN5fopsKiW9UsAhGKg0epC6y5ed+NAUHTEa6pSOdo7CyFDwtn
4HF61Esyb4gzPT6QiSr0zvdTtgYBRZjAEPFVu3Dio0oZ5UQZ7fzdZfeixMQ8VMTQ
4y4x5vik9B+cqmGiq9AW71ixlDYVWasgR093fXiD9NLT4DTtK+KLGYNjJ8eMRqfZ
Ws7g7C+9aEGHfsGZ/SxLOumx/GfiTloal0dnq8TC7XQ/JuNdB9qjoXzRF+faDUsj
WuvNSQEqUXW1dzJjBvroEvgTdfCJfRpIgOrc256qvDMp1SxchMFltPlo5mbSMKu1
x1p4UkAzx543meMlRXOgx2/hnBm6H6L0FsSyDS6P224yF+30eeODD4Ju4BCyQ0jO
IpUxmUnApo/m0eRelI6TRl7jK6aGqSYUNhFBuFxSPKgKYBpFhVzRM63Jsvib82rY
438q3sIOUdxZY6pvMOWRkdUVoz7WBExTdx5NtGX4kdW5QtcQHM+2kht6sBnJsvcB
JYcYIwAUeA5vdRfwLKuZn6SgAUKdgeOtuf+cPR3/E68LZr784SlokiHLtQkfk98j
NXm6fJjXwJvwiM2IiFyg8aUwEEDX5U+QOCA0wYrgUQ/h8iathvBJKSc9jQARAQAB
tEJDZW50T1MtNyBLZXkgKENlbnRPUyA3IE9mZmljaWFsIFNpZ25pbmcgS2V5KSA8
c2VjdXJpdHlAY2VudG9zLm9yZz6JAjUEEwECAB8FAlOn/0sCGwMGCwkIBwMCBBUC
CAMDFgIBAh4BAheAAAoJECTGqKf0qA61TN0P/2730Th8cM+d1pEON7n0F1YiyxqG
QzwpC2Fhr2UIsXpi/lWTXIG6AlRvrajjFhw9HktYjlF4oMG032SnI0XPdmrN29lL
F+ee1ANdyvtkw4mMu2yQweVxU7Ku4oATPBvWRv+6pCQPTOMe5xPG0ZPjPGNiJ0xw
4Ns+f5Q6Gqm927oHXpylUQEmuHKsCp3dK/kZaxJOXsmq6syY1gbrLj2Anq0iWWP4
Tq8WMktUrTcc+zQ2pFR7ovEihK0Rvhmk6/N4+4JwAGijfhejxwNX8T6PCuYs5Jiv
hQvsI9FdIIlTP4XhFZ4N9ndnEwA4AH7tNBsmB3HEbLqUSmu2Rr8hGiT2Plc4Y9AO
aliW1kOMsZFYrX39krfRk2n2NXvieQJ/lw318gSGR67uckkz2ZekbCEpj/0mnHWD
3R6V7m95R6UYqjcw++Q5CtZ2tzmxomZTf42IGIKBbSVmIS75WY+cBULUx3PcZYHD
ZqAbB0Dl4MbdEH61kOI8EbN/TLl1i077r+9LXR1mOnlC3GLD03+XfY8eEBQf7137
YSMiW5r/5xwQk7xEcKlbZdmUJp3ZDTQBXT06vavvp3jlkqqH9QOE8ViZZ6aKQLqv
pL+4bs52jzuGwTMT7gOR5MzD+vT0fVS7Xm8MjOxvZgbHsAgzyFGlI1ggUQmU7lu3
uPNL0eRx4S1G4Jn5
=OGYX
-----END PGP PUBLIC KEY BLOCK-----

从上面的输出,你会知道该数码签章码其实仅是一个乱数而已,这个乱数对于数码签章有意义而已, 我们看不懂!那么这个文件如何安装呢?

rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

由于不同版本 GPG 金钥文件放置的位置可能不同,不过文件名大多是以 GPG-KEY 来说明的, 因此你可以简单的使用 locate 或 find 来找寻,如以下的方式来搜寻即可:

locate GPG-KEY

find /etc -name '*GPG-KEY*'

这个金钥的内容会以什么方式呈现呢?基本上都是使用 pubkey 作为软件的名称的!那我们先列出金钥软件名称后,再以 -qi 的方式来查询看看该软件的信息为何

[root@study ~]# rpm -qa | grep pubkey
gpg-pubkey-f4a80eb5-53a7ff4b
[root@study ~]# rpm -qi gpg-pubkey-f4a80eb5-53a7ff4b
Name : gpg-pubkey
Version : f4a80eb5
Release : 53a7ff4b
Architecture: (none)
Install Date: Fri 04 Sep 2015 11:30:46 AM CST
Group : Public Keys
Size : 0
License : pubkey
Signature : (none)
Source RPM : (none)
Build Date : Mon 23 Jun 2014 06:19:55 PM CST
Build Host : localhost
Relocations : (not relocatable)
Packager : CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>
Summary : gpg(CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>)
Description :
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: rpm-4.11.1 (NSS-3)
....(下面省略)....

重点就是最后面出现的那一串乱码!那可是作为数码签章非常重要的一环!如果你忘记加上数码签章,很可能很多原版软件就不能让你安装啰~除非你利用 rpm 时选择略过数码签章的选项

7.3.6. RPM 反安装(卸载)与重建数据库 (erase/rebuilddb)

反安装就是将软件解除安装!要注意的是,“解安装的过程一定要由最上层往下解除”,

  1. 以 rp-pppoe 为例,这一个软件主要是依据 ppp 这个软件来安装的,所以当你要解除 ppp 的时候,就必须要先解除 rp-pppoe 才行!否则就会发生结构上的问题!
  2. 这个可以由建筑物来说明, 如果你要拆除五、六楼,那么当然要由六楼拆起

移除的选项很简单,就通过 -e 即可移除。不过,很常发生软件属性相依导致无法移除某些软件的问题!能加 --nodeps 来强制移除,如此一来所有会用到 pam 函数库的软件,都将成为无法运行的程序;

我们以下面的例子来说明 :

# 1. 找出与 pam 有关的软件名称,并尝试移除 pam 这个软件:
[root@study ~]# rpm -qa | grep pam
fprintd-pam-0.5.0-4.0.el7_0.x86_64
pam-1.1.8-12.el7.x86_64
gnome-keyring-pam-3.8.2-10.el7.x86_64
pam-devel-1.1.8-12.el7.x86_64
pam_krb5-2.4.8-4.el7.x86_64
[root@study ~]# rpm -e pam
error: Failed dependencies: <==这里提到的是相依性的问题
			libpam.so.0()(64bit) is needed by (installed) systemd-libs-208-20.el7.x86_64
			libpam.so.0()(64bit) is needed by (installed) libpwquality-1.2.3-4.el7.x86_64
....(以下省略)....
# 2. 若仅移除 pam-devel 这个之前范例安装上的软件呢?
[root@study ~]# rpm -e pam-devel 			# <==不会出现任何讯息!
[root@study ~]# rpm -q pam-devel
package pam-devel is not installed

由于 RPM 文件常常会安装/移除/升级等,某些动作或许可能会导致 RPM 数据库 /var/lib/rpm/ 内的文件破损。那你该如何是好?可以使用 --rebuilddb 这个选项来重建一下数据库

rpm --rebuilddb # 重建数据库

7.4. YUM线上升级机制

yum : 通过分析rpm的标头数据 , 根据各个软件的相关性 作出属性相依时的解决方案 , 然后可以自动处理软件的相依属性问题 ,以解决软件安装或移除与升级的问题 ;

  1. 找到合适的yum server :
    1. 由于 distribution 必须要先释出软件,然后将软件放置于 yum 服务器上面,以提供用户端来要求安装与升级之用的。 因此我们想要使用 yum 的功能时,必须要先找到适合的 yum server 才行
    2. 每个 yum server 可能都会提供许多不同的软件功能,那就是“软件库” ; 因此你必须前往 yum server查询到相关的软件库 网址后 ,再继续处理
  1. 事实上 CentOS 在释出软件时已经制作出多部映射站台 (mirror site) 提供全世界的软件更新之用, 所以,理论上我们不需要处理任何设置值,只要能够连上 Internet,就可以使用 yum

7.4.1. 利用 yum 进行查询、安装、升级与移除功能

查询功能:yum [list|info|search|provides|whatprovides] 参数

如果想要查询利用 yum 来查询原版 distribution 所提供的软件,或已知某软件的名称,想知道该软件的功能, 可以利用 yum 相关的参数为:

[root@study ~]# yum [option] [查询工作项目] [相关参数]
选项与参数:
    [option]:主要的选项,包括有:
        -y :当 yum 要等待使用者输入时,这个选项可以自动提供 yes 的回应;
        --installroot=/some/path :将该软件安装在 /some/path 而不使用默认路径
		[查询工作项目] [相关参数]:这方面的参数有:
        search :搜寻某个软件名称或者是描述 (description) 的重要关键字;
        list :列出目前 yum 所管理的所有的软件名称与版本,有点类似 rpm -qa;
        info :同上,不过有点类似 rpm -qai 的执行结果;
        provides:从文件去搜寻软件!类似 rpm -qf 的功能!
        
范例一:搜寻磁盘阵列 (raid) 相关的软件有哪些?
[root@study ~]# yum search raid
Loaded plugins: fastestmirror, langpacks 			# yum 系统自己找出最近的 yum server
Loading mirror speeds from cached hostfile 		# 找出速度最快的那一部 yum server
 * base: ftp.twaren.net												# 下面三个软件库,且来源为该服务器!
 * extras: ftp.twaren.net
 * updates: ftp.twaren.net
....(前面省略)....
dmraid-events-logwatch.x86_64 : dmraid logwatch-based email reporting
dmraid-events.x86_64 : dmevent_tool (Device-mapper event tool) and DSO
iprutils.x86_64 : Utilities for the IBM Power Linux RAID adapters
mdadm.x86_64 : The mdadm program controls Linux md devices (software RAID arrays)
....(后面省略)....
# 在冒号 (:) 左边的是软件名称,右边的则是在 RPM 内的 name 设置 (软件名)
# 瞧!上面的结果,这不就是与 RAID 有关的软件吗?如果想了解 mdadm 的软件内容呢?

范例二:找出 mdadm 这个软件的功能为何
[root@study ~]# yum info mdadm
Installed Packages 				# <==这说明该软件是已经安装的了
Name : mdadm 							# <==这个软件的名称
Arch : x86_64 						# <==这个软件的编译架构
Version : 3.3.2 					# <==此软件的版本
Release : 2.el7 					# <==释出的版本
Size : 920 k 							# <==此软件的文件总容量
Repo : installed 					# <==软件库回报说已安装的
From repo : anaconda
Summary : The mdadm program controls Linux md devices (software RAID arrays)
URL : http://www.kernel.org/pub/linux/utils/raid/mdadm/
License : GPLv2+
Description : The mdadm program is used to create, manage, and monitor Linux MD (software
						: RAID) devices. As such, it provides similar functionality to the raidtools
						: package. However, mdadm is a single program, and it can perform
						: almost all functions without a configuration file, though a configuration
						: file can be used to help with some common tasks.
# 不要跟我说,上面说些啥?自己找字典翻一翻吧!拜托拜托!

范例三:列出 yum 服务器上面提供的所有软件名称
[root@study ~]# yum list
Installed Packages 			# <==已安装软件
GConf2.x86_64 3.2.6-8.el7 @anaconda
LibRaw.x86_64 0.14.8-5.el7.20120830git98d925 @base
ModemManager.x86_64 1.1.0-6.git20130913.el7 @anaconda
....(中间省略)....
Available Packages		# <==还可以安装的其他软件
389-ds-base.x86_64 1.3.3.1-20.el7_1 updates
389-ds-base-devel.x86_64 1.3.3.1-20.el7_1 updates
389-ds-base-libs.x86_64 1.3.3.1-20.el7_1 updates
....(下面省略)....
# 上面提供的意义为:“ 软件名称 版本 在那个软件库内 ”

范例四:列出目前服务器上可供本机进行升级的软件有哪些?
[root@study ~]# yum list updates <==一定要是 updates 喔!
Updated Packages
NetworkManager.x86_64 1:1.0.0-16.git20150121.b4ea599c.el7_1 updates
NetworkManager-adsl.x86_64 1:1.0.0-16.git20150121.b4ea599c.el7_1 updates
....(下面省略)....
# 上面就列出在那个软件库内可以提供升级的软件与版本!
范例五:列出提供 passwd 这个文件的软件有哪些
[root@study ~]# yum provides passwd
passwd-0.79-4.el7.x86_64 : An utility for setting or changing passwords using PAM
Repo : base
passwd-0.79-4.el7.x86_64 : An utility for setting or changing passwords using PAM
Repo : @anaconda
# 找到啦!就是上面的这个软件提供了 passwd 这个程序!
利用 yum 的功能,找出以 pam 为开头的软件名称有哪些?而其中尚未安装的又有哪些?


[root@study ~]# yum list pam*
Installed Packages
pam.x86_64 							1.1.8-12.el7 		  @anaconda
pam_krb5.x86_64 				2.4.8-4.el7 		  @base
Available Packages 																	# <==下面则是“可升级”的或“未安装”的
pam.i686 								1.1.8-12.el7_1.1  updates
pam.x86_64 							1.1.8-12.el7_1.1  updates
pam-devel.i686 					1.1.8-12.el7_1.1  updates
pam-devel.x86_64 				1.1.8-12.el7_1.1  updates
pam_krb5.i686 					2.4.8-4.el7 		  base
pam_pkcs11.i686 				0.6.2-18.el7 			base
pam_pkcs11.x86_64 			0.6.2-18.el7 			base

如上所示,所以可升级者有 pam 这两个软件,完全没有安装的则是 pam-devel等其他几个软件啰!

安装/升级功能:yum [install|update] 软件

[root@study ~]# yum [option] [安装与升级的工作项目] [相关参数]
选项与参数:
    install :后面接要安装的软件!
    update :后面接要升级的软件,若要整个系统都升级,就直接 update 即可
    
范例一:将前一个练习找到的未安装的 pam-devel 安装起来
[root@study ~]# yum install pam-devel
Loaded plugins: fastestmirror, langpacks # 首先的 5 行在找出最快的 yum server
Loading mirror speeds from cached hostfile
* base: ftp.twaren.net
* extras: ftp.twaren.net
* updates: ftp.twaren.net
Resolving Dependencies 								# 接下来先处理“属性相依”的软件问题
--> Running transaction check
---> Package pam-devel.x86_64 0:1.1.8-12.el7_1.1 will be installe
--> Processing Dependency: pam(x86-64) = 1.1.8-12.el7_1.1 for package: pam-devel-
				1.1.8-12.el7_1.1.x86_64
--> Running transaction check
---> Package pam.x86_64 0:1.1.8-12.el7 will be updated
---> Package pam.x86_64 0:1.1.8-12.el7_1.1 will be an update
--> Finished Dependency Resolution
Dependencies Resolved

# 由上面的检查发现到 pam 这个软件也需要同步升级,这样才能够安装新版 pam-devel 喔!
 

你不必知道软件在哪里,你不必手动下载软件,你也不必拿出原版光盘出来 mount 之后查询再安装!全部不需要,只要有了 yum 这个家伙,你的安装、升级再也不是什么难事!而且还能主动的进行软件的属性相依处理流程 .

移除功能:yum [remove] 软件

[root@study ~]# yum remove pam-devel
Loaded plugins: fastestmirror, langpacks
Resolving Dependencies			#  <==同样的,先解决属性相依的问题
--> Running transaction check
---> Package pam-devel.x86_64 0:1.1.8-12.el7_1.1 will be erased
--> Finished Dependency Resolution
Dependencies Resolved
==========================================================================================
Package 				Arch 			Version 				Repository		 Size
==========================================================================================
Removing:
pam-devel 		x86_64 		1.1.8-12.el7_1.1 		@updates 		528 k
Transaction Summary
==========================================================================================
Remove 1 Package 					# 还好!没有相依属性的问题,仅移除一个软件!
Installed size: 528 k
Is this ok [y/N]: y
Downloading packages:
Running transaction check
Running transaction test
Transaction test succeeded
Running transaction
	Erasing : pam-devel-1.1.8-12.el7_1.1.x86_64 1/1
	Verifying : pam-devel-1.1.8-12.el7_1.1.x86_64 1/1
Removed:
	pam-devel.x86_64 0:1.1.8-12.el7_1.1
Complete!

7.4.2. yum 的配置文件

虽然 yum 是你的主机能够连线上 Internet 就可以直接使用的,不过,由于 CentOS的映射站台可能会选错

所以可能需要修改配置文件 :

[root@study ~]# vim /etc/yum.repos.d/CentOS-Base.repo
[base]
name=CentOS-$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
#baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7

如上所示,仅列出 base 这个软件库内容而已,其他的软件库内容请自行查阅 ;

需要注意的是:

  1. [base]:代表软件库的名字!中括号一定要存在,里面的名称则可以随意取。但是不能有两个相同的软件库名称, 否则 yum 会不晓得该到哪里去找软件库相关软件清单文件。
  2. name:只是说明一下这个软件库的意义而已,重要性不高!
  3. mirrorlist=:列出这个软件库可以使用的映射站台,如果不想使用,可以注解到这行;
  4. baseurl=:这个最重要,因为后面接的就是软件库的实际网址!
    1. mirrorlist 是由 yum程序自行去捉映射站台, baseurl 则是指定固定的一个软件库网址!我们刚刚找到的网址放到这里来啦!
  1. enable=1:就是让这个软件库被启动。如果不想启动可以使用 enable=0 喔!
  2. gpgcheck=1:这就是指定是否需要查阅 RPM 文件内的数码签章!
  3. gpgkey=:就是数码签章的公钥档所在位置!使用默认值即可
测试一下配置的这些软件库是否正常的运行中

范例一:列出目前 yum server 所使用的软件库有哪些?
[root@study ~]# yum repolist all
repo id 											repo name 										status
C7.0.1406-base/x86_64 				CentOS-7.0.1406 - Base 				disabled
C7.0.1406-centosplus/x86_64 	CentOS-7.0.1406 - CentOSPlus 	disabled
C7.0.1406-extras/x86_64 			CentOS-7.0.1406 - Extras 			disabled
C7.0.1406-fasttrack/x86_64 		CentOS-7.0.1406 - CentOSPlus 	disabled
C7.0.1406-updates/x86_64 			CentOS-7.0.1406 - Updates 		disabled
base 													CentOS-7 - Base 							enabled: 8,652
base-debuginfo/x86_64 				CentOS-7 - Debuginfo 					disabled
base-source/7 								CentOS-7 - Base Sources 			disabled
centosplus/7/x86_64 					CentOS-7 - Plus 							disabled
centosplus-source/7 					CentOS-7 - Plus Sources 			disabled
cr/7/x86_64 									CentOS-7 - cr 								disabled
extras 												CentOS-7 - Extras 						enabled: 181
extras-source/7 							CentOS-7 - Extras Sources 		disabled
fasttrack/7/x86_64 						CentOS-7 - fasttrack 					disabled
updates 											CentOS-7 - Updates 						enabled: 1,302
updates-source/7 							CentOS-7 - Updates Sources 		disabled
repolist: 10,135
# 上面最右边有写 enabled 才是有启动的!由于 /etc/yum.repos.d/
# 有多个配置文件,所以你会发现还有其他的软件库存在。

7.4.3. 修改软件库产生的问题与解决之道

由于我们是修改系统默认的配置文件,事实上,我们应该要在 /etc/yum.repos.d/ 下面新建一个文件, 该扩展名必须是 .repo 才行!但因为我们使用的是指定特定的映射站台,而不是其他软件开发商提供的软件库, 因此才修改系统默认配置文件。

但是可能由于使用的软件库版本有新旧之分,你得要知道, yum 会先下载软件库的清单到本机的 /var/cache/yum 里面去!那我们修改了网址却没有修改软件库名称 (中括号内的文字), 可能就会造成本机的清单与 yum 服务器的清单不同步,此时就会出现无法更新的问题了!

那怎么办啊?很简单,就清除掉本机上面的旧数据即可!需要手动处理吗?不需要的, 通过 yum 的 clean 项目来处理即可!

[root@study ~]# yum clean [packages|headers|all]
选项与参数:
    packages:将已下载的软件文件删除
    headers :将下载的软件文件开始删除
    all :将所有软件库数据都删除!
    
范例一:删除已下载过的所有软件库的相关数据 (含软件本身与清单)
[root@study ~]# yum clean all

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值