基础概念
-
单一目录树
对比windows从不同的盘符出发寻找文件,Linux一切都是从
/根目录开始。Linux维护了一个单目录树文件结构,所有的内容都在这个目录树上。graph TB 1["/"] --> 2["boot"] 1["/"] --> 3["home"] 1["/"] --> 4["usr"] 1["/"] --> 5["root"] 1["/"] --> 6["dev"] 1["/"] --> 7["etc"] 1["/"] --> 8["var"] 1["/"] --> 9["tmp"] 1["/"] --> 10["bin"] 1["/"] --> 11[...] 4["usr"] --> 12["bob"]k所谓的盘符了,只有分区,分区实际会被当作设备,默认会在/dev下,比如IDE接口的硬盘会显示/dev/sda,/dev/sdb等,如果再插入U盘,根据系统查找到存储设备的顺序,此时显示/dev/sdc。
在
/dev下的设备是根据检测的存储设备顺序自动显示的,此时能获取设备的一些信息,但是这里显示的是设备文件信息,并不具备存入文件功能,要想使设备能够存储文件,需要用到挂载mount。 -
一切皆文件
linux和windows不同,有个重要概念就是一切皆文件,比如设备、进程、套字节等也是文件,好处是可以使用操作文件的方法来使用他们,实际就是统一了操作。
文件类型:
类型 简称 描述 普通文件 -,Normal File 如mp4、pdf、html log; 用户可以根据访问权限对普通文件进行查看、更改和删除,包括 纯文本文件(ASCII);二进制文件(binary);数据格式的文件(data);各种压缩文件.第一个属性为 [-] 目录文件 d,directory file /usr/ /home/ 目录文件包含了各自目录下的文件名和指向这些文件的指针,打开目录事实上就是打开目录文件,只要有访问权限,就可以随意访问这些目录下的文件。能用#cd命令进入的。第一个属性为[d],例如 [drwxrwxrwx] 硬链接 -,hard links 若一个inode号对应多个文件名,则称这些文件为硬链接。硬链接就是同一个文件使用了多个别名删除时,只会删除链接, 不会删除文件; 硬链接的局限性:1.不能引用自身文件系统以外的文件,即不能引用其他分区的文件;2.无法引用目录; 符号链接(软链接) l,symbolic link 若文件用户数据块中存放的内容是另一文件的路径名的指向,则该文件就是软连接,克服jj链接的局限性, 类似于快捷方式,使用与硬链接相同。 字符设备文件 c,char 文件一般隐藏在/dev目录下,在进行设备读取和外设交互时会被使用到 即串行端口的接口设备,例如键盘、鼠标等等。第一个属性为 [c]。 /dev/tty的属性是 crw-rw-rw-,注意前面第一个字 c,这表示字符设备文件 | 块设备文件 | b,block | 存储数据以供系统存取的接口设备,简单而言就是硬盘。 # /dev/hda1 的属性是 brw-r—– ,注意前面的第一个字符是b,这表示块设备,比如硬盘,光驱等设备 系统中的所有设备要么是块设备文件,要么是字符设备文件,无一例外 |
| FIFO管道文件 | p,pipe | 管道文件主要用于进程间通讯。FIFO解决多个程序同时存取一个文件所造成的错误。比如使用mkfifo命令可以创建一个FIFO文件,启用一个进程A从FIFO文件里读数据,启动进程B往FIFO里写数据,先进先出,随写随读。 # pipe |
| 套接字 | s,socket | 以启动一个程序来监听客户端的要求,客户端就可以通过套接字来进行数据通信。用于进程间的网络通信,也可以用于本机之间的非网络通信,第一个属性为 [s],这些文件一般隐藏在/var/run目录下,证明着相关进程的存在 |
-
挂载
将硬盘\分区挂载到某个目录下,这样该目录下存入的所有内容,都将直接存入该设备里。
**注意:**如果挂载的目录是非空目录,挂载后这些内容将会隐藏(不是删除),取消挂载后才能显示。
分区概念
目前主要有2种分区格式MBR与GPT。在系统安装时可以进行选择,一般小于2T的硬盘会默认使用MBR,但是可以使用inst.gpt选项强制开启使用GPT分区。
MBR
硬盘的第一个扇区512bytes记录了开机管理程序和分区表
- 主要启动记录区(Master Boot Record, MBR):可以安装开机管理程序的地方,有 446 bytes
- 分区表(partition table):记录整颗硬盘分区的状态,有 64 bytes
由于分区表只有64bytes,所以最多只能有4个分区记录,这4个分区记录被称为主要(primary)和延申(Extended)分区槽。
是不是意味者使用MBR就最多只能分4个区,当然不是,可以通过延申分区实行逻辑分区。
延申分区并不是常规意义上的分区,他仅仅是指向下一个逻辑分区的指针,且延申分区并不是连续的,他分布在每一个逻辑分区前面的几个扇区。所以一般操作系统会限制只有一个延申分区,延申分区的每一块都指向一个逻辑分区和下一个延申分区表。
由于MBR只有第一个扇区记录了分区信息,如果第一个扇区坏了,那整个硬盘也就废了。
MBR使用4个字节来存储所有的扇区数量,也就是最多识别2^32^个扇区,每个扇区512bytes,也就是MBR分区格式最多支持2TB容量的硬盘,2TB后面的扇区无法被分配地址,也就无法管理了。
GPT
由于MBR的限制性,所以后面又出现了更高级的GPT分区格式
以前的扇区都是512bytes,后面出现4k的扇区,为了兼容所有的硬盘,所以出现了所谓的逻辑块地址(LBA),预设为512bytes。
MBR使用第一个扇区记录分区信息,而GPT使用34个LBA来记录分区信息,而且还会使用最后33个LBA来备份分区信息,所以安全性大大的增强了。
- LBA0主要存放了第一阶段的开机管理程序和一个GPT的标志,表示此硬盘使用的是GPT分区格式。
- LBA1存放了分区表的位置、大小,以及备份用的GPT分区位置。同时放置了分区表的校验机制码。
- LBA2-34存放了分区记录,每个LBA,4个分区记录,可以分4*32=128笔分区记录。每个LBA有512bytes,每个分区记录使用128bytes,GPT在每个记录中使用64bits来存放扇区号码,也就是2^64^ * 512bytes是每个分区能识别的最大容量。
- 最后一个LBA用来备份LBA1
- 倒数第2个LBA-倒数第34个LBA用来备份LAB2-34
linux系统在安装的时候,可以使用自定义模式进行分区,并挂载到相关目录上。
当硬盘大小较小时默认采用MBR分区格式,如果强制使用GPT分区,需要在安装时,将光标移动到install上,然后tab,在参数后面输入inst.gpt,然后enter安装
分区大小
如何设计分区,和这台服务器的用处有关。
-
懒人分区法:
给
/一个分区,swap一个分区就可以了。简单粗暴。 -
常规分区法:
- /boot
- /
- /home
- /var
- /usr
- Swap
这些目录可能读写比较频繁,所以最好是从根目录独立出来,就算这些分区出了问题也不至于影响根目录下的数据,方便救援。
注意:使用MBR分区时,会在第一个扇区后面的扇区存放一些复杂的boot loader(第2阶段启动程序),但是GPT中没有这样的扇区(第一个扇区后面的扇区用来存放分区记录了),所以需要一个单独的bios boot分区用来存放这些复杂的启动程序,一般为2M即可。
GPT第一个扇区只有第一阶段引导程序,本质上就是记录了boot程序的位置,所以需要一个单独的boot分区。而MBR在第一个扇区就已经有开机程序了,所以并不需要boot分区。
分区时相关概念
-
标准分区,就是常规的分区,类似/dev/sda1,/dev/vda1(虚拟机下)
-
LVM,弹性增加减少容量。实际就是逻辑卷,逻辑卷的大小可以动态调整。(和逻辑分区不是一个概念,逻辑分区大小不能改变)
graph BT 11[硬盘/分区] --> 21["PV(物理卷)"] 12[硬盘/分区] --> 22["PV(物理卷)"] 13[硬盘/分区] --> 23["PV(物理卷)"] 14[硬盘/分区] --> 24["PV(物理卷)"] 21 --> 31("VG(卷组)") 22 --> 31("VG(卷组)") 23 --> 31("VG(卷组)") 24 --> 31("VG(卷组)") 31 --> 41["LV(逻辑卷)1"] 31 --> 42[LV2] 31 --> 43[LV3] 31 --> 44[LV4]原理:
- 硬盘或分区格式为PV,一个PV包含多个PE,一个PE预设大小为4M
- VG的作用实际就是封装PE,一个VG可以包含多个不同来源的PE,所以VG的大小肯定是4M的整数倍
- PV和VG是对底层硬盘的抽象,还不能被直接使用,需要创建LV,LV是基于VG中的PE创建,所有LV肯定也是PE的大小整数倍,而且组成LV的PE可能来源于不同的PV,也就是不同的硬盘或分区。
- LV格式化文件系统,并挂载使用
- LV的动态扩充缩减实际就是增加或减少PE的数量,并且不会影响已有的数据
-
LVM紧张供应,相比LVM分配一个固定的容量,这个类型,容量完全取决于内容大小。
-
swap,硬盘仿真内存,内存不够时,将内存中不活跃的内容写进swap中,这个分区不用进行挂载
-
xfs,比ext2/ext3/ext4更先进的文件系统,一般用这个
-
vfat,同时兼容windows和linux的文件系统
命令帮助文档
-
--help: 查看命令的使用 -
man command: 更详细的使用说明man出来的信息中,在命令指令名称后面还有一个数字,不同的数字代表不同的含义:
- 1 用户在 shell 环境中可以操作的指令或可执行文件
- 2 系统核心可呼叫的函数与工具等
- 3 一些常用的函数(function)与函式库(library),大部分为 C 的函式库(libc)
- 4 装置文件的说明,通常在/dev 下的文件
- 5 配置文件或者是某些文件的格式
- 6 游戏(games)
- 7 惯例与协议等,例如 Linux 文件系统、网络协议、ASCII code 等等的说明
- 8 系统管理员可用的管理指令
由于man出来的信息很多,有时候需要进行翻页或者查询
按键 进行工作 空格键 向下翻一页 [Page Down] 向下翻一页 [Page Up] 向上翻一页 [Home] 去到第一页 [End] 去到最后一页 /string 向『下』搜寻 string 这个字符串,如果要搜寻 vbird 的话,就输入 /vbird ?string 向『上』搜寻 string 这个字符串 n, N 利用 / 或 ? 来搜寻字符串时,可以用 n 来继续下一个搜寻 (不论是 / 或 ?) ,可以利用 N 来进行『反向』搜寻。举例来说,我以 /vbird 搜寻 vbird 字符串, 那么可以 n 继续往下查询,用 N 往上查询。若以 ?vbird 向上查询 vbird 字符串, 那我可以用 n 继续『向上』查询,用 N 反向查询 q 结束这次的 man page
文件权限
权限说明
通过ls -al命令可以查看当前目录下的文件结构和权限
比如:
drwxr-xr-- 5 foo foos 4096 日期 文件名
[ 权限 ] [连结][拥有者][群组][文件容量][ 修改日期 ] [ 文件名 ]- 第一个字符表示文件类型,d是目录。
- d后面是权限,分为三组,每组由
rwx组成,代表读、写、执行权限,没有相关权限用-代替,顺序不会改变,比如只有可执行权限,结构就是--x。这3组权限分别代表拥有者(owner),群组(group),其他人(others)的权限,上述例子中,拥有者是foo,拥有该目录的rwx权限,群组是foos,拥有该目录的r-x读、执行权限,其他人拥有r--读权限。 - 5表示链接数,即这个文件对应的i-node被多少文件关联。
- foo 拥有者owner
- foos 群组group
- 4096 大小,默认单位bytes
- 日期,修改日期
注意:linux中能否执行只和权限x有关,和扩展名无关(linux中扩展名主要作用是进行一定程度上的文件标识),至于执行有没有效果和文件内容有关。
修改权限
修改owner或者group时,owner必须在/etc/passwd中存在,group必须在/etc/group中存在,否则报错。
-
chgrp: 修改文件群组chgrp [-R] 组名 文件或目录 # -R 表示递归修改,修改目录下的所有文件或目录的群组 -
chown: 修改拥有者chown [-R] 用户名 文件或目录 chown [-R] 用户名:组名 文件或目录 # 可以顺便修改组名 -
chmod: 修改权限-
通过数字类型改变权限
r-4,w-2,x-1,所以7就代表所有权限
chmod [-R] 750 文件或目录 # owner权限为7 = rwx,group权限为5 = r-x,others权限0 = --- -
通过符号类型改变权限
u=ownerg=groupo=othersa=all然后通过+,-,=改变权限
+添加某个权限-删除某个权限=赋予一组权限,没有的权限不写,不要用-号替代chmod [-R] o+x 文件或目录 # others添加执行权限 chmod [-R] a+w 文件或目录 # 所有人增加写权限 chmod [-R] u=rwx,g=rx,o=r # 授权对应的权限 chmod [-R] u=rwx,go=rx # group和other的权限相同,可以合并写
-
文件和目录在权限上的区别
-
文件:
r: 读取文件内容w: 修改文件内容x: 执行文件的内容注意:文件本身的权限,无法删除文件本身
-
目录
r: 读取目录的文件结构,可以使用ls命令w: 可以修改目录结构的权限。包括:-
建立新的文件或目录
-
删除文件或目录(不管是否拥有该目录或文件的权限)
# 比如/home/bob/1.txt 权限为 -rwx------ root root # 用户bob没有1.txt任何权限,但是bob有/home/bob目录的所有权限,此时可以删除1.txt rm /home/bob/1.txt # 成功删除 -
重命名
-
移动位置
x: 进入目录的权限 -
常用目录说明
- 所有用户皆可用的系统程序放在
/bin - 超级用户才能使用的系统程序放在
/sbin - 所有用户都可用的系统repository提供的应用程序放在
/usr/bin - 超级用户才能使用的系统repository提供的应用程序放在
/usr/sbin - 所有用户都可用的与本地机器无关的程序存放在
/usr/local/bin - 超级用户才能使用的与本地机器无关的程序存放在
/usr/local/sbin
/boot: 开机程序/dev: 设备文件,比较重要的有/dev/null, /dev/zero, /dev/tty/etc: 系统主要的配置文件几乎都放置在这个目录内,比较重要的文件有:/etc/modprobe.d/, /etc/passwd,/etc/fstab, /etc/issue 等等/run: 系统开机后所产生的各项信息/srv: 是一些网络服务启动之后,这些服务所需要取用的数据目录。 常见的服务例如 WWW, FTP 等等。举例来说,WWW 服务器需要的网页资料就可以放置在/srv/www/里面。/usr: 类似 Windows 系统的『C:\Windows\ (当中的一部份) + C:\Program files\』这两个目录的综合体。软件安装的位置。/usr/local: 管理员自行安装的程序位置,该目录下也有bin,sbin,etc,include,lib等目录/var: 主要存放一些运行时改变的文件,比如/var/cache/缓存、/var/log/日志等。/var/lib/,程序运行过程中需要用到/产生的数据文件,各程序都应该有自己的次级目录,比如mysql,/var/lib/mysql/存储mysql数据文件。/proc: 数据在内存中,存放一些进程数据,比较重要的文件例如:/proc/cpuinfo, /proc/dma, /proc/interrupts,/proc/ioports, /proc/net/* 等等(这也是一切皆文件的体现)/sys: 和/proc类似,内核与系统硬件信息较相关的信息/media: 放置可移除装置比如光盘等/mnt: 临时挂载用
环境变量
环境变量分为:
-
全局环境变量
可以被所有进程访问。
-
局部环境变量
只能在进程内部访问,进程的环境变量来源于继承的父进程和本身进程,以及全局环境变量。
比如shell进程启动时会继承一部分环境变量,然后可以在shell中设置环境变量(临时export,每次都生效可以修改.bashrc),这样通过shell中指令启动的进程,就会继承shell的环境变量。
shell得到指令也是去$PATH环境变量中的路径中寻找去执行,这和windows是一样的,windows的环境变量也是类似的。
$PATH为linux比较特殊的环境变量,通过设置环境变量中的路径,可以让你在任何目录中使用相关命令,比如ls命令,在/bin/ls下,但是你在其他目录中完全可以使用ls,是因为/bin在环境变量中。
查看环境变量,多个路径用 : 隔开
echo $PATH
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/foo/.local/bin:/home/foo/bin还可以添加环境变量
PATH="${PATH}:/XXX"文件与目录
目录操作
-
cd: 切换目录cd - # 上一个目录 cd ~ # 当前用户的Home目录 -
pwd: 显示当前目录pwd -P # 显示真实目录,比如link文件的真实目录 -
mkdir: 创建空目录mkdir [-mp] 目录 # -m 不使用预设权限,直接设置权限 mkdir -m 771 /home/foo/test # -p 递归建立 mkdir -p /home/foo/test/test1/test2 -
rmdir: 删除空目录rmdir test # 提示删不掉,应为不是空目录 rmdir -p test/test1/test2 # 会删掉test test1 test2递归删掉空目录注意:
-p只能递归删掉空目录,如果还有其他内容,是删不掉的,需要用到rm -r test,比较危险。
文件操作
操作文件
-
ls: 列举目录中的所有目录和文件。这应该是使用频率最高的命令了,有很多参数,常见的有ls -al[root@study ~]# ls [-aAdfFhilnrRSt] 文件名或目录名称 .. [root@study ~]# ls [--color={never,auto,always}] 文件名或目录名称 .. [root@study ~]# ls [--full-time] 文件名或目录名称 .. 选项与参数: -a :全部的文件,连同隐藏档( 开头为 . 的文件) 一起列出来(常用) -A :全部的文件,连同隐藏档,但不包括 . 与 .. 这两个目录 -d :仅列出目录本身,而不是列出目录内的文件数据(常用) -f :直接列出结果,而不进行排序 (ls 预设会以档名排序!) -F :根据文件、目录等信息,给予附加数据结构,例如: *:代表可执行文件; /:代表目录; =:代表 socket 文件; |:代表 FIFO 文件; -h :将文件容量以人类较易读的方式(例如 GB, KB 等等)列出来; -i :列出 inode 号码,inode 的意义下一章将会介绍; -l :长数据串行出,包含文件的属性与权限等等数据;(常用) -n :列出 UID 与 GID 而非使用者与群组的名称 (UID 与 GID 会在账号管理提到!) -r :将排序结果反向输出,例如:原本档名由小到大,反向则为由大到小; -R :连同子目录内容一起列出来,等于该目录下的所有文件都会显示出来; -S :以文件容量大小排序,而不是用档名排序; -t :依时间排序,而不是用档名。 --color=never :不要依据文件特性给予颜色显示; --color=always :显示颜色 --color=auto :让系统自行依据设定来判断是否给予颜色 --full-time :以完整时间模式 (包含年、月、日、时、分) 输出 --time={atime,ctime} :输出 access 时间或改变权限属性时间 (ctime) 而非内容变更时间 (modification time) -
cp: 复制命令,除了可以复制文档、目录,还可以更新文件,建立link,重命名等[root@study ~]# cp [-adfilprsu] 来源文件(source) 目标文件(destination) [root@study ~]# cp [options] source1 source2 source3 .... directory 选项与参数: -a :相当于 -dr --preserve=all 的意思,至于 dr 请参考下列说明;(常用) -d :若来源文件为链接文件的属性(link file),则复制链接文件属性而非文件本身; -f :为强制(force)的意思,若目标文件已经存在且无法开启,则移除后再尝试一次; -i :若目标文件(destination)已经存在时,在覆盖时会先询问动作的进行(常用) -l :进行硬式连结(hard link)的连结档建立,而非复制文件本身; -p :连同文件的属性(权限、用户、时间)一起复制过去,而非使用默认属性(备份常用); -r :递归持续复制,用于目录的复制行为;(常用) -s :复制成为符号链接文件 (symbolic link),亦即『快捷方式』文件; -u :destination 比 source 旧才更新 destination,或 destination 不存在的情况下才复制。 --preserve=all :除了 -p 的权限相关参数外,还加入 SELinux 的属性, links, xattr 等也复制了。 最后需要注意的,如果来源档有两个以上,则最后一个目的文件一定要是『目录』才行!==注意:目标目录存在,则目录或文件会直接复制到该目录下;目标目录或文件不存在,则视同重命名,不管是目录还是文件。如果只是想复制目录下的文件,而非目录本身,后面加
/,比如/etc是复制etc整个目录,/etc/是复制etc下的所有文件。== -
rm: 删除目录或文件[root@study ~]# rm [-fir] 文件或目录 选项与参数: -f :就是 force 的意思,忽略不存在的文件,不会出现警告讯息; -i :互动模式,在删除前会询问使用者是否动作 -r :递归删除啊!最常用在目录的删除了!这是非常危险的选项!!! -
mv: 移动目录或文件,也可以重命名[root@study ~]# mv [-fiu] source destination [root@study ~]# mv [options] source1 source2 source3 .... directory 选项与参数: -f :force 强制的意思,如果目标文件已经存在,不会询问而直接覆盖; -i :若目标文件 (destination) 已经存在时,就会询问是否覆盖! -u :若目标文件已经存在,且 source 比较新,才会更新 (update)操作类似cp,注意事项也相同。
-
basename,dirname取得文件或目录的名称,目录名
ls文件时,可以使用通配符,有点类似正则,比如test*,test开头的,test[123],表示test1或test2或test3
查看文件内容
-
cat: 由第一行开始显示文件内容[root@study ~]# cat [-AbEnTv] 选项与参数: -A :相当于 -vET 的整合选项,可列出一些特殊字符而不是空白而已; -b :列出行号,仅针对非空白行做行号显示,空白行不标行号! -E :将结尾的断行字符 $ 显示出来; -n :打印出行号,连同空白行也会有行号,与 -b 的选项不同; -T :将 [tab] 按键以 ^I 显示出来; -v :列出一些看不出来的特殊字符 -
tac: 从最后一行开始显示,可以看出 tac 是 cat 的倒着写! -
nl: 显示的时候,顺道输出行号![root@study ~]# nl [-bnw] 文件 选项与参数: -b :指定行号指定的方式,主要有两种: -b a :表示不论是否为空行,也同样列出行号(类似 cat -n); -b t :如果有空行,空的那一行不要列出行号(默认值); -n :列出行号表示的方法,主要有三种: -n ln :行号在屏幕的最左方显示; -n rn :行号在自己字段的最右方显示,且不加 0 ; -n rz :行号在自己字段的最右方显示,且加 0 ; -w :行号字段的占用的字符数。 -
more: 一页一页的显示文件内容 -
less: 与 more 类似,但是比 more 更好的是,他可以往前翻页!- 空格键 :向下翻动一页;
- [pagedown]:向下翻动一页;
- [pageup] :向上翻动一页;
- /字符串 :向下搜寻『字符串』的功能;
- ?字符串 :向上搜寻『字符串』的功能;
- n :重复前一个搜寻 (与 / 或 ? 有关!)
- N :反向的重复前一个搜寻 (与 / 或 ? 有关!)
- g :前进到这个资料的第一行去;
- G :前进到这个数据的最后一行去 (注意大小写);
- q :离开 less 这个程序;
-
head: 只看头几行[root@study ~]# head [-n number] 文件 -
tail: 只看尾巴几行[root@study ~]# tail [-n number] 文件 选项与参数: -n :后面接数字,代表显示几行的意思 -f :表示持续侦测后面所接的档名,要等到按下[ctrl]-c 才会结束tail 的侦测 -
od: 以二进制的方式读取文件内容!比如/etc/passwd
[root@study ~]# 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 ;
建立文件
touch: 建立空文件或改变文件时间
一个文件有3个时间
- modification time (mtime):
当该文件的『内容数据』变更时,就会更新这个时间!内容数据指的是文件的内容,而不是文件的属性或
权限。
ls -l显示的就是mtime。 - status time (ctime): 当该文件的『状态(status)』改变时,就会更新这个时间,举例来说,像是权限与属性被更改了,都会更新 这个时间
- access time (atime): 当『该文件的内容被取用』时,就会更新这个读取时间(access)。举例来说,我们使用cat 去读取 /etc/man_db.conf , 就会更新该文件的atime 了
[root@study ~]# touch [-acdmt] 文件
选项与参数:
-a :仅修订 access time;
-c :仅修改文件的时间,若该文件不存在则不建立新文件;
-d :后面可以接欲修订的日期而不用目前的日期,也可以使用 --date="日期或时间"
-m :仅修改 mtime ;
-t :后面可以接欲修订的时间而不用目前的时间,格式为[YYYYMMDDhhmm]==注意:不使用-d,-t指定时间,默认就是当前时间。如果不跟-a,-m就是同时修改这2个时间。注意无法修改ctime,因为ctime记录的是状态修改时间,比如修改了atime,mtime那么ctime也会记录这个修改的时间。==
默认权限
使用umask可以查看预设的权限
umask # 以数字的形式列出权限,默认是0022,注意这里的数字是扣除的意思,扣除0那就是权限7,扣除2就是r-x
umask -S # 更直观的方式查看权限如果要改变,也很容易
umask 002 # group的权限和owner改成一样==注意:预设的情况下文件没有x权限,只有rw-,最大权限为6,就算是0,没有扣除也是6==
umask会返回4位数,第一位实际是特殊权限SUID,SGID,SBIT。
隐藏属性
-
chattr: 设置隐藏属性[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 而已==
-
lsattr: 隐藏属性的查看[root@study ~]# lsattr [-adR] 文件或目录 选项与参数: -a :将隐藏文件的属性也秀出来; -d :如果接的是目录,仅列出目录本身的属性而非目录内的文件名; -R :连同子目录的数据也一并列出来!
特殊权限
除了正常rwx外,有时候会见到s和t的权限代码
root@LAPTOP-GH95O3K5:~# ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 May 28 2020 /usr/bin/passwd-
SUID: 当s出现在owner的权限组上时,就是SUID。表示的意义是,当你对这个文件拥有
x权限时,在==执行期间==将获得owner的权限,如果执行过程中涉及其他文件,也将以owner的身份获得相关授权。此权限仅对二进制文件生效。
-
SGID: 当s出现在group的权限组上时,就是SGID。可以在文件、目录上使用。
当在文件上使用时,该文件必须为二进制文件,且执行者如果拥有
x权限,那么执行者将自动被加入该文件的群组,相当于此时有了这个群组的权限。当在目录上使用时,如果使用者拥有
r-x则可以进入该目录,同时该使用者被加入该目录群组,如果该使用者还拥有w权限,那么新建的文件或目录的群组就是当前进入的这个目录的群组,因为此时已经加入了这个群组。 -
SBITroot@LAPTOP-GH95O3K5:~# ls -dl /tmp drwxrwxrwt 4 root root 4096 Jun 17 11:40 /tmp仅对目录有效,放在others权限组上。
当使用者拥有
wx权限时,在这个目录下建立的文件或目录,只有使用者和root可以删除。
如何授予这些权限:
-
数字模式
SUID - 4
SGID - 2
SBIT - 1
在原来的数字授权模式前,可以加上上面的数字、数字和。
# 比如 -rwsr-xr-x的权限 chmod 4755 文件 # 比如 -rwsr-sr-x的权限 chmod 6755 文件 # 比如 -rwxr-xr-t的权限 chmod 1755 文件 -
符号模式
chmod u+s 文件 chmod g+s 文件 chmod o+t 文件 chmod u=rwxs 文件
还有个特殊情况S,T大写的S,T表示为空,比如
chmod 7666 文件 # rwSrwSrwT,本身权限666没有x执行权,加入s s t就没有效果了SUID,SGID是怎么实现的呢,实际上就是命令在执行时,bash会fork一个子进程来执行这个命令,此时子进程的权限提升(用户提升为owner,pstree可查看),从而达到能够执行这个命令的目的。
文件类型观察
file: 查看文件类型
root@LAPTOP-GH95O3K5:~# file .bashrc
.bashrc: ASCII text
root@LAPTOP-GH95O3K5:~# file /usr/bin/passwd
/usr/bin/passwd: setuid ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fa23c6b4e145d9bb5487c6cb7adb9338c5ef4fb9, for GNU/Linux 3.2.0, stripped文件与指令的搜索
-
which: 会去PATH下找指令[root@study ~]# which [-a] command 选项或参数: -a :将所有由 PATH 目录中可以找到的指令均列出,而不止第一个被找到的指令名称 -
whereis: 搜索文件,去特定的目录下找[root@study ~]# whereis [-bmsu] 文件或目录名 选项与参数: -l :可以列出 whereis 会去查询的几个主要目录而已 -b :只找 binary 格式的文件 -m :只找在说明文件 manual 路径下的文件 -s :只找 source 来源文件 -u :搜寻不在上述三个项目当中的其他特殊文件 -
locate: 利用数据库查询[root@study ~]# locate [-ir] keyword 选项与参数: -i :忽略大小写的差异; -c :不输出档名,仅计算找到的文件数量 -l :仅输出几行的意思,例如输出五行则是 -l 5 -S :输出 locate 所使用的数据库文件的相关信息,包括该数据库纪录的文件/目录数量等 -r :后面可接正规表示法的显示方式实际是去
/var/lib/mlocate这个数据库查找,但是数据库是每天更新一次,所以可能会出现找不到,但实际存在的情况。可以在查找之前updatedb更新下。 -
find: find
文件系统
并不是一个分区一个文件系统,LVM技术可以让一个分区格式化为多个文件系统,也可以让多个分区合并为一个文件系统。
概念
-
inode: 每个文件或目录都有且仅有一个inode;inode中存储的是文件或目录的属性,包括权限、时间等等,还有实际存储数据的block信息。 -
block: inode指向block,表示实际存储数据的地方,一个block只能存放一个文件,如果block大小为4k,文件大小为2k,那么另外2k相当于浪费了,如果将block设置的很小,那么一个文件又会分散到过多的block中,造成查找效率过低,所以要根据使用途径设计好block大小。 -
superblock: 每个文件系统都会有唯一一个superblock用于记载整个文件系统所有的汇总信息,比如inode,block总数量,剩余数量等信息 -
block bitmap: 通过他可以寻找空block -
inode bitmap: 通过他可以寻找空inode -
block group: 由于inode和block的数量很多,全放在一起不好管理,所以会采取分组的形式,每组都有自己的inode,block,block bitmap,inode bitmap,甚至还有superblock,只不过除了第一组的superblock,后面其他组的superblock如果存在也是对第一组的备份。superblock放在group的0号block,紧跟着的是block bitmap和inode bitmap,再然后是inode table也就是存储inode的block,再后面才是正常能被使用block
-
文件的block中存储的是实际数据,目录的block中存储的是目录下的文件名以及对应的inode。
ext系统在格式化时,会分配所有的inode和block,即大小和数量都固定了,所以在格式化大容量的存储设备时会很慢。
而xfs格式,是动态分配的,也就是需要的时候才会分配inode和block,速度会快的多。目前一般预设的文件系统为xfs。
XFS
xfs拥有ext4的所有功能。和ext主要区别是:
- 动态分配inode,block
- block容量可由512bytes - 64K 调配
graph TB 1[xfs] --> 2[资料区-data section] 1[xfs] --> 3[活动登录区-log section] 1[xfs] --> 4[实时运作区-realtime section] 2[资料区-data section] --> 5[group1] 5[group1] --> 6[media] 5[group1] --> 8[inode] 5[group1] --> 9[block] 2[资料区-data section] --> 10[group2] 2[资料区-data section] --> 11[group...] 6[metadata] --> 12[superblock] 6[metadata] --> 13[block bitmap] 6[metadata] --> 14[inode bitmap]
- 资料区类似ext,一样的分组,每组都有superblock,inode,block,还有剩余空间管理机制,能动态更新metadata数据
- 活动登录区就是日志系统,用来记录文件的变化,由于这个区域会频繁的写入,硬盘工作频繁,xfs允许指定外部硬盘作为日志区,比如外接一个SSD硬盘。
- 实时运作区,可以看成一个临时区域,当要建立文件时,xfs会在这个区域找到一个或多个extent区块,然后将文件放置在这个区块中,等到分配完毕,再写入资料区的inode,block。
可以通过xfs_info命令查看xfs文件系统superblock
xfs_info 挂载点|装置文件名一个系统通常不会只有一个文件系统,多个文件系统怎么传递数据呢,通过VFS,虚拟文件系统。
文件系统的操作
-
df: 文件系统的硬盘整体使用量[root@study ~]# df [-ahikHTm] [目录或文件名] 选项与参数: -a :列出所有的文件系统,包括系统特有的 /proc 等文件系统; -k :以 KBytes 的容量显示各文件系统; -m :以 MBytes 的容量显示各文件系统; -h :以人们较易阅读的 GBytes, MBytes, KBytes 等格式自行显示; -H :以 M=1000K 取代 M=1024K 的进位方式; -T :连同该 partition 的 filesystem 名称 (例如 xfs) 也列出; -i :不用硬盘容量,而以 inode 的数量来显示 -
du: 评估文件系统的硬盘使用量(常用在推估目录所占容量)[root@study ~]# du [-ahskm] 文件或目录名称 选项与参数: -a :列出所有的文件与目录容量,因为默认仅统计目录底下的文件量而已。 -h :以人们较易读的容量格式 (G/M) 显示; -s :列出总量而已,而不列出每个各别的目录占用容量; -S :不包括子目录下的总计,与 -s 有点差别。 -k :以 KBytes 列出容量显示; -m :以 MBytes 列出容量显示; -
硬连接
实际就是多个文件指向同一个inode,和面向对象中的对象一样,多个变量存储的是一个对象的地址。所以硬连接的文件属性改了,其他指向这个inode的文件也会变。
硬连接的文件删除了并不会影响其他连接到这个inode的文件,相当于只是删除了一个指向。
ln 原文件 目标文件 # 用于建立硬链接,cp命令也可以建立硬链接hard link不能跨系统,也不能连接目录。
为什么不能连接目录,目录下有2个隐藏文件
.和..,如果允许硬连接,这2个文件指向谁将出现冲突。查找文件时,都是从/根目录开始找,inode → block → 文件名 → inode → block → …一层一层的就能找到
-
软连接
实际就是快捷方式
软连接会占用inode,block,只不过他的block指向的是被连接的文件的inode。所以被连接文件一但删除,这个软连接就无法打开了。
ln -s 原文件 目标文件[root@study ~]# ln [-sf] 来源文件 目标文件 选项与参数: -s :如果不加任何参数就进行连结,那就是hard link,至于 -s 就是symbolic link -f :如果 目标文件 存在时,就主动的将目标文件直接移除后再建立!
硬盘管理
分区
MBR格式使用fdisk工具,GPT格式使用gdisk工具
-
查看硬盘信息
lsblk: 列出所有存储设备[root@study ~]# lsblk [-dfimpt] [device] 选项与参数: -d :仅列出磁盘本身,并不会列出该磁盘的分区数据 -f :同时列出该磁盘内的文件系统名称 -i :使用 ASCII 的线段输出,不要使用复杂的编码 (再某些环境下很有用) -m :同时输出该装置在 /dev 底下的权限数据 (rwx 的数据) -p :列出该装置的完整文件名!而不是仅列出最后的名字而已。 -t :列出该磁盘装置的详细数据,包括磁盘队列机制、预读写的数据量大小等blkid: 列出存储设备的UUID以及文件系统类型blkid -
查看分区信息
parted: 查看分区类型(MBR,GPT)[root@study ~]# parted device_name print -
使用gdisk进行分区
[root@study ~]# gdisk 装置名称使用上面的命令后,可以输入
?查看后续操作,非常清楚Command (? for help): ? b back up GPT data to a file c change a partition's name d delete a partition # 删除一个分区 i show detailed information on a partition l list known partition types n add a new partition # 增加一个分区 o create a new empty GUID partition table (GPT) p print the partition table # 打印出分区表 (常用) q quit without saving changes # 不储存分区就直接离开 gdisk r recovery and transformation options (experts only) s sort partitions t change a partition's type code v verify disk w write table to disk and exit # 储存分区操作后离开 gdisk x extra functionality (experts only) ? print this menu Command (? for help): -
更新信息
修改分区后,为了保证系统稳定并不会立即生效,可以使用更新命令
[root@study ~]# partprobe -s
fdisk的操作类似,只是要注意主分区、扩展分区、逻辑分区的限制。
格式化
格式化就是建立文件系统。比如要格式为xfs系统,可以使用mkfs.xfs命令
[root@study ~]# mkfs.xfs [-b bsize] [-d parms] [-i parms] [-l parms] [-L label] [-f] [-r parms] 装置名称一般使用默认值即可,除非有特殊需求。
mkfs是一个综合指令,几乎支持所有文件系统的创建(格式化)
文件系统的校验
-
xfs系统
一般在文件系统出现问题后,才使用,因为可能导致系统危害。所以**慎用**。
[root@study ~]# xfs_repair [-fnd] 装置名称 选项与参数: -f :后面的装置其实是个文件而不是实体装置 -n :单纯检查并不修改文件系统的任何数据 (检查而已) -d :通常用在单人维护模式底下,针对根目录 (/) 进行检查与修复的动作!很危险!不要随便使用对文件系统进行检测之前,必须进行卸载(取消挂载)。根目录的检查需要进入单人维护或救援模式下,因为根目录所在dev/partition无法卸载。
-
ext4系统
[root@study ~]# fsck.ext4 [-pf] [-b superblock] 装置名称 选项与参数: -p :当文件系统在修复时,若有需要回复 y 的动作时,自动回复 y 来继续进行修复动作。 -f :强制检查!一般来说,如果 fsck 没有发现任何 unclean 的旗标,不会主动进入 细部检查的,如果您想要强制 fsck 进入细部检查,就得加上 -f 旗标啰! -D :针对文件系统下的目录进行优化配置。 -b :后面接 superblock 的位置!一般来说这个选项用不到。但是如果你的 superblock 因故损毁时, 透过这个参数即可利用文件系统内备份的 superblock 来尝试救援。一般来说,superblock 备份在: 1K block 放在 8193, 2K block 放在 16384, 4K block 放在 32768每个群组都有个superblock,如果第一个坏了,去第2个群组找superblock,由于block是从0开始的,而第2个群组的superblock在8193/16384/32768,所以每个群组实际有8193/16384/32768个block。
fsck是个综合指令,可以用于修复不同的文件系统。
挂载和卸载
- 不要将一个文件系统挂载到多个目录
- 一个目录不要挂载多个文件系统
- 被挂载的目录要是空目录
挂载
mount: 挂载文件系统(被挂载的对象必须是文件系统,比如分区后,如果没有进行格式化指定文件系统,挂载会出现问题,但是如果是U盘已经有了文件系统,那可以直接挂载)。
[root@study ~]# mount -a
[root@study ~]# mount [-l]
[root@study ~]# mount [-t 文件系统] LABEL='' 挂载点
[root@study ~]# mount [-t 文件系统] UUID='' 挂载点 # UUID的唯一性,这种方式最保险
[root@study ~]# mount [-t 文件系统] 装置文件名 挂载点
选项与参数:
-a :依照配置文件 /etc/fstab 的数据将所有未挂载的磁盘都挂载上来
-l :单纯的输入 mount 会显示目前挂载的信息。加上 -l 可增列 Label 名称!
-t :可以加上文件系统种类来指定欲挂载的类型。常见的 Linux 支持类型有:xfs, ext3, ext4,
reiserfs, vfat, iso9660(光盘格式), nfs, cifs, smbfs (后三种为网络文件系统类型)
-n :在默认的情况下,系统会将实际挂载的情况实时写入 /etc/mtab 中,以利其他程序的运作。
但在某些情况下(例如单人维护模式)为了避免问题会刻意不写入。此时就得要使用 -n 选项。
-o :后面可以接一些挂载时额外加上的参数!比方说账号、密码、读写权限等:
async, sync: 此文件系统是否使用同步写入 (sync) 或异步 (async) 的
内存机制,请参考文件系统运作方式。预设为 async。
atime,noatime: 是否修订文件的读取时间(atime)。为了效能,某些时刻可使用 noatime
ro, rw: 挂载文件系统成为只读(ro) 或可擦写(rw)
auto, noauto: 允许此 filesystem 被以 mount -a 自动挂载(auto)
dev, nodev: 是否允许此 filesystem 上,可建立装置文件? dev 为可允许
suid, nosuid: 是否允许此 filesystem 含有 suid/sgid 的文件格式?
exec, noexec: 是否允许此 filesystem 上拥有可执行 binary 文件?
user, nouser: 是否允许此 filesystem 让任何使用者执行 mount ?一般来说,
mount 仅有 root 可以进行,但下达 user 参数,则可让
一般 user 也能够对此 partition 进行 mount 。
defaults: 默认值为:rw, suid, dev, exec, auto, nouser, and async
remount: 重新挂载,这在系统出错,或重新更新参数时,很有用!-t 选项已经不是必须的,因为操作系统能识别挂载的文件系统,并进行合理的配置。
remount选项,比如根目录是无法卸载的,但是如果根目录变成只读了,怎么改回来呢,换句话说如果要重新修改挂载参数怎么办?
[root@study ~]# mount -o remount,rw,auto /卸载
比如U盘,挂载使用后,拔下来之前要进行卸载
[root@study ~]# umount [-fn] 装置文件名或挂载点
选项与参数:
-f :强制卸除!可用在类似网络文件系统 (NFS) 无法读取到的情况下;
-l :立刻卸除文件系统,比 -f 还强!
-n :不更新 /etc/mtab 情况下卸除。一般用挂载点来进行卸载
开机挂载
/etc/fstab文件就是开机读取的挂载配置文件。mount -a也是根据这个文件自动挂载。
文件格式为:
[装置/lable/UUID 等] [挂载点] [文件系统] [文件系统参数] [dump] [fsck]文件系统参数就是mount -n后面指定的参数,一般用defaults即可(如果是loop设备需要是defaults,loop形式);dump能否被备份指令作用,填0即可,因为有其他备份手段;fsck,使用fsck检验硬盘,xfs会自检,这里也不需要填0就行。
/etc/fstab是开机的配置文件,实际挂载记录是在/etc/mtab和/proc/mounts中,每次挂载变动时都会更新这2个记录。
将文件当作设备挂载
可以使用loop将文件或镜像等构造成伪设备/仿真设备,然后挂载到目录上,这样就可以把文件当作设备,或者直接读取镜像中的内容(就像挂载后正常读取设备内容一样)
loop转换的本身就是文件系统中的文件,转换后又被第一层文件系统加载,相当于回环。
-
建立文件
[root@study ~]# dd if=/dev/zero of=/srv/loopdev bs=1M count=512 512+0 records in <==读入 512 笔资料 512+0 records out <==输出 512 笔数据 536870912 bytes (537 MB) copied, 12.3484 seconds, 43.5 MB/s # 这个指令的简单意义如下: # if 是 input file ,输入文件。那个 /dev/zero 是会一直输出 0 的装置! # of 是 output file ,将一堆零写入到后面接的文件中。 # bs 是每个 block 大小,就像文件系统那样的 block 意义; # count 则是总共几个 bs 的意思。所以 bs*count 就是这个文件的容量了! -
文件格式化
[root@study ~]# mkfs.xfs -f /srv/loopdev [root@study ~]# blkid /srv/loopdev -
挂载
mount -o loop UUID="7dd97bd2-4446-48fd-9d23-a8b03ffdd5ee" /mnt使用
-o loop可以将文件转换为伪设备。上面是直接转换并挂载,实际分了2步:
- losetup /dev/loop0 /srv/loopdev 转换为loop设备
- mount /dev/loop0 /mnt 挂载
还可以直接读取iso镜像文件,原理相同,转换为loop设备,挂载,然后就可以直接访问了。
[root@study ~]# mount -o loop /tmp/CentOS-7.0-1406-x86_64-DVD.iso /data/centos_dvdswap分区
内存不够时会将内存中不活动的内容写入swap。
划分swap分区和其他分区大体一致。
需要注意4点:
Hex code or GUID (L to show codes, Enter = 8300):gdisk会使用这里的id预设为该分区的文件系统,swap对应的id为8200,可以输入L查看。- 使用
mkswap 设备文件格式化设备,格式化为swap类型 - swap不需要挂载,通过
swapon 设备文件启动 - swap没有挂载点,写入
/etc/fstab时,挂载点填写swap
如果分区无法设置为swap,比如没有剩余容量了。可以将文件设置为swap。
- dd创建文件
- mkswap格式化
- swapon启用
swapoff可以取消swap
压缩与打包
常用压缩技术
- .zip zip 程序压缩的文件;
- .gz gzip 程序压缩的文件;
- .bz2 bzip2 程序压缩的文件;
- .xz xz 程序压缩的文件;
- .tar tar 程序打包的数据,并没有压缩过;
- .tar.gz tar 程序打包的文件,其中并且经过 gzip 的压缩
- .tar.bz2 tar 程序打包的文件,其中并且经过 bzip2 的压缩
- .tar.xz tar 程序打包的文件,其中并且经过 xz 的压缩
tar用于打包,多个文件打包成一个文件,但是并没有经过压缩,gz xz bz2才是用来压缩的
后缀只是为了方便识别是哪种打包压缩技术,并无实际意义
gzip
使用最多的一种压缩技术
[dmtsai@study ~]$ gzip [-cdtv#] 文件名
选项与参数:
-c :将压缩的数据输出到屏幕上,可透过数据流重导向来处理;
-d :解压缩的参数;
-t :可以用来检验一个压缩文件的一致性~看看文件有无错误;
-v :可以显示出原文件/压缩文件案的压缩比等信息;
-# :# 为数字的意思,代表压缩等级,-1 最快,但是压缩比最差、-9 最慢,但是压缩比最好!预设是 -6注意压缩后,原文件会被删除。如果gzip -d解压,解压后压缩文件也会自动删除
cat,more,less可以查看ascii文件,zcat,zmore,zless可以直接查看压缩后的文件内容
同样的,grep可以搜索文件内容,zgrep可以直接搜索压缩包里的文件内容
bzip2
[dmtsai@study ~]$ bzip2 [-cdkzv#] 文件名
选项与参数:
-c :将压缩的过程产生的数据输出到屏幕上!
-d :解压缩的参数
-k :保留源文件,而不会删除原始的文件喔!
-z :压缩的参数 (默认值,可以不加)
-v :可以显示出原文件/压缩文件案的压缩比等信息;
-# :与 gzip 同样的,都是在计算压缩比的参数, -9 最佳, -1 最快!使用方法和gzip几乎一样。同样的还有bzcat,bzmore,bzless,bzgrep
xz
[dmtsai@study ~]$ xz [-dtlkc#] 文件名
选项与参数:
-d :就是解压缩啊!
-t :测试压缩文件的完整性,看有没有错误
-l :列出压缩文件的相关信息
-k :保留原本的文件不删除~
-c :同样的,就是将数据由屏幕上输出的意思!
-# :同样的,也有较佳的压缩比的意思!使用方法类似。同样的还有xzcat,xzmore,xzless,xzgrep
压缩效果越好,时间越久,综合来看gzip适合大部分情况。
tar打包
虽然gzip,xz,bzip2能够压缩目录,但是只是将目录中的每一个文件压缩了而已
[dmtsai@study ~]$ tar [-z|-j|-J] [cv] [-f 待建立的新文件名] filename... <==打包与压缩
[dmtsai@study ~]$ tar [-z|-j|-J] [tv] [-f 既有的 tar 文件名] <==察看文件名
[dmtsai@study ~]$ tar [-z|-j|-J] [xv] [-f 既有的 tar 文件名] [-C 目录] <==解压缩
选项与参数:
-c :建立打包文件,可搭配 -v 来察看过程中被打包的档名(filename)
-t :察看打包文件的内容含有哪些档名,重点在察看『档名』就是了;
-x :解打包或解压缩的功能,可以搭配 -C (大写) 在特定目录解开
特别留意的是, -c, -t, -x 不可同时出现在一串指令列中。
-z :透过 gzip 的支持进行压缩/解压缩:此时档名最好为 *.tar.gz
-j :透过 bzip2 的支持进行压缩/解压缩:此时档名最好为 *.tar.bz2
-J :透过 xz 的支持进行压缩/解压缩:此时档名最好为 *.tar.xz
特别留意, -z, -j, -J 不可以同时出现在一串指令列中
-v :在压缩/解压缩的过程中,将正在处理的文件名显示出来!
-f filename:-f 后面要立刻接要被处理的档名!建议 -f 单独写一个选项啰!(比较不会忘记)
-C 目录 :这个选项用在解压缩,若要在特定目录解压缩,可以使用这个选项。常用的也就是
# 压缩
tar -zcv -f 目标文件名 要被压缩的文件目录列表
# 查看
tar -ztv -f 压缩文件名
# 解压
tar -zxv -f 压缩文件名 -C 解压目录还有些比较适用的,比如
-p: 选项是保留原本文件的权限和属性,常用于备份。
-P: 选项保留根目录,正常打包后路径是从被打包的目录开始的,这样做的目的是,解压到哪个目录,那文件所属路径就属于哪个目录,如果使用 -P 限定,那么解压后会直接定位到这个包含根目录的绝对路径,就会覆盖原来的内容,很危险。
其他用法:
只解压某个文件
tar -zxv -f 压缩文件 -C 解压目录 单独解压的文件 # 注意这个文件名必须是 tar -ztv中展示出来的排除某些文件:
tar -zcv -f /tmp/abc.tar.gz --exclude=/tmp/abc.tar.gz --exclude=/root/etc* /root /etc打包某个时间之后的文件
tar -zcv -f /tmp/etc_bak.tar.gz --newer-mtime="2021/06/18" /etc/*tarfile:表示只进行打包后的文件,比如 tar -cv /tmp/abc.tar /etc
tarball:表示打包并压缩后的文件,比如tar -zcv /tmp/abc.tar.gz /etc
复制文件:
除了使用cp命令,还可以借助tar配合管道,打包数据并解压数据
tar -cv -f - | tar -xv -f - -C 目标目录文件系统备份与恢复
备份
xfsdump备份xfs格式的文件系统
[root@study ~]# xfsdump [-L S_label] [-M M_label] [-l #] [-f 备份档] 待备份资料
[root@study ~]# xfsdump -I
选项与参数:
-L :xfsdump 会纪录每次备份的 session 标头,这里可以填写针对此文件系统的简易说明
-M :xfsdump 可以纪录储存媒体的标头,这里可以填写此媒体的简易说明
-l :是 L 的小写,就是指定等级~有 0~9 共 10 个等级喔! (预设为 0,即完整备份)
-f :有点类似 tar 啦!后面接产生的文件,亦可接例如 /dev/st0 装置文件名或其他一般文件档名等
-I :从 /var/lib/xfsdump/inventory 列出目前备份的信息状态比如备份/boot
xfsdump -l 0 -L boot_all -M boot_all -f /srv/boot.dump /boot0表示完整备份,有0之后,后面可以是1-9level进行差异化备份
[root@study ~]# xfsdump -l 1 -L boot_2 -M boot_2 -f /srv/boot.dump1 /boot恢复
[root@study ~]# xfsrestore -I <==用来察看备份文件资料
[root@study ~]# xfsrestore [-f 备份档] [-L S_label] [-s] 待复原目录 <==单一文件全系统复原
[root@study ~]# xfsrestore [-f 备份文件] -r 待复原目录 <==透过累积备份文件来复原
系统
[root@study ~]# xfsrestore [-f 备份文件] -i 待复原目录 <==进入互动模式
选项与参数:
-I :跟 xfsdump 相同的输出!可查询备份数据,包括 Label 名称与备份时间等
-f :后面接的就是备份档!企业界很有可能会接 /dev/st0 等磁带机!我们这里接档名!
-L :就是 Session 的 Label name 喔!可用 -I 查询到的数据,在这个选项后输入!
-s :需要接某特定目录,亦即仅复原某一个文件或目录之意!
-r :如果是用文件来储存备份数据,那这个就不需要使用。如果是一个磁带内有多个文件,
需要这东西来达成累积复原
-i :进入互动模式,进阶管理员使用的!一般我们不太需要操作它!-
整个恢复
同名文件直接覆盖,不在备份档里的新文件保留
[root@study ~]# xfsrestore -f /srv/boot.dump -L boot_all /boot -
单独恢复某个文件
[root@study ~]# xfsrestore -f /srv/boot.dump -L boot_all -s grub2 /tmp/boot2 -
累计复原,比如前面备份了level0,level1,复原的时候就是先从0开始,一级一级的恢复
[root@study ~]# xfsrestore -f /srv/boot.dump -L boot_all /boot [root@study ~]# xfsrestore -f /srv/boot.dump1 -L boot_2 /boot -
使用互动模式,即
-i,根据引导完成恢复
dd命令
dd命令可以创建一个文件,还可以用来备份,因为dd是直接读取扇区。
[root@study ~]# dd if="input_file" of="output_file" bs="block_size" count="number"
选项与参数:
if :就是 input file 啰~也可以是装置喔!
of :就是 output file 喔~也可以是装置;
bs :规划的一个 block 的大小,若未指定则预设是 512 bytes(一个 sector 的大小)
count:多少个 bs 的意思。比如:
dd if=/etc/passwd of=/tmp/passwd.back
dd if=/tmp/system.iso of=/dev/sda # 备份到设备,注意还没有进行挂载!因为是扇区直接复制进去,不是读取文件,不需要挂载就能写入。
dd if=/dev/vda2 of=/tmp/vda2.img # 备份一整个设备如果vda2 大小为1G,使用了500M,vda2.img此时也会是1G,因为dd会直接读取所有扇区,不管有没有数据。这意味着dd命令和文件系统无关,因为直接对扇区进行了复制。在某些情况下,这会造成问题,比如复制一整个分区到另一个分区,如果使用dd命令,连log和UUID都复制过去了,此时就需要清除log并重新改写UUID,否则无法挂载
Vim
文本编辑器/程序编辑器,功能强大,快捷键非常多。
模式
- 正常模式:可以使用快捷键命令,或按
:输入命令行 - 插入模式:可以输入文本,在正常模式下,按
i、a、o等都可以进入插入模式 - 可视模式:正常模式下按
v可以进入可视模式, 在可视模式下,移动光标可以选择文本按V进入可视行模式, 总是整行整行的选中ctrl+v进入可视块模式
常用快捷键
h: 退格或左移一个字符,l: 右移一个字符 ,j: 下移一行 ,k: 上移一行x: 剪切(常用来删除)光标下的字符r: 替换光标处的字符yy或 Y: 复制整行文本y0: 从光标当前位置复制到行首y$: 从光标当前位置复制到行尾p: 在光标之后粘贴P: 在光标之前粘贴[n]dd: 删除(剪切)1(n)行d0: 删除(剪切)当前位置到行首的内容d$或 D: 删除(剪切)当前位置到行尾的内容d: 删除(剪切)在可视模式下选中的文本[n]u: 取消一(n)个改动ctrl + r: 重做最后的改动:earlier 4m: 回到4分钟前:later 55s: 前进55秒:w: 保存修改:x: 保存并退出 ,:wq: 保存并退出,:ZZ: 保存并退出:saveas newfilename: 另存为gg: 到文件头部G: 到文件尾部H: 把光标移到屏幕最顶端一行M: 把光标移到屏幕中间一行L: 把光标移到屏幕最底端一行/something: 在后面的文本中查找something?something: 在前面的文本中查找somethingn: 向后查找下一个N: 向前查找下一个ctrl+w ctrl+p: 切换到前一个窗口ctrl+w ctrl+w: 切换到下一个窗口ctrl+w ctrl+r:旋转窗口的位置~: 反转光标所在字符的大小写:! cmd: 执行外部命令:!!: 执行上一次的外部命令Vex: 垂直分割,左目录右编辑窗口Sex: 水平分割,上目录下编辑窗口:split(:sp): 把当前窗水平分割成两个窗口:split filename: 水平分割窗口,并在新窗口中显示另一个文件:vsplit(:vsp): 把当前窗口分割成水平分布的两个窗口:only: 只保留当前窗口,关闭其它窗口:set spell-开启拼写检查功能:set nospell-关闭拼写检查功能
换行符与编码格式
windows中换行符为CRLF,linux中换行符为LF,enter也是换行符,linux中enter表示执行指令。如果windows中的文件直接复制进来,如果是一个shell script,那很可能执行出现意外。可以使用dos2unix功能,需要下载第三方软件。
编码格式同样可以进行转换,比如gbk转utf8,可以使用iconv指令。
[dmtsai@study ~]$ iconv --list
[dmtsai@study ~]$ iconv -f 原本编码 -t 新编码 filename [-o newfile]
选项与参数:
--list :列出 iconv 支持的语系数据
-f :from ,亦即来源之意,后接原本的编码格式;
-t :to ,亦即后来的新编码要是什么格式;
-o file:如果要保留原本的文件,那么使用 -o 新档名,可以建立新编码文件。还可以使用sed:
unix2dos:
sed -i -e 's/\r*$/\r/' filedos2unix:
sed -i -e 's/\r//g' fileBash
shell
Linux的内核是kernel,kernel不会随便的被用户所控制,否则容易造成系统崩溃,所以都是通过接口程序或应用程序调用,而应用程序的调用也是通过接口程序,接口程序就有shell或者x-window可视化界面等。
graph LR 1[用户] --> 2[shell] --> 3[programs] --> 4[kernel] --> 5[硬件] 2[shell] --> 4[kernel]
shell程序就是提供给用户下达指令的地方。
cat /etc/shells # 可以看到系统支持的shell程序一般预设给用户的shell程序是bash,各发行版的bash使用都差不多。
cat /etc/passwd # 可以看到分配给用户的shellbash特点
-
tab命令补全功能,很好用,可以补全命令,参数,文件名,tab tab 可以查看所有相关命令。
root@LAPTOP-GH95O3K5:/tmp# ls ls lsb_release lscpu lsinitramfs lslocks lsmem lsns lspci lsusb lsattr lsblk lshw lsipc lslogins lsmod lsof lspgpot -
查看历史命令
cat ~/.bash_history # 查看当前用户下达过的历史命令 -
命令别名。对于常用命令可以设置别名,快速调用.
alias lm = 'ls -al' # 设置别名 -
前景、背景工作。执行的命令可以放在背景中执行,而不至于占用整个接口。
-
shell scripts,壳脚本,类似批处理文件,但是强大的多。
查看指令
指令可以是bash内置的,也可以是应用程序提供的
type指令可以查看是否bash内建指令
[dmtsai@study ~]$ type [-tpa] name
选项与参数:
:不加任何选项与参数时,type 会显示出 name 是外部指令还是 bash 内建指令
-t :当加入 -t 参数时,type 会将 name 以底下这些字眼显示出他的意义:
file :表示为外部指令;
alias :表示该指令为命令别名所设定的名称;
builtin :表示该指令为 bash 内建的指令功能;
-p :如果后面接的 name 为外部指令时,才会显示完整文件名;
-a :会由 PATH 变量定义的路径中,将所有含 name 的指令都列出来,包含 aliastype -a command # 显示的顺序就是指令的查找顺序下达指令
\使用,比如命令太长需要换行的时候,需要用反斜杠转义enter进行换行,直接enter就是执行命令了- 常用组合键:
ctrl + u光标处向前删,ctrl + k光标处向后删ctrl + a跳到命令开头,ctrl + e跳到命令结尾
变量
可以将路径,字符串,数字等赋值给变量
-
读取
echo $VAR -
设置变量
VAR=str # = 左右不能出现空格,且值也不能以空格结尾 VAR="any str" # 有空格需要用双引号包裹 VAR=any\ str # 也可以使用反斜杠转义 VAR='$PATH' # var的值为$PATH VAR="$PATH" # var的值为$PATH代表的值,相当于双引号会解析其他中变量,而单引号只是将里面的内容当作普通的字符串 -
关联其他指令
VAR=$(uname -r) # 引用其他指令,在命令中也可以使用这种方式 cd /lib/modules/$(uname -r)/kernel VAR=`uname -r` # 或者使用``包裹 -
增加变量内容
以PATH为例,PATH中的值是以:隔开
PATH=${PATH}:/home/bin # "$PATH"也可以 -
设置为环境变量
export VAR # 将普通变量var设置为环境变量,供其他程序调用,比如另一个bash -
取消变量
unset VAR # 删除变量
环境变量
查看
使用env和export可以查看所有的环境变量
root@LAPTOP-GH95O3K5:/tmp# env
SHELL=/bin/bash
PWD=/tmp
LOGNAME=root
HOME=/root
LANG=C.UTF-8
....使用set观察bash的所有变量,包括环境变量,用户自定义变量等
wgx@LAPTOP-GH95O3K5:/tmp$ set | head -n 15
BASH=/usr/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:globasciiranges:histappend:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=([0]="0")
BASH_ARGV=()
BASH_CMDS=()
BASH_COMPLETION_VERSINFO=([0]="2" [1]="10")
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="5" [1]="0" [2]="17" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
BASH_VERSION='5.0.17(1)-release'
COLUMNS=120
DIRSTACK=()
EUID=1000
GROUPS=()
...
PS1='\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ 'PS1表示提示字符的设置,就是wgx@LAPTOP-GH95O3K5:/tmp$这段,可以通过PS1修改
特殊变量
-
$: 表示当前shell的PIDecho $$ -
?: 上一个指令的返回值,类似函数的返回值cd ~ echo $? # 上一个指令成功执行,返回值为0
export
bash也是一个进程,通过bash可以开启另一个进程,2个进程就是父子程序关系
父子程序中变量是独享的,但是环境变量是可以通用的。
export VARlocale
-
locale: 查看当前语言环境wgx@LAPTOP-GH95O3K5:~$ locale LANG=C.UTF-8 LANGUAGE= LC_CTYPE="C.UTF-8" LC_NUMERIC="C.UTF-8" LC_TIME="C.UTF-8" LC_COLLATE="C.UTF-8" LC_MONETARY="C.UTF-8" LC_MESSAGES="C.UTF-8" LC_PAPER="C.UTF-8" LC_NAME="C.UTF-8" LC_ADDRESS="C.UTF-8" LC_TELEPHONE="C.UTF-8" LC_MEASUREMENT="C.UTF-8" LC_IDENTIFICATION="C.UTF-8" LC_ALL=优先级:LC_ALL > LC* > LANG
-
locale -a: 查看可用语言环境 -
系统locale配置文件
cat /etc/locale.conf -
修改locale
可以修改上述的配置文件永久生效。或者修改LC_ALL临时生效,为了修改生效,需要export为环境变量
变量交互与声明
-
read
让用户输入值
[dmtsai@study ~]$ read [-pt] variable 选项与参数: -p :后面可以接提示字符! -t :后面可以接等待的『秒数!』这个比较有趣~不会一直等待使用者啦! -
declare
声明变量类型
[dmtsai@study ~]$ declare [-aixr] variable 选项与参数: -a :将后面名为 variable 的变量定义成为数组 (array) 类型 -i :将后面名为 variable 的变量定义成为整数数字 (integer) 类型 -x :用法与 export 一样,就是将后面的 variable 变成环境变量; -r :将变量设定成为 readonly 类型,该变量不可被更改内容,也不能 unsetbash默认会将变量的值认为是字符串,比如:
SUM=1+2+3 echo $SUM # 1+2+3 # 认为是字符串,不会计算 declare -i SUM=1+2+3 # 会进行计算 echo $SUM # 6数组:
wgx@LAPTOP-GH95O3K5:~$ declare -a ARR wgx@LAPTOP-GH95O3K5:~$ ARR=(a b c) # 空格隔开元素 wgx@LAPTOP-GH95O3K5:~$ echo ${ARR[0]} # a
变量内容的删除、替换
删除
-
#: 后面跟表达式,代表从前往后删,非贪婪模式,只删除匹配的第一个echo ${PATH} #/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin echo ${PATH#/*local/bin:} # 删除了/usr/local/bin: *表示通配 -
##: 后面跟表达式,代表从前往后删,贪婪模式,尽可能多的匹配,然后删除echo ${PATH##/*:} # 删除了/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin: -
%: 后面跟表达式,代表从后往前删,非贪婪模式echo ${PATH%:*bin} # 删除了 :/home/dmtsai/bin -
`:*bin} # 删除了 :/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
替换
-
/: 替换第一个echo ${PATH/bin/sbin} # 将第一个bin替换为sbin -
//: 替换所有echo ${PATH//bin/sbin} # 全部的bin替换为sbin
alias
通过alias可以查看并设置别名
alias # 查看哪些命令别名
alias lm='ls -a | more' # 给长命令取别名
alias rm = 'rm -i' # 替代原来的别名可以通过unalias取消别名
查看历史命令
[dmtsai@study ~]$ history [n]
[dmtsai@study ~]$ history [-c]
[dmtsai@study ~]$ history [-raw] histfiles
选项与参数:
n :数字,意思是『要列出最近的 n 笔命令行表』的意思!
-c :将目前的 shell 中的所有 history 内容全部消除
-a :将目前新增的 history 指令新增入 histfiles 中,若没有加 histfiles ,
则预设写入 ~/.bash_history
-r :将 histfiles 的内容读到目前这个 shell 的 history 记忆中;
-w :将目前的 history 记忆内容写入 histfiles 中!正常注销时会写入~/.bash_history中,可以使用-w强制立即写入,~/.bash_history能记录多少命令,取决于${HISTSIZE}的大小。
history除了查看历史命令外,还可以对历史命令加以利用
!number: 从后往前数,执行第几个命令!command: 从后往前搜索,以command开头的指令,并执行!!: 立即执行上一条指令
login shell 与 nologin shell
正常通过用户密码登录获取的bash就是一个login shell,而通过x-window进入或者在login shell下使用bash调出的另一个bash就是nologin shell。
login shell 和 nologin shell打开时读取的配置文件并不一样(配置文件包括各种变量等,正常个人定义的变量、环境变量在退出bash后就没有了,但是写入配置文件中就可以在进入bash后读取)
login shell
主要有2个配置文件(shell scripts)
/etc/profile: 这是整体系统的配置,不要修改。包含PATH;MAIL;USER;umask等变量,这个配置文件还能调用其他的配置文件,比如locale。~/.bash_profile: 这是用户的配置文件,比如会把~/bin加入到PATH中,并读取~/.bashrc文件
可以修改~/.bashrc文件,注销后再次登入就能更新了。
当然可以使用source指令直接执行这个文件(也可以使用.命令,效果相同)。
nologin shell
只会读取~/.bashrc这个文件。
这个文件定义了一些别名,并调用了/etc/bashrc这个文件,这个文件定义了PS1提示符等信息
其他配置文件:
- /etc/man_db.conf: 如果以tarball安装的软件,那么该软件提供的man信息就在/usr/local/packageName/man里面,此时就需要把这个路径加入到man_db.conf,否则man的时候可能查不到
- ~/.bash_history: 进入bash后会自动加载这个文件,把历史命令都加载进来
- ~/.bash_logout: 退出bash后,系统做的操作,可以修改这个文件,让bash在退出时帮助做些事情
通配符
有点类似正则
*: 表示0到多个字符?: 表示1个任意字符[]: 表示其中的任意一个[-]: 表示类似[a-z][0-9]中的任意一个[^]: 和正则相同,不在范围内
数据流重导向
-
stdin: 标准输入流。重导向,代码0,表示符号,<,<<,<表示将输入流重导向指定的文件,其中<<表示结束符号,比如将屏幕输入当作stdin的时候使用ctrl+d结束输入,但是通过<<可以指定结束符,一般可以是eof,当检查到结束符时自动结束输入。cat > /tmp/test # 键盘输入导向/tmp/test文件,键盘输入时使用ctrl+d退出输入 cat > /tmp/test << 'eof' # 使用eof符号结束输入,就不用ctrl+d了 cat > /tmp/test < ~/.bashrc # 将cat读取的信息导向/tmp/test文件,默认是使用键盘输入,但是使用 < 后,将输入重导向了.bashrc -
stdout: 标准输出流。重导向,代码1,表示符号>,>>(单箭头表示清空再添加,双箭头表示累加),后面跟文件或设备,表示将正常的输出流导向文件或设备。find /home -name .bashrc > /tmp/test # 将查找结果导向/tmp/test,由于指导向了正确结果,错误结果依然会在屏幕上显示 find /home -name .bashrc > /tmp/test 2> /dev/null # 正确结果导向/tmp/test,错误结果导向/dev/null find /home -name .bashrc > /tmp/test 2>&1 # 正确错误都导向一个/tmp/test find /home -name .bashrc &> /tmp/test # 效果同上/dev/null,会吞掉一切放进去的东西,有点类似回收站
/dev/zero,表示会输出0,使用dd命令的时候,用到过这个设备,用0填充文件
-
stderr: 标准错误输出流。重导向,代码2,表示符号2>,2>>(单箭头表示清空再添加,双箭头表示累加),后面跟文件或设备,表示将错误的输出流导向文件或设备。# 基本用法同上 # 特殊用法,可以将2>&1,错误信息放在stdout的文件里,当然也可以1>&2,stdout导向stderr echo 'hello world' 2> /tmp/test 1>&2 # 界面不会有显示,stdout导入到了/tmp/test里
指令组合
如果复杂指令组合,需要使用shell script组织语言完成任务。
如果是相对简单的,可以在命令行中直接使用多个指令。
;: 分号可以隔开多个指令。上一个执行完下一个接着马上执行。&&: 前一个指令的s?为0,则执行&&后面的指令||: 前一个指令的s?不为0时,则执行||后面的指令
管道命令PIPE
管道命令:|。
管道命令实际就是把前一个命令的输出结果当作stdin。所以这里有2个前提:
- 前一个命令能够进行
stdout(管道命令无法处理stderr) - 后一个命令能够接收
stdin
cat /etc | lesscut,grep,sort,wc,uniq
-
cut: 截取stdout里的内容。注意:cut是以行为单位,不是整个文档。
[dmtsai@study ~]$ cut -d '分隔字符' -f fields <==用于有特定分隔字符 [dmtsai@study ~]$ cut -c 字符区间 <==用于排列整齐的讯息 选项与参数: -d :后面接分隔字符。与 -f 一起使用; -f :依据 -d 的分隔字符将一段讯息分区成为数段,用 -f 取出第几段的意思; -c :以字符 (characters) 的单位取出固定字符区间;echo ${PATH} | cut -d ':' -f 5 # 取用:隔开后第5个 echo ${PATH} | cut -d ':' -f 3,5 # 取用:隔开后第3,5个 export | -c 12- # 取每一行从第12个字符开始的数据 -
grep: 对每一行数据查找关键字[dmtsai@study ~]$ grep [-acinv] [--color=auto] '搜寻字符串' filename 选项与参数: -a :将 binary 文件以 text 文件的方式搜寻数据 -c :计算找到 '搜寻字符串' 的次数 -i :忽略大小写的不同,所以大小写视为相同 -n :顺便输出行号 -v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行! --color=auto :可以将找到的关键词部分加上颜色的显示喔!last | grep -in 'root' | cut -d ' ' -f 1grep 后面可以使用正则表达式,这和前面的通配符不一样,这里是正常的正则表示式,支持^,$开始结束,*表示0个或多个,.表示任意1个字符,{n,m}限定次数({和}需要用\转义)。如果要支持延申正则(更多正则规则),需要使用
egrep。 -
sort: 排序[dmtsai@study ~]$ sort [-fbMnrtuk] [file or stdin] 选项与参数: -f :忽略大小写的差异,例如 A 与 a 视为编码相同; -b :忽略最前面的空格符部分; -M :以月份的名字来排序,例如 JAN, DEC 等等的排序方法; -n :使用『纯数字』进行排序(默认是以文字型态来排序的); -r :反向排序; -u :就是 uniq ,相同的数据中,仅出现一行代表; -t :分隔符,预设是用 [tab] 键来分隔; -k :以那个区间 (field) 来进行排序的意思cat /etc/passwd | sort -fb -t ':' -k 3 -n # 以-t 分割后,以第三个元素,并以数字排序默认是以第一个字母,以文字的形式排序。
-
uniq: 重复行,只显示一个[dmtsai@study ~]$ uniq [-ic] 选项与参数: -i :忽略大小写字符的不同; -c :进行计数last | cut -d ' ' -f 1 | sort | uniq -c就是分组排序,然后取每组第一个,并计算count
-
wc: 统计文件整体信息,比如多少行,多少字符[dmtsai@study ~]$ wc [-lwm] 选项与参数: -l :仅列出行; -w :仅列出多少字(英文单字); -m :多少字符;last | grep [a-zA-Z] | grep -v 'wtmp' | grep -v 'reboot' | grep -v 'unknown' |wc -l # 搜索登录人信息,每一行至少包含一个a-zA-Z的字符,并排除 wtmp reboot unknown,最后对结果统计行数
tee
通过>,>>可以将标准输出流重导向到文件、设备,如果我们既想将stdout输出到文件或设备,又想通过管道符进行后续处理,难道还要再读取一边,可以使用tee将输出流进行双重导向,既可以输出到文件也可以输出到屏幕,就可以使用管道命令处理了。
[dmtsai@study ~]$ tee [-a] file
选项与参数:
-a :以累加 (append) 的方式,将数据加入 file 当中!last | tee /tmp/test | cut -d ' ' -f 1
ls -al /etc | tee /tmp/test | less字符转换命令
-
tr: 删除或替换[dmtsai@study ~]$ tr [-ds] SET1 ... 选项与参数: -d :删除讯息当中的 SET1 这个字符串; -s :取代掉重复的字符!last | tr [a-z] [A-Z] # 大小写替换 last | tr -d ':' # 删除所有的: -
col: 用空格取代tab[dmtsai@study ~]$ col [-xb] 选项与参数: -x :将 tab 键转换成对等的空格键 -
join: 将2个文件相同的行组合成一行输出[dmtsai@study ~]$ join [-ti12] file1 file2 选项与参数: -t :join 默认以空格符分隔数据,并且比对『第一个字段』的数据, 如果两个文件相同,则将两笔数据联成一行,且第一个字段放在第一个! -i :忽略大小写的差异; -1 :这个是数字的 1 ,代表『第一个文件要用那个字段来分析』的意思; -2 :代表『第二个文件要用那个字段来分析』的意思。如何定义相同的行:
默认是以空格分割,取第一个。第一个相同就认为行相同,可以join,且相同的部分会放在行首。
join -t ':' -i -1 4 /etc/passwd -2 3 /etc/group | head -n 3 # 以:分开,忽略大小写,第一个文件取第4个元素,第二个文件取第3个元素,进行比对。最好是对文件先排序再join。 sort /etc/passwd | join -t ':' -i -1 4 -2 3 /etc/group | head -n 3 -
paste: 直接将2行粘在一起,没有对比条件[dmtsai@study ~]$ paste [-d] file1 file2 选项与参数: -d :后面可以接分隔字符。预设是以 [tab] 来分隔的! - :如果 file 部分写成 - ,表示来自 standard input 的资料的意思。paste -d ' ' file1 file2 cat ~/.bashrc | -d ' ' - file2 # -表示前面那个stdout对应的stdin -
expend: tab转空格,对比col可以指定一个tab对应几个空格,默认8个[dmtsai@study ~]$ expand [-t] file 选项与参数: -t :后面可以接数字。一般来说,一个 tab 按键可以用 8 个空格键取代。 我们也可以自行定义一个 [tab] 按键代表多少个字符呢!grep '^MANPATH' /etc/man_db.conf | head -n 3 | expand -t 6 | cat -A
split
文件分割
[dmtsai@study ~]$ split [-bl] file PREFIX
选项与参数:
-b :后面可接欲分区成的文件大小,可加单位,例如 b, k, m 等;
-l :以行数来进行分区。
PREFIX :分割出来的文件名前缀,后面跟aa,ab,ac...cd /tmp;split -b 300k /etc/services services # 将分割的文件放在/tmp下xargs
构造命令的参数
[dmtsai@study ~]$ xargs [-0epn] command
选项与参数:
-0 :如果输入的 stdin 含有特殊字符,例如 `, \, 空格键等等字符时,这个 -0 参数
可以将他还原成一般字符。这个参数可以用于特殊状态喔!
-e :这个是 EOF (end of file) 的意思。后面可以接一个字符串,当 xargs 分析到这个字符串时,
就会停止继续工作!
-p :在执行每个指令的 argument 时,都会询问使用者的意思;
-n :后面接次数,每次 command 指令执行时,要使用几个参数的意思。
当 xargs 后面没有接任何的指令时,默认是以 echo 来进行输出喔!id root # 获取账号信息
cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -p -n 1 id # 将/etc/passwd每行用:隔开,并取第一段,然后取前3行,然后每次取出一个值就询问一次,这样可以适配-n 1,因为id后面只跟1个参数xargs默认是以键盘作为输入流,所以xargs命令语法中没有指定命令执行的具体参数,这需要用户自己构建输入流
减号
-: 在管道命令中,-可以作为stdout或stdin来使用
tar -cvf - /home | tar -xvf - -C /tmp/test # 第一个-表示打包到stdout,第二个-表示解压数据源是stdin有时候是可以省略的:
cat /etc | less # 实际less后面就是前面stdout对应的stdinsed工具
sed是一个流编辑器,相对于vim,ed这种TUI编辑器。这在脚本中运用较多。
核心功能都在script中以命令的形式体现,也提供了一些基本选项。
核心概念
-
input stream: 包括管道input和file,以输入流的形式被sed读取,行是不会被重复读取的,比如用n/N命令提前读取下一行了,这一行也算读取了,sed再读取,也是继续读,因为pos不会回退。
-
pattern space: 模式空间,就是从input stream中读入的行所放入的位置,也是命令操作的地方。script只针对pattern space里的内容进行匹配,然后执行命令。 -
hold space: 个人理解,就是另一个临时存储区域 -
address: 除了
:,#,}其他command都支持地址,如果不提供地址则对每一行都执行命令,提供地址则对指定地址的行执行命令。地址后面加!表示取反。地址支持:
-
number: 就是第几行的意思,注意使用
-s选项后,就无效了。 -
first
step: 看起来像范围,但是不是,效果类似python中的2,可以匹配所有奇数行range(1,10,2)),就是匹配固定步长的行,比如1 -
$: 最后一行
-
/regexp/: 正则,用的最多的
-
addr1,addr2: 这才是表示地址范围,效果类似awk中的范围表示,也是先匹配addr1,然后一直直到匹配到addr2,中间的都有效,注意如果addr2是正则,对于addr1匹配的行,不会再去匹配,比如
/foo/,/bar/范围,如果有2行foo bar\nbar,addr2为/bar/不会匹配foo bar这行,因为addr1已经匹配了,addr2只会匹配后面的行。例子:
sed -n '/./,/^$/p' file # 打印完整段落 -
0,addr2: 正常行是从第1行开始,这里为0,表示addr2从第一行开始匹配。如果为
1,addr2,则addr2从第2行开始匹配,符合上一条的表述。这个规则只有addr2是正则才生效。 -
addr1,+N: 匹配addr1和后面的N行
-
addr1,~N: 匹配addr1以及后面的行,直到行号是N的倍数
-
-
command: 操作的命令,比如添加,修改,删除,替换等等
基本逻辑
sed将行放入pattern space中,然后执行脚本,看是否匹配,匹配则执行命令,然后print(默认行为),不匹配就只会print(默认行为)。
graph LR input[input] --> ps[pattern space] --> match{address match} match --> |yes| command[exec command] --> print[print pattern space] match --> |no| print
选项说明
-
-n: 脚本执行完后pattern space中的内容默认执行print,-n可以disable这个行为 -
-e: 指定script,默认把第一个非选项参数当作script,剩余参数当作input files。可以使用-e多次指定script。指定多个
-e时,实际就是把所有script放一起执行,匹配就执行对应的命令,不匹配就跳过到下一个-e而且前面的执行结果会影响后面的脚本执行,比如
echo 'a\na\n' | sed -e '1d' -e '1s/a/b/' # 会输出a,1d已经删了,1已经没有了,后面的替换失败,第2行a匹配不了2个条件,执行默认print,所以输出a -
-E: 扩展正则 -
-i[suffix]: 直接编辑,如果有suffix则会进行原文件备份。
常用命令
一下所有例子中的\n为换行符。
-
: lable: 定义一个lable,用于b/t/T跳转,就是goto语法 -
=: 打印当前行号 -
a\<text>: 添加行,echo 'a' | sed '1a\new line'输出: a\nnew line -
i\<text>: 插入行 -
c<text>: 替换行
-
d: 删除行
-
D:删除pattern space中第一行,并且对于pattern space中剩下的内容重新开始执行脚本,而不是读取下一行再开始脚本
例子:
echo "id\n1\n2\n3\n" | sed '/^id/{N;D;P}' # 输出: 1\n2\n3 #脚本 /^id/{N;D;P} 的执行过程是: # - 遇到 id 行命中地址:执行 N,把下一行并入模式空间,变成 id\n1。 # - 继续执行 D:删除模式空间中第一个换行符之前的部分(即 id\n),剩下1,并“立即从脚本顶部重启”,不读取新行、也不打印任何东西。 # - 重启后,当前模式空间是1,已不匹配 /^id/,所以 {N;D;P} 块不再执行;到本轮结束,默认“自动打印”把1打印出来。 # - 接着读取后续输入行2、3,同样不匹配地址,按默认自动打印输出它们。 # 实际上P从未执行过 -
r <filename>: 将文件内容添加到匹配行的后面 -
R <filename>: 将文件中的行添加到匹配行的后面,且<filename>的行也是input stream,每次读取一行,pos向前移动。 -
h/H/g/G/x: hold space和pattern space数据交换相关操作,具体man -
q|Q: 退出脚本,q在没有-n时,会print pattern space中的内容,而Q则不管,没有任何输出 -
l[ <width]: 醒目的打印(测试就是加了个$在行尾),如果提供width,作为输出的最大宽度,会截断超出的字符。 -
n|N: 读取或追加下一行到pattern space -
p|P: 打印pattern space,或者打印其中的第一行 -
s/regexp/replacement/: 匹配行的正则替换,支持/g TODO: 是否支持g i 等flag -
w|W <filename>: pattern space中的内容或者第一行写入文件 -
y/source/dest/: 字符映射
lable使用
相关命令:<lable>,b [<lable>],t [<lable>],T [<lable>]
本质就是用来脚本跳转。
b: 无条件跳转,没有lable则跳到script最后。
t: 有成功的s///才跳,需要自上次读取新行或者自上次t/T后,有成功的替换,才会跳转。
T: 和t相反,有失败的替换才跳
例1:
echo "foo bar\n" | sed 's/foo/bar/; t changed; b; :changed s/^/[CHG] /'
# 输出: [CHG] bar bar
# 替换成功跳到changed lable,也就是:changed定义的地方,执行后面的命令,加上CHG前缀
echo "bar bar\n" | sed 's/foo/bar/; t changed; b; :changed s/^/[CHG] /'
# 输出bar bar
# 因为没有成功的替换,t命令不生效,继续执行b,跳到脚本尾,结束,输出pattern space中的内容例2:
sed ':a; s/ / /; ta' file
# 模拟循环printf
格式化输出
[dmtsai@study ~]$ printf '打印格式' 实际内容
选项与参数:
关于格式方面的几个特殊样式:
\a 警告声音输出
\b 退格键(backspace)
\f 清除屏幕 (form feed)
\n 输出新的一行
\r 亦即 Enter 按键
\t 水平的 [tab] 按键
\v 垂直的 [tab] 按键
\xNN NN 为两位数的数字,可以转换数字成为字符。
关于 C 程序语言内,常见的变数格式
%ns 那个 n 是数字, s 代表 string ,亦即多少个字符;
%ni 那个 n 是数字, i 代表 integer ,亦即多少整数字数;
%N.nf 那个 n 与 N 都是数字, f 代表 floating (浮点),如果有小数字数,
假设我共要十个位数,但小数点有两位,即为 %10.2f 啰!常用表格格式的输出,用tab隔开
printf '%s\t %s\t %s\t %10s\t %10i\t %10.2f\t' $(cat file) # printf不是管道命令awk
sed针对一行一行的数据处理,awk是针对某一行分割后的字段处理.更详细的内容参考man awk.
awk本质是运用mawk语言,所以可以进行非常复杂的逻辑处理,不是简单的命令行工具,可以实现非常复杂的功能。
重点概念
record: 对于输入分割为一条条记录,默认分割符为\nfield: 对record进行分割,默认按<space>分割pattern: 即匹配条件,按正则匹配,~表示匹配,!~表示不匹配action: 即程序执行块,用{}包裹变量: 可以是内置的比如ARGV,NR,NF等等,也可以是自行定义的
awk命令行只提供了简单的选项,比如-F,指定field分隔符,-v指定变量(内置和自定义都可以设置),基本就这2个,--表示选项结束,后面就是程序了,程序后面是文件,或者stdin。
mawk [-W option] [-F value] [-v var=value] [--] 'program text' [file ...]
mawk [-W option] [-F value] [-v var=value] [-f program-file] [--] [file ...]整个核心逻辑在程序上,程序实际上就一个范式:
pattern {action}其中pattern可以是:
-
BEGIN -
END -
expression -
expression, expression: 表示表达式约束的范围,也就是2个表达式匹配到的记录范围,比如NR 1,NR 5,表示第1到5条记录,又比如/^id/,/^name,表示匹配id开头到name开头的record。这里有个误区,比如匹配第1到第5行,不是NR >= 1, NR ⇐ 5,而是 NR 1, NR 5,范围模式的逻辑是,record匹配第一个条件时,开始,直到某条record满足第2个条件时结束,这中间的records就是选中的范围,如果record同时满足2个条件,并不会结束,相对于没有满足条件2(可能类似!exp1 && exp2 ,exp1为true就继续下一行了)。所以NR >= 1时,所有记录都满足,都会去执行对应的action。
所以exp1,exp2的条件应该互斥。
Note
One, but not both, of pattern {action} can be omitted. If {action} is omitted it is implicitly { print }. If pattern is omitted, then it is implicitly matched. BEGIN and END patterns require an action.
核心逻辑
在进入程序执行之前所有内置变量会被初始化,包括你通过命令行传入的-v,这些会作为你程序执行的环境,换句话说,你可以修改这些变量的值,以影响后面程序的执行。
BEGIN在any input读取之前执行,这里常用作调整变量值,比如OFS,ORS等,以及初始化自定义变量。
可以有多个BEGIN他们按顺序执行。
然后开始读取input,每读取一个record,将匹配每一个pattern(BEGIN,END除外),匹配成功则执行对应的action。
当没有输入了,则执行END
Note
Once an input stream is open, each input record is tested against each pattern, and if it matches, the associated action is executed. An expression pattern matches if it is boolean true (see the end of section 2). A BEGIN pattern matches before any input has been read, and an END pattern matches after all input has been read. A range pattern, expr1,expr2 , matches every record between the match of expr1 and the match expr2 inclusively.
action
即程序块,可以包含如下内容:
if ( expr ) statement
if ( expr ) statement else statement
while ( expr ) statement
do statement while ( expr )
for ( opt_expr ; opt_expr ; opt_expr ) statement
for ( var in array ) statement
continue
break基本类似c的语法表示,包括操作符。
有很多内置函数,比如gsub,sub,printf,match等等,可覆盖常规需求。
可以自定义函数。
例子
#!/usr/bin/awk -f
# begin
BEGIN {
print "begin awk ------------";
FS=","; # -F指定的本质就是这里的FS变量
ARGV[1]="./export.csv.bak"; # 很有意思的用法,直接修改命令行参数,定义输入的文件
ARGC=2; # 只有2个参数,ARGV[0]就是程序,必然是awk,另一个就是上面定义好的文件
}
# pattern {action}
$0 !~ /^id/ {
print ($1,$2,NF,NR,NFR,"(NF="NF")") # 字符串拼接不需要使用+ ..之类,类似python 直接"abc" "bcd" == "abcbcd"
}
# omitted pattern means has matched
{
if (NR > 5) exit;
}
# end
END {
print "complete awk------------";
test();
}
# user function
function test()
{
print "test function"
}man中也举了很多实际例子,可以看出功能的强大,甚至模拟其他工具。
find
GNU系软件,更符合直觉的替代品有fdfind。
find是一个功能强大的文件搜索命令,语法格式为:
find [-H] [-L] [-P] [-D debugopts] [-Olevel] [starting-point...] [expression]
# -H -L -P 是关于symbolic link的选项,明确是否follow
# -D debug模式,输出更多信息
# -Olevel 表达式优化,默认为1
# starting-point 就是要搜索的路径
# expression 核心规范,怎么搜索,以及怎么处理的逻辑重点概念
- expression可以包含5个部分: tests,actions,global options,position options,operators
- 上面的5个部分都可以看作item,每个item都会返回true or false
- item和item之间隐式的使用 and 连接,可以显示的使用
-a表示and,-o表示 or,且遵循短路原则,还支持()来提升优先级,!表示否定,当然这2个需要escape,否则会被shell当作特殊符号处理。 - 所以expression本质上就是
(),!,and,or关联起来的布尔表达式,且遵循短路原则。
position options
总是返回true,且只影响它后面的tests。
-daystart: a/c/m时间相关,用于表示时间是从什么开始算,默认从命令运行时间,-daystart表示从今天0点开始。-regextype: 使用哪种正则,常用的有awk/grep/emacs,默认为emacs-warn/-nowarn: on/off warn消息
global options
总是返回true。影响整个命令行的tests。
-d: 即-depth指定搜索的深度-maxdepth: 最大搜索深度-mindepth: 从第几层开始搜索-mount: 只搜索当前文件系统-noleaf: (不是很理解),对于一些特殊的文件系统或者发现find有遗漏时,可以使用。-files0-from <file>: 从文件中而不是命令行中读取starting points
tests
最常用的部分,返回true or false。
这里用到的整数n,有n, +n, -n表示明确的n,大于n,小于n。
非常多,具体见man。列举几个:
-
-amin <n>: n分钟之前有access。atime:表示n天以前有access。cmin,ctime,mmin,mtime,都一样,c表示status changed,m表示data modified -
-anewer <reference>: current file a时间 > reference的m时间cnewer: c时间 > reference的m时间newer: m时间 > reference的m时间 -
-newerXY <reference>: 这个更灵活,X表示当前文件的某个时间,Y表示reference的某个时间即current X > reference Y.
X/Y可以是: a,c,m,B(birth time创建时间),t
只有Y可以是t,此时reference表示具体时间。
-
-empty: 空文件或目录 -
-executable: 可执行文件,可进入目录 -
-false/-true: 直接返回false/true,当作条件使用 -
-name <pattern>:最常用,pattern为glob不是regex-iname,忽略大小写-lname,-ilname,匹配link,如果开启了-L,会直接返回false,因为相对于没有link了-path,-ipath,匹配path,注意. /就是表示本身,比如./*.py,这不是正则。 -
-regex <pattern>: 文件名的完整正则匹配,注意这不是搜索(包括上面的-name,-path也一样),这是正则的完整匹配,即^...$匹配-iregex,忽略大小写 -
-perm <mode>: 权限匹配。mode: ugo精确匹配;-mode: ugo包含匹配,即实际权限 >= mode;/mode: ugo任意一个匹配即可。 -
-type: 也是用的非常多,b(block设备,比如/dev/sda),c(character流设备,比如/dev/tty,/dev/stdou),p(pipe,进程间通信用,比如/tmp/xxxin),d(目录),f(regular文件),l(symbolic link),s(socket)
actions
根据执行是否成功来返回true or false.
-
-delete: 注意不要放在expression的最前面,否则可能把整个starting points都删掉。delete action不会删掉目录,除非它是空的。 -
-exec <command>: 执行命令,每个文件都执行一次,exec <command> {} +,效果类似进行了xargs,拼接了所有匹配的文件执行了一次。命令返回0,则返回true。
命令后面的都是参数直到遇到
;,由于;在shell中表示命令分割,所以这里要escape。{}占位符表示当前文件名。
execdir: 执行目录为匹配到文件所在目录,而不是cwd。也有类似的execdir <command> {} +ok|okdir: 提示版exec,需要用户同意。 -
-ls: 等同于ls -dils。 -
-print: 打印出来,用\n分割,-print0,用\0空字符分割 -
-printf: 格式化打印,类似C,有很复杂的格式实现。-
%a: ctime格式的access时间 -
%A<k>: 以k所在格式显示access时间,k可以有非常多的选项,比如@表示时间戳,F,H等等。其他时间也都有类似的,比如
%c,%C<k>等等 -
%f: file basename -
%h: dirname -
%p: file name -
%P: 包含starting point的file name
-
-
prune: 如果这是一个目录,则不进入,就是跳过某些目录。返回true。 -
-quit: 退出find。
operators
(),!,-a,-o,连接item。
,,这个主要用来表示多个文件类型,-type d,f,p。
核心逻辑
对于starting points,扫描每一个file,然后执行表达式,表达式就是由operators连接的布尔表达式,短路执行。
例子
find . -exec file {} \; # 对每个file执行file命令
find /tmp -name test.* -type f -print0 | xargs -0 /bin/rm -f # 找到所有test.*文件,然后用空字符拼接,传给xargs用空字符分开,然后执行rm
find $HOME -mtime 0 # 过去1天内有修改过的
find . -perm -664 # 至少有664权限的,比如777
find . -path './test*' -prune -o -type f -print # 跳过./test相关文件夹,打印其他文件。 匹配path为true,prune为true,短路,后面的不执行了grep
GNU命令,用于查找文件内容。
用法:
grep [OPTION...] PATTERNS [FILE...]
grep [OPTION...] -e PATTERNS ... [FILE...]
grep [OPTION...] -f PATTERN_FILE ... [FILE...]Note
这里的FILE,可以理解为linux下的file,也就是一切,并不是regular file。
没有提供FILE,则默认递归搜索cwd,standard input需要显示使用-
基本选项
-E: extand regex模式-F: 把regex当作普通的字符串匹配-e: 可以重复使用-e多次指定pattern,表示or-v: revert match,反向匹配-w: 匹配word,意味者boundary,也可以用regex模拟,比如\Whello\W-x: line match,本质就是^...$,整行匹配-c: 输出文件对应匹配的行数-L: 输出没有匹配到的文件name-l: 输出有匹配到的文件name,由于只要匹配到就立即结束,所以速度会快很多-m: 搜索多少行最多-o: print only matched partq: quiet,silent,好处是有匹配到立即exit,效率高-H: print file name-n: print line number-T: 输出内容格式对齐-Z: 输出的文件名称后面使用空字符连接,而不是默认的:-A,-B,-C: matched part上下指定行内容-d { read | skip | recurse }: 如果FILE是目录时的action--exclude[-dir]=<GLOB>,--include=<GLOB>: 排除或包含文件-r: 等于-d recurse-R: 效果等于-r,且follow symbolic link-z: 输出结果使用空字符连接而不是\n
例子
grep -n -- 'f.*\.c$' *g*.h /dev/null
# 这是man中的例子
# --表示选项结束,所以*g*.h表示文件,这将被shell展开(不是grep的能力)
# 最后的/dev/null 表示输出的文件名的目标文件,这是文档中没有提到的用法diff
比较文件差异
[dmtsai@study ~]$ diff [-bBi] from-file to-file
选项与参数:
from-file :一个档名,作为原始比对文件的档名;
to-file :一个档名,作为目的比对文件的档名;
注意,from-file 或 to-file 可以 - 取代,那个 - 代表『Standard input』之意。
-b :忽略一行当中,仅有多个空白的差异(例如 "about me" 与 "about me" 视为相同
-B :忽略空白行的差异。
-i :忽略大小写的不同。to-file作为标准进行对比,用于差异化描述时针对的对象。
diff可以对比2个目录下的所有文件,只是对比目录结构的差异。
[dmtsai@study ~]$ diff /etc/rc0.d/ /etc/rc5.d/cmp用于字节对比
[dmtsai@study ~]$ cmp [-l] file1 file2 选项与参数: -l :将所有的不同点的字节处都列出来。因为 cmp 预设仅会输出第一个发现的不同点。
根据对比差异,可以制作patch,然后更新旧文件即可。
vim/neovim中可以使用diffpath命令将patch更新到文件中。
curl
curl的用法,模拟url客户端,可以一定程度上代替postman等软件,还可以实现下载。
curl http://localhost:8080 # get请求
curl -o test.html http://localhost:8080/index.html # 将返回的内容保存为test.html,相当于wget
curl -O http://localhost:8080/index.html # 将返回的内容保存为index.html
curl -H 'Accept: application/json' -H 'Content-type: application/json' http://localhost:8080 # 修改请求头
curl -b 'foo=bar;foo2=bar2' http://localhost:8080 # 发送cookie
curl -c cookies.txt http://localhost:8080 # 将服务端返回的cookie写入文件
curl -i http://localhost:8080 # 先输出response headers 然后再输出返回的内容
curl -I http://localhost:8080 # 只输出response headers
curl -d 'foo=bar' -d 'foo2=bar2' http://localhost:8080 # 默认以application/x-www-form-urlencoded的格式发送post请求
curl --data-urlencode 'foo=bar&foo2=bar2' http://localhost:8080 # 类似-d,只是进行了url编码
curl -F 'file=@/root/index.png;type=image/png' http://localhost:8080 # 上传二进制文件,并可以指定MIME类型
curl -G -d 'foo=bar' -d 'foo2=bar2' http://localhost:8080 # 以get形式发送,-d构建的是get请求参数
curl -G --data-urlencode 'foo=bar' http://localhost:8080 # 和上面的区别是参数进行了编码
curl -L http://localhost:8080 # 跟随服务器的重定向
curl --limit-rate 200k http://localhost:8080 # 限制请求响应的带宽为200KB
curl -u 'foo:12345' http://localhost:8080 # 自动转换为Authorization: Basic xxxx 认证头
curl -v http://localhost:8080 # 通信追踪,用来调试
curl -x sock5://localhost:1080 http://localhost:8080 # 使用代理
curl -X POST -d 'foo=bar&foo2=bar2' http://localhost:8080 # 设置请求方法
curl -X POST -H 'Content-type: application/json' -d '{"name":"foo","age":11}' http://localhost:8080 # 注意body如果是json格式,不只是要改Content-type,-d指定的参数也必须是Json格式的字符串。shell script
基础知识:
- 进程修改的环境变量只影响当前进程及当前进程衍生的子进程。进程一但退出,修改和定义的变量就会失效。子进程修改的变量影响不到父进程,这是单向传递。
bash执行脚本是在子bash中执行,source/.执行是在当前bash中执行。- shell script需要在开头使用
#!/bin/bash声明个脚本使用的是哪个shell。(一般就用默认的/bin/bash) - shell script 以sh作为文件扩展名,vim时会有颜色提示
条件判断
test: 可以利用test进行测试,内容是否为true/false
-
关于某个档名的『文件类型』判断,如 test -e filename 表示存在否
- -e 该『档名』是否存在?(常用
- -f 该『档名』是否存在且为文件(file)?(常用)
- -d 该『文件名』是否存在且为目录(directory)?(常用)
- -b 该『档名』是否存在且为一个 block device 装置?
- -c 该『档名』是否存在且为一个 character device 装置?
- -S 该『档名』是否存在且为一个 Socket 文件?
- -p 该『档名』是否存在且为一个 FIFO (pipe) 文件?
- -L 该『档名』是否存在且为一个连结档?-r 侦测该档名是否存在且具有『可读』的权限?
-
关于文件的权限侦测,如 test -r filename 表示可读否 (但 root 权限常有例外)
- -r 侦测该档名是否存在且具有『可读』的权限?
- -w 侦测该档名是否存在且具有『可写』的权限?
- -x 侦测该档名是否存在且具有『可执行』的权限?
- -u 侦测该文件名是否存在且具有『SUID』的属性?
- -g 侦测该文件名是否存在且具有『SGID』的属性?
- -k 侦测该文件名是否存在且具有『Sticky bit』的属性?
- -s 侦测该档名是否存在且为『非空白文件』?
-
两个文件之间的比较,如: test file1 -nt file2
- -nt (newer than)判断 file1 是否比 file2 新
- -ot (older than)判断 file1 是否比 file2 旧
- -ef 判断 file1 与 file2 是否为同一文件,可用在判断 hard link 的判定上。 主要意义在判 定,两个文件是否均指向同一个 inode 哩!
-
关于两个整数之间的判定,例如 test n1 -eq n2
- -eq 两数值相等 (equal)
- -ne 两数值不等 (not equal)
- -gt n1 大于 n2 (greater than)
- -lt n1 小于 n2 (less than)
- -ge n1 大于等于 n2 (greater than or equal)
- -le n1 小于等于 n2 (less than or equal)
-
判定字符串的数据
- test -z string 判定字符串是否为 0 ?若 string 为空字符串,则为 true
- test -n string 判定字符串是否非为 0 ?若 string 为空字符串,则为 false。注: -n 亦可省略
- test str1 == str2 判定 str1 是否等于 str2 ,若相等,则回传 true
- test str1 != str2 判定 str1 是否不等于 str2 ,若相等,则回传 false
-
多重条件判定,例如: test -r filename -a -x filename
- -a (and)两状况同时成立!例如 test -r file -a -x file,则 file 同时具有 r 与 x 权限 时,才回传 true。
- -o (or)两状况任何一个成立!例如 test -r file -o -x file,则 file 具有 r 或 x 权限时,就可回传 true。
- ! 反相状态,如 test ! -x file ,当 file 不具有 x 时,回传 true
[] 判断
利用 [] 包裹判断条件,在shell script中使用较多,条件写法同上。
注意:[]包裹条件时,里面每个条件因子左右都要有空格,比如:
[ $name == "hello" ] # $name 和 ”hello" 左右都要用空格分开同时用[]写法,组合多个条件时,即可以使用上述-a,-o,还可以将多个条件分开写,用&&,||连接,比如 [] && []。
脚本参数
脚本可以向命令一样,后面跟参数(实际命令也可以看作是由脚本封装而来)。
script_name p1 p2 p3 ...$0: 文件名,表示script_name。$1,$2,$3..: 表示后面的p1,p2,p3…$#: 参数个数$@: 所有参数,每个参数单独用表示,”${1}”,”${2}”,”${3}”…$*: 所有参数,统一表示,”${1} ${2} ${3}”
这些代表执行脚本时各个变量,可以直接在脚本中使用
#!/bin/bash
echo "The script name is ==> ${0}"
echo "Total parameter number is ==> $#"
[ "$#" -lt 2 ] && echo "The number of parameter is less than 2. Stop here." && exit 0
echo "Your whole parameter is ==> $@"
echo "The 1st parameter is ==> ${1}"
echo "The 2st parameter is ==> ${2}"可以使用shift偏移变量
# 比如参数有 1,2,3,4,5,6
shift # 第一次偏移,偏移数量为1
2,3,4,5,6 # 偏移后的参数
shift 3 # 第二次偏移,偏移量为3
5,6 # 偏移后的结果if判断
前面都在利用[]进行条件判断,然后利用&&,||短路原则执行后面的语句。但是对于复杂语句的执行就很吃力了。可以使用if语句。
-
简单if
if [ var1 == var2 ]; then ....条件为true时执行.... fi # if的倒写,代表if语句的结束 -
if else
if [ var -ge 1 ]; then ... >= 1 执行... else ... < 1执行... fi -
if elif
if [ var -ge 1 ]; then ... >= 1 执行... elif [ var -ge 2 ]; then ... >=2 执行... else ... < 1 && > 2执行... fi -
case esac
case $char in "a") ...==a时执行... ;; "b") ...==b时执行... ;; *) ...其他情况... ;; esac
function
先定义后使用
function fn() {
}
# 可以接收参数,以$1,$2...表示,注意和执行整个脚本传进来的$1,$2区分#!/bin/bash
function printit(){
echo "Your choice is ${1}" # 此时${1} 为调用处传入的第一个参数
}
case ${1} in
"one")
printit 1
;;
"two")
printit 2
;;
"three")
printit 3
;;
*)
echo "Usage ${0} {one|two|three}"
;;
esacloop
-
while..do..done
while条件为fasle时跳出循环
#!/bin/bash while ["${yn}" == "yes" ] do read -p "please input yes to stop the program: " fn done echo "You have input the correct answer." -
until..do..done
和while的唯一区别是,但until后面判断为true时跳出循环
-
for循环
#!/bin/bash for animal in dog cat pig do echo "animal is ${animal}" done#!/bin/bash users=$(cut -d ":" -f1 /etc/passwd) # 获取用户名 for username in ${users} do id ${username} # id查看详细信息 done如果是把整数作为for限定,可以借助
seq start end命令来生成从start到end(包括)的整数。还可以使用
{start..end}来设置,这种方式还可以设置字母(注意是2个点) -
for i循环
#!/bin/bash #read -p "please enter a number: " num #test ${num} -lt 0 && echo "the number must > 0." && exit 0 until [ ${num} -gt 0 ] do read -p "please input a number greater than 0 : " num done s=0 for(i=0;i<=${num};i++) do s=$((${s}+${num})) done echo "sum is : ${s}"
语法检查
[dmtsai@study ~]$ sh [-nvx] scripts.sh
选项与参数:
-n :不要执行 script,仅查询语法的问题;
-v :再执行 sccript 前,先将 scripts 的内容输出到屏幕上;
-x :将使用到的 script 内容显示到屏幕上,这是很有用的参数!可以运行前检查一遍。
用户权限
主要涉及3个文件/etc/passwd 用户文件,/etc/group群组文件,/etc/shadow密码文件
-
/etc/passwd
展示结构为: 用户名:密码(密码现在都放在/etc/shadow文件,这里用x):uid:gid:用户说明信息(没什么用基本):home路径:shell
-
/etc/shadow
展示结构为: 用户名:密码:最近密码修改日期:密码不可变动天数(即设置后几天内不能修改密码):密码过期天数:过期前的警告天数:过期后的宽限天数:账号失效日期:保留字段
passwd 密码 来修改密码
-
/etc/group
展示结构为: 组名:组密码:gid:组里的用户
用户可以通过root用户usermod指令将用户加到群组里。也可以利用群组管理员,加入到对应的群组里。群组管理员信息在/etc/gshadow文件里
初始群组与有效群组
-
初始群组
/etc/passwd,第四个字段gid就是初始群组,由于是初始群组,所以/etc/group中对应的群组,第四个字段是省略的,不需要再指明用户了。如果还拥有其他群组,那就需要在第四列中指明用户。
-
有效群组
groups: 指令显示的第一个群组就是有效群组,新建文件时,文件权限中的群组就是有效群组。newgrp: 切换有效群组。注意被切换的群组一定是当前用户所拥有的。这个指令会新开一个shell,在这个shell中有效群组是你切换过来的,原来的shell中还是原来的。可以通过
$$查看pid得知。
账号管理
-
建立账号
useradd xxx # 新增账号 passwd xxx # 设置密码 后面不带账号名代表修改当前用户密码useradd有很多选项,比如可以设置为系统账号,设置UID,GID(初始群组),失效日期等,但是实际上系统已经预设了很多设置,可以通过
useradd -D查看,一般使用默认的就可以了。同样的passwd也有很多选项设置,主要是/etc/shadow里的内容,比如密码不可修改天数,多少天后过期,警告天数,冻结账号等,一般用默认的就可以了。
可以通过chage -d 0 账号,让这个账号在登录后强制修改密码。原理是-d 0会将账号的最后修改时间改为1970/1/1这个初始值。
-
usermod使用
usermod作为root权限指令,几乎可以用来管理账号相关的所有事项。
[root@study ~]# usermod [-cdegGlsuLU] username 选项与参数: -c :后面接账号的说明,即 /etc/passwd 第五栏的说明栏,可以加入一些账号的说明。 -d :后面接账号的家目录,即修改 /etc/passwd 的第六栏; -e :后面接日期,格式是 YYYY-MM-DD 也就是在 /etc/shadow 内的第八个字段数据啦! -f :后面接天数,为 shadow 的第七字段。 -g :后面接初始群组,修改 /etc/passwd 的第四个字段,亦即是 GID 的字段! -G :后面接次要群组,修改这个使用者能够支持的群组,修改的是 /etc/group 啰~ -a :与 -G 合用,可『增加次要群组的支持』而非『设定』喔! -G后面列的组会替代该账号所有的非初始组,添加了-a就不会替代,只是追加。 -l :后面接账号名称。亦即是修改账号名称, /etc/passwd 的第一栏! -s :后面接 Shell 的实际文件,例如 /bin/bash 或 /bin/csh 等等。 -u :后面接 UID 数字啦!即 /etc/passwd 第三栏的资料; -L :暂时将用户的密码冻结,让他无法登入。其实仅改 /etc/shadow 的密码栏。(密码前面加!,让密码改变,造成无法登录) -U :将 /etc/shadow 密码栏的 ! 拿掉,解冻啦! -
删除用户
[root@study ~]# userdel [-r] username 选项与参数: -r :连同用户的家目录也一起删除 -
其他指令
id: 查看用户信息chfn: 修改个人展示信息,即/etc/passwd第三列chsh: 修改shell
这些功能就是提供给普通用户修改自己的账号的。
群组管理
-
添加群组
[root@study ~]# groupadd [-g gid] [-r] 组名 选项与参数: -g :后面接某个特定的 GID ,用来直接给予某个 GID ~ -r :建立系统群组啦!与 /etc/login.defs 内的 GID_MIN 有关。简单使用默认就可以了
-
修改群组
[root@study ~]# groupmod [-g gid] [-n group_name] 群组名 选项与参数: -g :修改既有的 GID 数字; -n :修改既有的组名 -
删除群组
[root@study ~]# groupdel [groupname]
ACL权限
默认的owner:group:others,无法做到给某一个用户或群组单独授权,比如这个群组不是该文件的群组,那群组里的成员除非是文件拥有者,否则只能是others权限,在某些时候显然不够用,所以出现ACL这种更细粒度的授权模式,目前一般的挂载参数中都默认支持了ACL,可以通过dmesg | grep -i acl查看。
设定ACL
[root@study ~]# setfacl [-bkRd] [{-m|-x} acl 参数] 目标文件名
选项与参数:
-m :设定后续的 acl 参数给文件使用,不可与 -x 合用;
-x :删除后续的 acl 参数,不可与 -m 合用;
-b :移除『所有的』 ACL 设定参数;
-k :移除『预设的』 ACL 参数,关于所谓的『预设』参数于后续范例中介绍;
-R :递归设定 acl ,亦即包括次目录都会被设定起来;
-d :设定『预设 acl 参数』的意思!只对目录有效,在该目录新建的数据会引用此默认值使用较多的就是 -m,-x,-b 。设定ACL权限后,ls -l显示的权限后面有个+号。
-
给用户增加ACL权限
setfacl -m u:user1:rx testfile # 单独给user1这个用户授权rx,省略中间的用户名,就是给文件拥有者授权。 -
给群组增加ACL权限
setfacl -m g:group1:rx testfile # 单独给group1这个群组授权rx -
设定有效权限
setfacl -m m:r testfile # 有效权限限定了能增加的ACL权限范围,这里限定了r,那么就算给用户,群组授予了rx,也只有r生效 -
权限继承
默认给一个目录设定ACL后,只对这个目录生效,目录下新增加的文件或目录不会继承ACL
setfacl -m d:u:user1:rx test # test目录下新增的文件或目录,user1会自动拥有rx权限这是设置新增继承,对已有的呢,很简单,
-R递归设置就可以了。setfacl -m u:user1:- testfile 可以通过这种方式设置0权限
查看ACL
正常通过ll是看不到ACL权限的
getfacl testfile # 参数基本痛setfacl删除ACL
setfacl -b testfile # 删除该文件所有的ACL权限
setfacl -x u:user1 testfile # 删除这个文件user1的ACL权限
setfacl -x g:group1 testfile # 删除这个文件group1的ACL权限
setfacl -x d:u:user1 test # 删除user1的继承权限切换身份
-
su切换
su - # 切换到root su -l user1 # 切换到user1 su -m user1 # 切换到user1,但是使用当前的环境配置文件 su -l -c {command} user1 # 以user1的身份执行指令su命令用户切换到用户,输入切换到的用户密码。
-
sudo
sudo只有系统管理员(/etc/sudoers)才有权限使用的命令。sudo命令可以以root或其他用户来执行指令,输入当前用户的密码。
[root@study ~]# sudo [-b] [-u 新使用者账号] 选项与参数: -b :将后续的指令放到背景中让系统自行执行,而不与目前的 shell 产生影响 -u :后面可以接欲切换的使用者,若无此项则代表切换身份为 root 。有些系统账号是nologin shell,你无法切换过去,只能以sudo的形式切换到这个用户执行指令。
设置sudoers:
使用
visudo命令修改这个文件-
添加用户
# 账号 主机名(可切换的身份) 可下达的指令 user1 ALL=(ALL) ALL # 这个账号在以某些主机连接到系统的情况下,可以切换的用户,可以使用的指令 -
添加群组
以
%开头表示群组%wheel ALL=(ALL) ALL
-
特殊shell
有些时候希望添加的用户并不具备登录权限,只能使用某些服务,可以设置shell为sbin/nologin,比如某些系统账号。
定时任务
一次性任务
at任务
/etc/at.allow,/etc/at.deny,先去allow中查找是否允许,如果没有,则取deny中查找是否禁止,如果2个文件都没有,则只允许root设置at任务。(一般没有allow文件,但会有一个deny文件,如果deny文件为空,则表示任何人都可以创建at任务)
[root@study ~]# at [-mldv] TIME
[root@study ~]# 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
就是说,在某个时间点『再加几个时间后』才进行。at now + 2 minutes
echo "hello,world" >> /tmp/hello.txt
#ctrl + d 结束输入
atq # 查询
atrm # 删除注意at的输出与终端环境无关,所有的输出都会导向到mailbox中,所以要么指定重导向输出,或者可以使用 >> /dev/tty1 指定终端
循环任务
cron任务
同样有/etc/cron.allow,/etc/cron.deny文件限制用户设置cron任务
[root@study ~]# crontab [-u username] [-l|-e|-r]
选项与参数:
-u :只有 root 才有这个选项,帮其他用户建立cron任务
-e :编辑 crontab 的工作内容
-l :查阅 crontab 的工作内容
-r :移除所有的 crontab 的工作内容,若仅要移除一项,请用 -e 去编辑。30 12 * * * echo "hello,$(date)" >> /tmp/hello.txt前半部分时间格式,后面是命令
* * * * *
分 时 天 月 周 (周用0-7表示,0,7都表示星期天)
,表示多个,比如 0 3,6 * * * 表示每月,每周,每天的3点,6点整执行
-表示区间,比如 0 3-6 * * * 表示每月,每周,每天的3到6点整执行
/n表示每隔n单位,比如*/1 * * * * 表示每1分钟执行一次上面是针对个人的
-
系统性的cron任务直接编辑 /etc/crontab即可
vim /etc/crontab # 注意需要设置shell PATH 以及时间和命令中间的用户 -
自己开发的软件cron配置文件放在/etc/cron.d下面
这个文件下的内容,主要是配置你的cron怎么执行的
-
系统性的cron任务,还有一种偷懒的方式
把脚本文件放在/etc/cron.daily,/etc/cron.weekly,/etc/monthly,/etc/cron.hourly 等文件下,会按对应的周期执行
如果系统关机了怎么办,这段时间的cron任务会丢失吗,anacron就是用来处理关机期间未被执行的cron任务的
/etc/cron.d/0hourly配置文件会每小时去/etc/cron.hourly目录下执行所有可执行的脚本,而/ect/cron.hourly/0anacron这个脚本又会执行anacron命令,并去加载/etc/anacrontab配置文件,根据这个配置文件每天、每月,每周的去分析/etc/cron.daily,/etc/cron.weekly,/etc/cron.monthly内的脚本文件(如果时间到了就去执行,如果没按计划执行也会优先被执行)
进程管理
基础概念
每一个进程都有独立的PID
父子进程是通过fork - and - exec的模型建立
graph LR 1["父进程 pid=x 父程序"] --fork复制进程--> 2["暂存进程 pid=y ppid=x 父程序"] --exec 子程序--> 3["子进程 pid=y ppid=x 子程序"]
通过bash执行命令时,会复制这个bash进程,然后赋予新的pid,同时根据启发这个进程的用户与相关属性授予这个进程相关权限,并将ppid指向被复制的bash pid,然后在这个复制的pid进程中执行这个指令的内容。
像很多命令,比如ls,mkdir,touch,cat等命令,会开启新进程,但是由于程序很快执行完成,这个进程也很快会消失,但是有些进程是常驻内存的,比如某些服务。有些命令会有stdout,这个显示是在/dev/tty终端上显示,和bash无关。终端和bash的关系可以理解为,终端用来和用户交互,终端中的命令是交给bash执行,开启终端会根据配置启动一个bash进程。
job control
一般默认可以开启6个tty。但是有时候如果设置只给你一个tty,又要同时运行多个程序,怎么办?
-
直接在背景中运行
tar -zpcv /tmp/etc.bak.tar.gz /etc & # 指令最后加上&表示在背景中运行 -
将已经运行的程序丢到背景中
ctrl + z # 通过ctrl + z 丢到背景中的程序默认是stopped暂停状态bg %jobnumber # ctrl + z 会把工作丢到背景当中并暂停,bg命令可以唤醒在后台执行
查看背景中的工作任务:
[root@study ~]# jobs [-lrs]
选项与参数:
-l :除了列出 job number 与指令串之外,同时列出 PID 的号码;
-r :仅列出正在背景 run 的工作;
-s :仅列出正在背景当中暂停 (stop) 的工作。jobs -l 展示的内容,jobnumber后面可能有+,-号,分别代表最后一个加入背景的任务,和倒数第二个加入的任务。
将背景中的任务拿到fg来处理:
fg %jobnumberkill:
kill -signal %jobnumber # 干掉一个Job任务kill -l # 可以查看signal的取值范围,常用的有1,9,15。1表示重新读取参数的配置文件,类似reload重启。9表示强制删除,15表示正常的终止。&和ctrl+z都是放在bash的环境下执行,一但没有了这个tty,比如你关掉了tty,对应的bash进程也会终止,此时在bash及他的子程序下运行的都会杀死。
只有系统背景下的程序运行和tty无关,可以使用at或者nohup命令(nohup 也可以&放在背景执行),但是nohup不支持bash内建指令(因为不是放在bash环境下执行),所以一般要写成脚本的形式。
进程查看
-
查看当前bash进程
ps -l # 查阅当前bash及对应的子进程,也就是只从你的bash出发结果结构:
F表示process flags,4为root,1表示此子进程只是进行了复制没有execS表示进程状态。R:Running,S:Sleep,D:比如I/O阻塞,T:Stop,Z:Zombie(僵尸状态)- UID/PID/PPID
C表示CPU使用率PRI/NI表示程序执行优先级,越小优先级越高ADDR/SZ/WCHAN,ADDR内存的哪一部分,SZ用了多少内存,WCHAN表示进程是否运行中,-表示运行TTY,终端机是哪个,tty开头的表示本机终端,pts开头的表示网络远程登录的终端TIME,CPU使用时长CMD,触发进程的指令
-
查看所有进程
ps aux # 查阅所有进程结果结构:
VSZ: 占用的虚拟内存量RSS: 占用的固定内存里TTY: 如果是?表示和终端无关
-
动态查看进程
[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)。输入k会有相关提示,比如输入pid,然后输入signal。 r :给予某个 PID 重新制订一个 nice 值。同上。 q :离开 top 软件的按键。 -
查看进程之间的关系
[root@study ~]# pstree [-A|U] [-up] 选项与参数: -A :各进程树之间的连接以 ASCII 字符来连接; -U :各进程树之间的连接以万国码的字符来连接。在某些终端接口下可能会有错误; -p :并同时列出每个 process 的 PID; -u :并同时列出每个 process 的所属账号名称。 -
杀死进程
kill -signal PID # 针对pid定向干掉 killall [-iIe] -signal [command name] # 针对指令kill 选项与参数: -i :interactive 的意思,交互式的,若需要删除时,会出现提示字符给用户; -e :exact 的意思,表示『后面接的 command name 要一致』,但整个完整的指令 不能超过 15 个字符。 -I :指令名称(可能含参数)忽略大小写。==注意和
kill -signal $jobnumber的区别,如果没有加%,kill -9 1就杀死了pid为1的进程,这是系统1号进程,kill相当于关掉了系统。==
进程优先级
ps -l时有2个关于优先级的字段,PRI和NI(NICE)
PRI由系统分析决定,用户无法修改,PRI越低优先级越高,用户能修改NI值。
一般来说 PRI(new) = PRI(old) + NI。所以NI越低,PRI也就越低,间接达到控制优先级的目的。
- root用户,可以调整所有进程的nice值,范围为-20~19
- 一般用户可调整自己的进程的nice值,范围为0~19
- 一般用户调整nice值只能增加,不能减少,也就是原来是5,不能调整到4
如何调整nice值:
-
运行程序时直接指定
[root@study ~]# nice [-n 数字] command -
已运行的程序指定
[root@study ~]# renice [number] PID -
top调整,top后输入r指令
系统资源查看
-
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 列出几次的意思~ -
uname查看系统核心信息
[root@study ~]# uname [-asrmpi] 选项与参数: -a :所有系统相关的信息,包括底下的数据都会被列出来; -s :系统核心名称 -r :核心的版本 -m :本系统的硬件名称,例如 i686 或 x86_64 等; -p :CPU 的类型,与 -m 类似,只是显示的是 CPU 的类型! -i :硬件的平台 (ix86) -
uptime系统启动时间和负载情况
uptime会展示系统开机到现在的时间,load average:系统在1,5,15分钟的平均负载(单位时间内有多少个进程、工作要处理,越小越空闲,大于1就要注意了,系统是否过于繁忙)
-
netstat一般用于网络监控
[root@study ~]# netstat -[atunlp] 选项与参数: -a :将目前系统上所有的联机、监听、Socket 数据都列出来 -t :列出 tcp 网络封包的数据 -u :列出 udp 网络封包的数据 -n :不以进程的服务名称,以埠号 (port number) 来显示; -l :列出目前正在网络监听 (listen) 的服务; -p :列出该网络服务的进程 PID -
dmesg查看内核产生的信息
dmesg | more # 内容太多 -
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 :后面列出分区槽,可显示该分区槽的读写总量统计表 -
/proc目录
linux一切皆文件,进程信息也抽象成了文件。
/proc目录里的信息都在内存中,内容就是系统运行时的相关信息,而且所有的进程都有对应PID目录。
-
fuser查看文件被进程占用情况
如果删除或unmount时提示device is busy就是文件被占用了
[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) 啰! -
lsof列出进程正在使用的文件
[root@study ~]# lsof [-aUu] [+d] 选项与参数: -a :多项数据需要『同时成立』才显示出结果时! -U :仅列出 Unix like 系统的 socket 文件类型; -u :后面接 username,列出该使用者相关进程所开启的文件; +d :后面接目录,亦即找出某个目录底下已经被开启的文件! -
pidof查找pid
[root@study ~]# pidof [-sx] program_name 选项与参数: -s :仅列出一个 PID 而不列出所有的 PID -x :同时列出该 program name 可能的 PPID 那个进程的 PID
SELinux
一个命令想要执行某个文件资源,主要看2样东西,命令的执行者,由于命令最终会被进程去执行,可以简化为进程的拥有者,还一个是文件的权限,二者决定这个进程(命令)能否执行成功。
如果执行者权力过大,比如root,或者文件权限过大,比如777,都有可能误操作或者文件能被别的进程修改,这就是传统DAC(自主式访问控制)权限控制的问题。
上面可知DAC权限管理,实际和进程是无关的,只取决于执行者和资源权限,能否将权限控制的影响因素引入进程,让进程具有某些权限,而文件也可以给进程授权?这就是SELinux了,SELinux是通过MAC(委任式访问控制)来实现的。
MAC要素
- 主体:MAC管理的主体显然是进程
- 目标:文件系统
- 策略:进程和文件系统都很庞大,不可能一个一个的设置,所以SELinux预设了几个策略
- targeted: 针对网络服务限制较多,针对本机限制较少,这是默认设定
- minimum: 由target修订而来,仅针对选择性的保护
- mls: 完整的SELinux限制,限制很严格
- security context: 除了要通过策略的检查外,还需要一个东西,就是主体和目标安全上下文的一致性
graph LR 1[主体process] --访问资源-->2{SELinux策略检查相关规则是否启用} --启用--> 3{security context对比} --一致--> 4{rwx权限检查} --通过--> 5[目标访问资源] 2 --关闭--> 4 3 --不一致--> 6[提示权限不够] 4 --不通过--> 6
三种模式
- enforcing: 强制模式,必须经过SELinux
- permissive: 宽松模式,会进行校验日志记录,但校验结果不影响结果
- disabled: 关闭模式
enforcing,permissive为开启模式,disabled为关闭模式
getenforce # 可查看SELinux状态
sestatus # 查看SELinux状态,策略等信息开启模式和关闭模式的切换:
vim /etc/selinux/config # 编辑这个文件即可。从开启到关闭,关闭到开启都需要重启系统,因为SELinux是内核模块。开启模式下,切换enforcing和permissive:
setenforce [0|1]SELinux校验涉及概念
-
文件的SELinux属性
开启后SELinux会将相关预设属性写入文件的inode中(所以开启后要重启,且会经过很长时间的等待,因为要写入文件系统数据)
ls -Z # system_u:object_r:admin_home_t:s0 和SELinux相关结果- 第一段system_u表示身份,一般就2个,unconfined_u不受限用户(比如登录用户,通过bash创建的文件,属性中身份就是不受限用户),system_u系统用户
- 第二段object_r表示角色,也有2个值,object_r表示文件,system_r表示进程,这里肯定是object_r了
- 第三段admin_home_t表示类型,重要,security context对比一致性主要就是对比这个东西
-
进程的SELinux属性
ps -eZ # 查看进程相关SELinux属性 # 结果类似下面,LABEL就是 LABEL PID TTY TIME CMD system_u:system_r:init_t:s0 1 ? 00:00:03 systemd- 第一段system_u表示身份,有system_u和unconfined_u,一般用户登录后开启的进程都是unconfined_u不受限用户
- 第二段system_r表示角色,对应上面的有system_r和unconfined_r
- 第三段init_t表示domain,重要,security context主要是对比进程的domain和文件的type是否能对应(对应关系由相关规则维护)
SELinux规则
进程执行的时候,如果开启了SELinux是怎么运作的呢?从前面的流程可知:
-
首先是检查相关规则是否开启
getsebool [-a] 规则名称 选项与参数: -a :列出目前系统上面的所有 SELinux 规则的布尔值为开启或关闭值[root@study ~]# seinfo [-Atrub] 选项与参数: -A :列出 SELinux 的状态、规则布尔值、身份识别、角色、类别等所有信息 -u :列出 SELinux 的所有身份识别 (user) 种类 -r :列出 SELinux 的所有角色 (role) 种类 -t :列出 SELinux 的所有类别 (type) 种类 -b :列出所有规则的种类 (布尔值) -
查看规则中domain和type的对应关系(security context校验)
[root@study ~]# sesearch [-A] [-s 主体类别] [-t 目标类别] [-b 规则名称] 选项与参数: -A :列出后面数据中,允许『读取或放行』的相关数据 -t :后面还要接类别,例如 -t httpd_t -b :后面还要接SELinux 的规则,例如 -b httpd_enable_ftp_server==注意: 查看规则的时候不仅仅是看
allow domain1 type1就认为domain1的进程能访问type1类型的文件,还要看后面的file类型,一般有file,dir,lnk_file,如果只是对应了dir,lnk_file,那说明只能访问这个类型的目录和链接文件。==
开启或关闭规则:
[root@study ~]# setsebool [-P] 『规则名称』 [0|1]
选项与参数:
-P :直接将设定值写入配置文件,该设定数据未来会生效的!修改规则
-
修改文件或目录的SELinux属性
[root@study ~]# chcon [-R] [-t type] [-u user] [-r role] 文件 [root@study ~]# chcon [-R] --reference=范例文件 文件 选项与参数: -R :连同该目录下的次目录也同时修改; -t :后面接安全性本文的类型字段!例如 httpd_sys_content_t ; -u :后面接身份识别,例如 system_u; (不重要) -r :后面街角色,例如 system_r; (不重要) -v :若有变化成功,请将变动的结果列出来 --reference=范例文件:拿某个文件当范例来修改后续接的文件的类型!就是复制这个文件的SELinux属性 -
恢复预设属性
[root@study ~]# restorecon [-Rv] 文件或目录 选项与参数: -R :连同次目录一起修改; -v :将过程显示到屏幕上 -
设置预设属性
[root@study ~]# semanage fcontext [-l] -{a|d|m} [-frst] file_spec 选项与参数: fcontext :主要用在安全性本文方面的用途, -l 为查询的意思; -a :增加的意思,你可以增加一些目录的默认安全性本文类型设定; -m :修改的意思; -d :删除的意思。semanage fcontext -a -t system_cron_spool_t "/srv/mycron(/.*)?" # 给/srv/mycron以及/srv/mycron/xxx设置默认SELinux属性 type设置为system_cron_spool_t,然后通过restorecon还原即可
记录因SELinux造成无法访问的log
主要通过2个应用setroublshoot和setroubleshoot-server。
并启用auditd服务即可。
日志信息会被记录进/var/log/messages
服务
Linux中的服务由daemon提供(服务和daemon可以看作一个东西)。
以centos为例,centos7开始,使用systemd来管理服务,每个配置文件可以看作一个服务unit。
被systemd管理服务,会有对应的配置文件,这个配置文件规定了服务启动的脚本,环境配置文件,重新启动的方式等等。简单的说就是通过这个配置文件启动服务。(每个daemon,都由对应的程序来实现,一般以d结尾,表示核心服务程序,通过配置文件启动服务,最终会调用这个程序)
graph LR 1[systemd] --调用配置文件-->2[xxx.service/timer/path...]--调用daemon程序-->3[daemon程序]-->4[服务启动]
systemd配置文件有:
-
/etc/systemd/system/: 配置了系统会启动哪些服务(调用哪些配置文件),很多被调用的配置文件是在/usr/lib/systemd/system/下(链接到这个目录)
systemctl enable 服务,开机启动设置时,可以看到
Created symlink /etc/systemd/system/multi-user.target.wants/docker.service → /usr/lib/systemd/system/docker.service.
创建了一个快捷方式
-
/run/systemd/system/: 系统执行过程中所产生的unit文件
-
/usr/lib/systemd/system/: 服务的配置文件
优先级从上往下。
/etc/sysconfig/* 服务初始化的选项参数
服务类型
服务根据配置文件执行产生(systemctl 调用)。配置文件约束了怎么启动服务,一般产生的服务名称就是配置文件的前缀(所以可能有同名前缀的,不同后缀的配置文件,执行实际只会产生一个服务)。
配置文件的后缀名实际就是服务的类型
- .service 系统服务
- .socket 内部程序交换数据的服务
- .target 执行环境类型,封装了多个服务,启动不同的target其实就是切换不同的操作环境
- .mount .automount 挂载服务
- .path 侦测特定文件或目录的服务
- .timer 循环执行的服务
systemctl
systemd服务管理机制,主要通过systemctl这个命令来达成。
[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
mask: 冻结服务,冻结后无法启动
umask: 取消冻结查看所有服务:
[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 等切换操作环境
target类型的服务就是操作环境,其中封装了多个服务
[root@study ~]# systemctl [command] [unit.target]
选项与参数:
command:
get-default :取得目前的 target
set-default :设定后面接的 target 成为默认的操作模式
isolate :切换到后面接的模式[root@study ~]# systemctl poweroff 系统关机
[root@study ~]# systemctl reboot 重新启动
[root@study ~]# systemctl suspend 进入暂停模式 # 系统状态保存在内存中,唤醒很快
[root@study ~]# systemctl hibernate 进入休眠模式 # 系统状态保存在硬盘中,唤醒较慢
[root@study ~]# systemctl rescue 强制进入救援模式
[root@study ~]# systemctl emergency 强制进入紧急救援模式服务之间的依赖性
[root@study ~]# systemctl list-dependencies [unit] [--reverse]
选项与参数:
--reverse :谁依赖我网络服务
查看服务和端口号的对应关系
cat /etc/services # 在/etc/services文件下查看网络服务
netstat -tunlp如果要关闭某个网络服务,可以通过
systemctl list-units # 查询相关服务
systemctl stop unit # 关闭服务
systemctl enable unit # 开机不启动.service服务配置文件
/etc/systemd/system,/usr/lib/systemd/system,/run/systemd/system 这几个地方放的是服务的配置文件
其中/usr/lib/systemd,/run/systemd/system一个是系统预设的,一个是运行时产生的,都不建议修改。
所以如果要修改服务的配置,或者增加配置,都建议在/etc/systemd/system下面修改、增加。
一般有如下约定:
以nginx.service为例
- nginx.service为默认配置,一般在/usr/lib/systemd/system目录下
- nginx.service.d为自定义配置所在目录(一般由用户新增),内部配置可以是xxx.conf,这个目录下的文件会累加进默认设置
- nginx.service.wants/*为nginx启动后,建议启动这里面的服务,里面一般都是链接文件
- nginx.service.requires/*启动nginx之前,需要启动的服务,里面一般都是链接文件
具体配置文件:
# Stop dance for nginx
# =======================
#
# ExecStop sends SIGSTOP (graceful stop) to the nginx process.
# If, after 5s (--retry QUIT/5) nginx is still running, systemd takes control
# and sends SIGTERM (fast shutdown) to the main process.
# After another 5s (TimeoutStopSec=5), and if nginx is alive, systemd sends
# SIGKILL to all the remaining processes in the process group (KillMode=mixed).
#
# nginx signals reference doc:
# http://nginx.org/en/docs/control.html
#
[Unit]
Description=A high performance web server and a reverse proxy server
Documentation=man:nginx(8)
After=network.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload
ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid
TimeoutStopSec=5
KillMode=mixed
[Install]
WantedBy=multi-user.target-
Unit,这个服务/配置文件本身的描述,包括描述、说明文档、在什么服务启动之后启动,这里的After没有强制的意思,Requires弱
-
Service,服务类型,具体的启动命令,环境配置,重启方式等等
type: daemon启动方式
- simple: 默认值,启动后常驻内存
- forking: 父程序启动后可能终结,由子程序提供服务
- oneshot: 任务完成后就结束,相当于一次性的
ExecStart: 实际指令,可以用ExecStartPre,ExecPost之前、之后来设置额外的指令
ExceStop: systemctl stop相关
ExecReload: systemctl reload相关
-
Install,将这个服务unit安装到哪个target下,大多数服务性质的unit都是挂在multi-user.target下
自定义服务
-
定义脚本
#!/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 -
定义.service配置文件
/etc/systemd/system下新增
[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注意:bash -c 执行后面的指令,使用到了at now,所以需要先开启atd服务
-
systemctl daemon-reload重载配置文件 -
启动服务
.timer服务
按某个时间或周期,启动某个服务,和crond很像,但是timer是依靠systemd这个常驻内存的管理服务,所以有时候也比较好用
需要:
- timer.target: 必须开启这个环境
- xxx.servcie: 你的服务
- xxx.timer: 对应的timer服务
其他比较有用的服务
- firewall 防火墙服务
- sshd 远程连接服务,通过ssh连接
系统日志
什么用户,什么时候,用什么程序,执行了什么命令,产生了哪些后面
日志非常重要,对于分析问题,查找问题,处理问题非常有帮助
日志文件主要放在/var/log
常见的日志文件有:
- /var/log/boot.log: 开机的时候系统核心会去侦测与启动硬件,接下来开始各种核心支持的功能启动等。这些流程都会记录在/var/log/boot.log 里面,不过这个文件只会存在这次开机启动的信息,前次开机的信息并不会被保留下来!
- /var/log/cron: 你的crontab 排程有没有实际被进行? 进行过程有没有发生错误?你的/etc/crontab 是否撰写正确?在这个登录档内查询看看。
- /var/log/dmesg: 记录系统在开机的时候核心侦测过程所产生的各项信息。由于CentOS 默认将开机时核心的硬件侦测过程取消显示, 因此额外将数据记录一份在这个文件中;
- /var/log/lastlog: 可以记录系统上面所有的账号最近一次登入系统时的相关信息。lastlog 指令就是利用这个文件的记录信息来显示的。
- /var/log/maillog 或 /var/log/mail/*: 记录邮件的往来信息,其实主要是记录postfix (SMTP 协议提供者) 与dovecot (POP3 协议提供者) 所产生的讯息。SMTP 是发信所使用的通讯协议, POP3 则是收信使用的通讯协议。postfix 与dovecot 则分别是两套达成通讯协议的软件。
- /var/log/messages: 这个文件相当的重要,几乎系统发生的错误讯息(或者是重要的信息) 都会记录在这个文件中; 如果系统发生莫名的错误时,这个文件是一定要查阅的登录档之一。
- /var/log/secure: 基本上,只要牵涉到『需要输入账号密码』的软件,那么当登入时(不管登入正确或错误) 都会被记录在此文件中。包括系统的login 程序、图形接口登入所使用的gdm 程序、su, sudo 等程序、还有网络联机的sh, telnet 等程序, 登入信息都会被记载在这里;
- /var/log/wtmp, /var/log/faillog: 这两个文件可以记录正确登入系统者的帐户信息(wtmp) 与错误登入时所使用的帐户信息(faillog) ! last 就是读取wtmp 来显示的, 这对于追踪一般账号者的使用行为很有帮助!
- /var/log/httpd/, /var/log/samba/: 不同的网络服务会使用它们自己的登录文件来记载它们自己产生的各项讯息!上述的目录内则是个别服务所制订的登录档。
相关服务
systemd-.service是核心的日志管理工具,rsyslog.service用于持久化。
所有经过systemd管理的服务产生日志信息(比如服务的标准输出就会被journald捕获),都交给systemd-journald.service,然后再交给rsyslog.service写入日志文件。
/etc/systemd/journald.conf可以用于修改journald配置,比如修改默认的写入ram db的行为,改为写入设备文件系统,一般不需要动。
/etc/rsyslog.conf,/ect/rsyslog.d用于配置rsyslog,包括服务对应的日志文件,哪种级别应该记录在哪个文件等,还可以设置专门的日志服务器,rsyslog默认支持,只需开启相关配置端口,然后客户端再设置日志服务器的地址即可。
systemd-journald记录的信息是在内存中,最初的主要作用是记录开机到启动服务这段时间的日志(rsyslog.service启动在较后面,无法记录这段日志)。虽然
systemd-journald.service可以将日志永久写入文件系统,但是这就失去了读取快的优势,这部分工作交给rsyslog.service比较合适。
日志轮替
如果一直给一个日志文件里写数据,必然造成这个文件的臃肿,且备份困难
logrotate的功能就是迁移旧的日志文件,并创建一个空的日志文件。
logrotate配置文件/etc/logrotate.conf,/etc/logrotate.d
logrotate.conf放一些默认设置,全局设置
/etc/logrotate.d目录下放的是各个服务的日志轮替方式
比如/etc/logrotate.d/nginx:
/var/log/nginx/*.log {
daily # 每天
missingok
rotate 14 # 保留14个日志文件
compress # 压缩
delaycompress
notifempty
create 0640 www-data adm # 新增文件的权限 拥有者 群组
sharedscripts
prerotate
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi \
endscript
postrotate
invoke-rc.d nginx rotate >/dev/null 2>&1
endscript
}run-parts遍历目录下的脚本文件并执行
logrotate由cron定时执行
可以手动强制rotate一次
[root@study ~]# logrotate [-vf] logfile
选项与参数:
-v :启动显示模式,会显示 logrotate 运作的过程喔!
-f :不论是否符合配置文件的数据,强制每个登录档都进行 rotate 的动作!日志分析
通过last,lastlog,dmesg获得的日志信息毕竟过于松散,不好对比。
分析日志文件可以借助一些工具,比如logwatch。
开机流程
每个操作系统安装的文件系统的第一个扇区会安装一个boot loader程序,同时一般都会在MBR(MBR分区格式和GPT分区格式,GPT分区格式也保留了一块兼容MBR的扇区,用于存放boot loader,但是只是第一阶段的boot loader)也存放一个boot loader。所以会有2个boot loader,文件系统有很多个,MBR只会有一个,所以MBR中的boot loader可能会被后装的操作系统覆盖。
boot loader一般有3个功能:
- 提供选项,这个多重引导的重要功能
- 加载核心文件,直接指向可开机的程序段,开启操作系统
- 转到其他loader,控制器转移
遗憾的是windows预设的boot loader 不具备控制权移交功能,也就是MBR中如果是windows的boot loader,那只能选择windwos操作系统,如果MBR中是linux操作系统,那么就可以进行多重引导,可以选择将控制权交给其他文件系统里的boot loader,加载不同的操作系统。
所以双系统要先装windows,后装linux。
graph LR 1[开机] --> 2[BIOS硬件检测] --> 3[找到存储设备] --> 4[读取MBR开机管理程序] --> 5[加载kernel] --操作系统启动--> 6[调用systemd程序]
systemd的pid为1
systemd开始调用default.target准备环境
locale设置
-
生成区域设置
编辑/etc/locale.gen,取消对应的,比如en_US.UTF-8,zh_CN.UTF-8,en_DK.UTF-8、
运行locale-gen生成Locale
-
编辑/etc/locale.conf或/etc/default/locale等相关文件,设置LANG,LC_TIME等相关:
LANG=en_US.UTF-8 LC_TIME=en_DK.UTF-8 # 其他区域设置
sudo设置
-
install
apt install sudo -
给指定用户添加sudo群组
usermod -aG sudo username
网络管理
当前建议:
GUI系统:使用NetworkManager图形化管理网络
服务器类型:使用systemd-networkd和systemd-resolved管理网络
几种常见情况:
-
debian
debian11默认使用ifupdown来管理网络,并使用networking.service作为网络管理服务,networking.service本质上就是调用ifup(ifupdown)来读取配置文件
/etc/network/interfaces/以管理网络。 -
ubuntu
新版ubuntu(18之后)默认使用systemd-networkd作为网络管理服务,使用netplan来配置网络(yaml),netplan的作用是抹平网络管理服务之间的差异,相当于一个配置文件可以对应不同的网络管理服务,比如netplan可以同时应用于systemd-networkd和NetworkManager,只需要改下
render配置。 -
centos
centos6使用/etc/init.d/network脚本来管理网络,服务network.service本质上就是对/etc/init.d/network的引用,这个脚本会读取配置文件
/etc/sysconfig/network-scripts/ifcfg-*以启用网络。centos7之后默认使用NetworkManager来管理网络,也可以读取上面的配置文件。
对于服务器类型:
建议使用systemd-networkd,它使用配置文件/etc/systemd/network/*来管理网络。
命名一般以优先级-网卡.network,比如10-eth0.network,配置说明:参考
如果使用systemd-resolved作为域名解析服务,需要start,enable该服务:
并推荐将/etc/resolve.conf指向stub-resolve.conf:
ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf然后配置/etc/systemd/resolved.conf即可,比如:
[Resolve]
# Some examples of DNS servers which may be used for DNS= and FallbackDNS=:
# Cloudflare: 1.1.1.1 1.0.0.1 2606:4700:4700::1111 2606:4700:4700::1001
# Google: 8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844
# Quad9: 9.9.9.9 2620:fe::fe
DNS=223.5.5.5
DNS=8.8.8.8另:目前iproute2已经基本替代了net-tools工具,最常使用的比如ip link/address/route等等。
本质上都是修改配置文件(NetworkManager单独使用的时候无法直接修改配置文件来改变网络,需要使用命令),重新启动相关服务,这些服务会调用相关的命令来重新应用配置。
防火墙
防火墙的本质,就是对数据包的分析处理。
centos7 开始使用firewalld,不再使用iptables。
firewalld的操作接口对比iptables更人性化。
注意:firewalld和iptables本身其实都不具备防火墙功能,他们本质上都是操作内核中的netfilter,netfilter才是真正的防火墙。
防火墙的最小管理单位是数据包,处理的就是包。
iptables
测试环境debian11
概念
-
table
规则表,即规则集合,有:filter,nat,mangle(用于修改包),raw(该表主要用于与NOTRACK目标结合配置连接跟踪的例外情况),security(SELinux相关,应用于INPUT,OUTPUT,FORWARD)。
table中规则一定属于某个chain,对应的table中的规则只能分配到关联的chain上,而不是任意chain。

-
chain
规则链,默认的有:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING,也可以自定义chain,但是自定义的也是被默认的调用。请求会经过chain的过滤处理,chain中规则的执行是有先后顺序的,表有先后,表中规则也有先后。表的先后顺序是固定的:raw –> mangle –> nat –> filter。
也就是执行链的时候,会根据表的顺序去执行表中属于这个链的规则。
报文走向:
到本机某进程的报文:PREROUTING –> INPUT
由本机转发的报文:PREROUTING –> FORWARD –> POSTROUTING
由本机的某进程发出报文(通常为响应报文):OUTPUT –> POSTROUTING
在进入OUTPUT和FORWARD前,就会根据目标地址匹配路由表,写入OUT的网卡。报文进入网卡后,会逐级匹配到目标路由,最后根据路由进入目标主机服务。
-
规则匹配
只有规则被匹配后,才能进行相关的动作。
常见的匹配有源IP,目标IP,源端口,目标端口等。
匹配到一个规则后将不再继续匹配,如果没有匹配到任何规则,则执行默认动作。
常见的匹配语法:
-
源地址匹配
[!] -s,--source address[/mask][,...] -s 192.168.1.164 # 匹配ip,可以有多个,用,隔开 -s 1.2.0.0/16 # 匹配网段 ! -s # 取反 -
目标地址匹配
[!] -d,--destination address[/mask][,...] -
协议匹配
[!] -p, --protocol protocol # 比如tcp,upd,icmp等等,具体看man iptables,不指定默认是all -
网卡匹配
[!] -i, --in-interface name # 指定入的网卡名称,只在INPUT, FORWARD and PREROUTING中生效[!] -o, --out-interface name # 指定出的网卡名称,只在FORWARD, OUTPUT and POSTROUTING中生效
扩展匹配:
依赖扩展模块。
-m matchname [per-match-options] # matchname为模块名称-
端口匹配,依赖
tcp/multiport模块UDP模块同理。
-p tcp -m tcp --dport 22 # dport指定目标端口,可以使用范围,可以取反。-m 默认取-p指定的协议名称,所以2者相同时,-m可以省略,但是-p不能省略 -p tcp -m tcp --sport 54332 # sport指定源端口 -p tcp -m multiport --dport 22,23,8080:9090 # multiport可以指定多个离散端口,sport类似 # 特殊选项 --tcp-flags # 这个可以用于匹配tcp握手阶段的第几次握手,这个应用场景在哪里?防止别人主动连接?为什么TCP要3次握手。为了保证信道是可靠的,client发出消息,server收到消息并给出回应,此时只是给出了回应但是并不代表2者说的是一个”事情“,需要再确定一次,client再回应server,此时2者就在一个”频道“上了。相当于2次应答,一次检查来确定,所以需要3次,3次是最少能确认可靠的次数。
-
ip范围匹配,依赖
iprange模块-m iprange --src-range 192.168.1.10-192.168.1.50 # 也能取反 -m iprange --dst-range 192.168.1.10-192.168.1.50 -
报文包含指定字符串,依赖
string模块-m string --algo bm[/kmp] --string "XXOO" # 必须指定算法(随便哪个,影响不大),这是怎么匹配的,又没有字符集介入? -
时间匹配,依赖
time模块-m time --timestart 09:00:00 # 数据包到达时间 # 其他选项 --timestop 11:00: # 只有weekdays,monthdays可以取反 --weekdays 6,7 --monthdays 5,15,25 --datestart 2022-06-26 --datestop 2023-06-26 -
连接数匹配,依赖
connlimit模块-m connlimit --connlimit-above 2 -j REJECT # 匹配请求ip超过2个的连接的请求,可以取反 # 其他选项 --connlimit-mask 24 # 这是指定网段了,24即最后8位主机的ip地址范围,这些范围内的ip共享--connlimit-above指定的连接数量。 -
包到达速度匹配,依赖
limit模块
-t filter -I INPUT -p icmp -m limit --limit 10/minute[second|hour|day] -j ACCEPT # 每分钟10个包,即每6秒一个包,也就是这会间隔的匹配到包。可以理解为每6秒会生成一个令牌,数据包拿到令牌才会被放行 # 有个特殊选项 --limit-burst 可以指定一个数量,表示容量,这个容量决定了最初始可以生成的令牌,也就是初始可以放行(匹配)的数据包其实应用了上面的规则,进行ping的时候不会有任何变化,或者说无法达到想要的目的,因为间隔匹配的包是ACCEPT,在间隔间隙发过来的包没有匹配到,会走默认策略,INPUT默认策略就是ACCEPT。
很多取反规则也是同样的道理,一定要注意,没有匹配到的走的是默认策略。
- icmp报文类型匹配,依赖
icmp模块
基本只有一个用处,禁止别人ping,但是可以ping别人
iptables -t filter -I INPUT -p icmp -m icmp --icmp-type 8/0 -j REJECT # icmp-type 8/0表示匹配ping请求类型的报文如果不使用
icmp模块,只是禁止了icmp协议,此时别人固然ping不通我们,但是我们ping别人,应答的包也是通不过,也就ping不通了。- 连接”状态“匹配,依赖
state模块
问题:client访问某个服务,假如这个服务监听在80端口,client进行请求,服务进行响应,client此时必然是允许sport为80的请求了,否则就无法获得响应了,这就会造成一个问题,如果服务端主动通过80端口发送数据包过来进行攻击呢?
要避免这种情况,就要拒绝服务端主动发起的请求,显然
--sport 80 -j REJECT无法达到目的,此时就需要state模块了。state模块会标记连接的状态,有以下状态:-
NEW: 连接中的第一个包,状态就是NEW
-
ESTABLISHED:第一个包后面的所有包
-
RELATED: 这个状态主要用于标识多个连接的关系,比如服务端发送过来了一个包,虽然可能是“第一个”包,但是这个包是由前面的连接引起的,此时就不能标识为NEW,所以引入了RELATED来标识。
比如服务端多个进程参与通信,此时就需要建立多个连接了,假设为tcp,每个tcp连接的包是单独的,此时就需要用RELATED来区分真正的NEW。
另:tcp连接,或者说socket连接,必须满足5元规则,sourceIp,sourcePort,protocol,destIp,destPort,也就是如果2个进程端口、IP固定,使用tcp传输,那么他们之间同时只能建立一个连接。
-
INVALID: 包无法被识别,或者包没有状态
-
UNTRACKED: 无法确定该报文属于哪个连接
注意
state语境下的连接并不是我们常说的tcp连接,可以理解为通信,每一个包的到达就可以认为是一次连接。此时只需要允许ESTABLISHED和RELATED状态的连接进入即可:
-t filter -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 注意默认策略,所以还要添加阻止其他的 -t filter -A INPUT -j REJECT -
-
动作
规则捕获到请求后,最终的行为是什么,要做什么处理。
ACCEPT:允许数据包通过。
DROP:直接丢弃数据包,不给任何回应信息,这时候客户端会感觉自己的请求泥牛入海了,过了超时时间才会有反应。
REJECT:拒绝数据包通过,必要时会给数据发送端一个响应的信息,客户端刚请求就会收到拒绝的信息。可以接收选项,默认为
–reject-with icmp-net-unreachable。NAT类:
什么是NAT,即网络地址转换,地址分为公有地址和私有地址。
私有地址:10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,这3个网段的为私有地址,互联网是不会路由私有地址的,必须先转换为公网地址。
-
SNAT:源地址转换,解决内网用户用同一个公网地址上网的问题。
iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -j SNAT --to-source 公网IP # 内网地址修改为公网地址,响应会原路转换回来,也就是不用添加DNAT了 -
MASQUERADE:是SNAT的一种特殊形式,适用于动态的、临时会变的ip上。
iptables -t nat -A POSTROUTING -s 10.1.0.0/16 -o eth0 -j MASQUERADE # 内网地址修改为-o出口网卡的公网地址,用于动态公网IP -
DNAT:目标地址转换。
iptables -t nat -I PREROUTING -d 公网IP -p tcp --dport 公网端口 -j DNAT --to-destination 私网IP:端口号 # 理论上响应会自动转换,不需要做SNAT了 -
REDIRECT:在本机做端口映射。
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
LOG:记录日志信息,然后将数据包传递给下一条规则,也就是说除了记录以外不对数据包做任何其他操作,仍然让下一条规则去匹配。可以设置日志级别和选项。
RETURN: 进入自定义链后可以RETURN回到主链上继续匹配。
-

查询
iptables -t 表名 -L #查看某个表的所有规则
iptables -t 表名 -L INPUT #查看表中对应的chain的规则
iptables -t 表名 -nvL # -n 对于ip不要进行反解析,比如0.0.0.0/0,被反解析为anywhere,意义不大,-v显示更多信息,--lines-number显示顺序,对后续操作,比如delete,replace很有用常见的查询结果字段说明:
pkts:对应规则匹配到的报文的个数。
bytes:对应匹配到的报文包的大小总和。
target:规则对应的target,往往表示规则对应的”动作”,即规则匹配成功后需要采取的措施。
prot:表示规则对应的协议,是否只针对某些协议应用此规则。
opt:表示规则对应的选项。
in:表示数据包由哪个接口(网卡)流入,即从哪个网卡来。
out:表示数据包将由哪个接口(网卡)流出,即到哪个网卡去。
source:表示规则对应的源头地址,可以是一个IP,也可以是一个网段。
destination:表示规则对应的目标地址。可以是一个IP,也可以是一个网段。
操作
基本规则:
iptables -t 表名 -操作指令 链名 匹配条件 -j 动作操作指令:
-I,--insert,规则插入到表最前面
-A,--append,规则添加到表最后面
-D,--delete,删除规则,有2种用法,链后跟数字,删除指定表中,指定链的第几条规则,链后跟匹配规则,删除匹配到的规则
-R,--replace,后面跟规则的顺序,然后指定要替换的内容,注意如果只要替换某个内容,那其他不变的也要写进去,否则会被修改为默认值
-F,--flush,刷新整个链或整个表,没有保存前,刷新就相当于重置成上一次保存的状态了
-P,--policy,修改chain的默认动作,如果该链没有任何规则匹配就会执行默认动作例子:
iptables -t filter -A INPUT -s 192.168.1.146 -j DROP # 指定表,指定链的尾部添加一个规则,用于丢弃来自192.168.1.146的数据包
iptables -t filter -P FORWARD ACCEPT # 修改指定表,指定链的默认策略
iptables -t filter -D INPUT 3 # 删除指定表,指定链的第3条规则
iptables -t filter -D INPUT -s 192.168.1.146 -j DROP # 删除匹配的规则
iptables -t filter -R INPUT 3 -s 192.168.1.146 -j ACCEPT # 替换指定表,指定链的第3条规则的信息,这里替换了匹配条件和执行动作,如果只指定了-j,那source就会替换为默认值,0.0.0.0/0
iptables -t filter -I INPUT 2 -s 192.168.1.146 -j DROP # 在指定表,指定链的第2个位置插入一条规则,后面的规则顺序自动加1,对于要修改规则时,可以简单的先删除,然后再在指定位置添加匹配规则见上。
白名单
常规的办法:
iptables -t filter -I INPUT -p tcp --dport 80 -j ACCEPT
iptables -t filter -P INPUT DROP # 修改默认策略能达到目的但是会很危险,如果不小心清除了规则,比如-F,会导致所有连接都进不去。
更好的办法:
iptables -t filter -I INPUT -p tcp --dport 80 -j ACCEPT
iptables -t filter -A INPUT -j REJECT # 最后加一条匹配所有的请求的规则即可一定要注意上面的2种方法,都会导致其他所有非指定端口的请求都进不来,包括你发出去然后对方响应回来的消息。可以利用state模块来解决。
也要注意iptables会过滤本机loopback的请求,需要进行ACCEPT。
所以一般会添加如下规则:
sudo iptables -t filter -I INPUT -i lo -j ACCEPT # 允许本地lo访问
sudo iptables -t filter -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 允许响应进来
sudo iptables -t filter -I INPUT -p icmp -j ACCEPT # 允许ping,包括别人ping本机,可以进行额外的限制,不允许别人ping
sudo iptables -t filter -I INPUT -p tcp --dport 22 -j ACCEPT # 开放ssh端口
sudo iptables -t filter -I INPUT -p tcp -m multiport --dport 8888:9999 -j ACCEPT # 开放范围端口
sudo iptables -t filter -A INPUT -j REJECT # 默认阻止连接保存
iptabels的规则只是当时改变内存的中netfilter,重启后就失效了(不像firewalld,重启后对应的服务会重新把规则写入netfilter)
可以使用iptables-save > /etc/iptables/rule.v4保存到某个文件,启动后再使用iptables-restore < /etc/iptables/rule.v4来进行加载。
更简单的办法是使用:
sudo apt install iptables-persistent使用这个插件来保存,且重启后会自动加载规则。
sudo netfilter-persistent save # 会保存进/etc/iptables/rules.v4
sudo netfilter-persistent reloadipv6tables对应ipv6相关内容。
自定义链
可以理解为分组,命名空间之类的,用于规则分类管理,更方便维护。
自定义链必须挂在默认的链上才会生效。挂接实际上就是把自定义链当作动作来处理,匹配成功不直接处理,而是让子链来处理。
-
创建
iptables -t filter -N TEST_CHAIN -
添加规则
iptables -t filter -I TEST_CHAIN -p icmp -s 192.168.1.64 -j DROP -
挂接到默认CHAIN
iptables -t filter -I INPUT -p icmp -j TEST_CHAIN # 以动作的形式 -
删除
iptables -t filter -X TEST_CHAIN # 删除前取消挂接,删除链中的所有规则。 -
重命名
iptables -t filter -E TEST_CHAIN NEW_CHAIN
**总结:**自定义链就是规则集合,通过-j定向到自定义链后,自定义链开始处理,注意-j定义的表要和定义自定义链的表相同。
网络防火墙
对比主机防火墙,网络防火墙的作用是保护某个局域网,网络防火墙所在主机作为入口使用,作用是过滤与转发,也就是当作网关使用。
上面的图示也说明了,请求进入主机操作系统后,根据路由决定是走INPUT CHAIN进入本机,还是走FORWARD CHAIN后再转发到其他主机。
这里的FORWARD是FORWARD CHAIN,用于过滤处理请求,并不真正的转发,不要混淆了。
**例:**假设网络防火墙所在局域网是172.17.0.0/16,它还有一个网卡是192.168.1.64,所在192.168.1.0/24网段,现在192网段的另一个主机192.168.1.100如果要访问172.17.0.200,就需要使用192.168.1.64作为网关,当然172.17网段主机也需要将网关设为网络防火墙主机所在该网段的地址。
route add -net 172.17.0.0/16 gw 192.168.1.64 # 192.168.1.100访问172.17网络时使用192.168.1.64作为网关此时64主机上就会接收到转发请求,就要经过FORWARD链。
前提是主机开启了支持核心转发,看/proc/sys/net/ipv4/ip_forward是否为1
比如:
iptables -t filter -I FORWARD -j REJECT # 此时100就无法访问172.17了假如100要访问172.17.0.200上的80 http服务:
iptables -t filter -I FORWARD -p tcp -s 192.168.1.0/24 --dport 80 -j ACCEPT # 请求的转发通过
iptables -t filter -I FORWARD -p tcp -d 192.168.1.0/24 --sport 80 -j ACCEPT # 响应的转发通过可以使用state模块来优化:
iptables -t filter -I FORWARD -p tcp -m state --state ESTABLISHED,RELATED -j ACCEPT # 允许响应报文
iptables -t filter -A FORWARD -p tcp -s 192.168.1.0/24 --dport 80 -j ACCEPT # 允许client的请求,包括NEW
iptables -t filter -A FORWARD -j REJECT # 拒绝其他的,主要是服务端主动的请求为什么要这么优化?比如此时不仅想访问80,还想访问ssh 20,只需要添加一个规则就行了:
iptables -t filter -I FORWARD -p tcp -s 192.168.1.0/24 --dport 22 -j ACCEPTdocker
docker会自动添加iptables规则,主要在nat和filter表中。
如果你直接在INPUT中限制docker映射到主机上的端口,会发现根本没有用。
在PREROUTING中有一条规则:
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER # 匹配本机地址(包括虚拟网卡,比如docker0)这个规则的主要作用是,对本机地址的访问,转到DOCKER链上,然后对docker端口的访问进行DNAT,修改destination为容器地址和容器端口。
由于默认策略为ACCEPT,所有经过PREROUTING的数据包大概有三种:
- 非主机地址,比如容器之间的访问,此时没有匹配到,直接ACCEPT
- 主机地址,docker映射到主机的端口,进行DNAT
- 主机地址,非docker映射端口,不管是容器访问主机还是外部访问主机,都会ACCEPT
数据包经过PREROUTING后,根据目标地址,如果为本机地址则走INPUT,否则走FORWARD。
此时对容器的访问,显然去了FORWARD,所以在INPUT中添加规则是没有效果的。
实际上docker已经为自定义控制预留了接口,就是DOCKER-USER链,但是不建议直接修改它,可以自定义一个chain,然后把这个chain添加到DOCKER-USER上,比如:
iptables -t filter -N MYFILTER # 添加自定义chain然后添加规则:
iptables -t filter -I MYFILTER -i docker0 -j RETURN # 放开容器之间的访问,如果有其他自定义网络,也要加上,当然有需要可以进行更细致的控制
# 比如只允许某个docker-compose中的容器互相访问,此时可以
iptables -t filter -A MYFILTER -i br-746e0a58158e -o br-746e0a58158e -j RETURN # br-746e0a58158e就是这个docker-compose网络
# 又比如限制对容器端口的访问
iptables -t filter -A MYFILTER -s 192.168.1.0/24 -d 172.19.0.14 -p tcp -m tcp --dport 80 -j RETURN # 对容器端口只允许内网访问,注意这里的端口是容器端口,不是映射到主机的端口,因为在PREROUTING中已经进行DNAT转换。
iptables -t filter -A MYFILTER -d 172.19.0.14 -p tcp -m tcp --dport 80 -j REJECT # 此时为白名单模式,需添加默认拒绝规则最后,把MYFILTER添加到DOCKER-USER中:
iptables -t filter -I DOCKER-USER 1 -j MYFILTER另:
容器访问宿主机的端口,走的是INPUT,此时需要放开端口,否则也访问不到:
iptables -t filter -I INPUT 1 -i br-746e0a58158e -p tcp -m tcp --dport 9100 -j ACCEPT # 允许容器通过br-746e0a58158e访问宿主机9100端口有时候容器不在一个网段,比如2个docker-compose服务容器,他们之间的访问如果通过宿主机来访问,通过nat中PREROUTING下的DOCKER链可以看出,此时通过-i规则,直接RETURN了,没有进行DNAT,所以走的是INPUT,但是INPUT中无法DNAT,所以注定无法访问。如果直接访问呢?默认情况下在DOCKER-ISOLATION-STAGE-2中就进行DROP了,此时只能去修改DOCKER-USER。
firewalld
概念
- zone: 可以理解为组,区域,实际上就是将网络分成了不同的区域进行管理,每个区域有自己的规则和特点(预设了很多service),区域是绑定在网卡上面的,默认是public。
- service: 就是预定义规则,比如http service实际就是开放了80端口,添加一个service就是开通了一个或多个端口。如果你的应用没有合适的servcie,要么自定义service,然后添加service到对应的zone,或者直接开放端口。
使用
-
默认已经进行了安装,如果没有
yum install firewalld -
查看状态
firewall-cmd --state # 查看状态 systemctl status firewalld # 也可以查看状态,可以启用,停止,开机启用等等 -
zone设置
-
查看默认zone
firewall-cmd --get-default-zone -
查看所有可用zone
firewall-cmd --get-zones -
查看所有被使用的zone
firewall-cmd --get-active-zones -
查看某个zone被哪些网卡使用了
firewall-cmd --zone=public --list-all -
查看所有zone的配置情况
firewall-cmd --list-all-zones # 查看配置,内容非常多 -
修改网卡zone
firewall-cmd --zone=dmz --add-interface=eth0 # 分配给网卡 firewall-cmd --zone=work --change-interface=eth1 # 修改网卡zone -
修改默认zone
firewall-cmd --set-default-zone=home
-
-
service设置
这里就是配置规则了
-
查看所有services
firewall-cmd --get-services -
查看service具体内容,比如开放的端口
cat /usr/lib/firewalld/services/service_name.xml比如http service 对应的http.xml
<?xml version="1.0" encoding="utf-8"?> <service> <short>WWW (HTTP)</short> <description>HTTP is the protocol used to serve Web pages. If you plan to make your Web server publicly available, enable this option. This option is not required for viewing pages locally or developing Web pages.</description> <port protocol="tcp" port="80"/> </service>开放tcp协议的80端口
-
添加service到zone
firewall-cmd --zone=public --add-service=http # 将http service添加到public zone,如果网卡使用这个zone,经过这个网卡的网络请求就能访问80端口应用firewall-cmd --zone=public --add-service=http --permanent # 添加 --permanent能让配置永久生效,其他配置同样 -
查看zone对应的service
firewall-cmd --zone=public --list-services -
移除service
firewall-cmd --zone=public --remove-service=http --permanent -
对于没有合适service的应用,可以直接开放端口
firewall-cmd --zone=public --add-port=32400/tcp --permanent -
移除端口
firewall-cmd --zone=public --remove-port=32400/tcp --permanent -
查看zone对应开放的ports
firewall-cmd --zone=public --list-ports
-
-
自定义service
/usr/lib/firewalld/servcies复制一个然后进行修改。
比如复制ssh.xml,然后修改short,也就是名称,和description描述,最后改下协议,端口
添加完不要忘记重新加载配置文件。
6. 重新加载配置文件
```shell
firewall-cmd --reload
端口转发
-
对某个zone开启转发功能
firewall-cmd --zone=external --add-masquerade -
同一台服务器的端口转发
firewall-cmd --zone=external --add-forward-port=port=80:proto=tcp:toport=8080 # tcp 80 转 8080 -
不同服务器转发
firewall-cmd --zone=external --add-forward-port=port=80:proto=tcp:toaddr=10.10.10.2 # 转发到另一个服务器同一端口 firewall-cmd --zone=external --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=10.10.10.2 # 不同服务器不同端口
fail2ban
对于暴露在公网的服务器建议使用,这个可以增加安全配置,避免暴力破解。
最经济高效的办法是:
- key登录
- 白名单
- fail2ban
最重要的是1,一定要禁止密码登录,密钥的安全性要远大于密码。
-
安装
apt install fail2ban -
修改配置
原则:.local配置优先级高于.conf配置,独立服务配置优先级高于全局DEFAULT配置。
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local # 复制一个local配置文件全局设置:
[DEFAULT] bantime = 10m # 被ban时长 findtime = 10m # findtime和maxretry组成触发条件,即findtime内尝试的次数为maxretry时触发ban maxretry = 5修改sshd配置:
[sshd] enabled = true # 启用 bantime = 1h # 触发被ban条件后,被ban时间,这个会覆盖[DEFAULT]中的全局设置 port = ssh # 端口设置,ssh表示默认的22端口,如果改了ssh监听端口,这里需要同步修改 logpath = %(sshd_log)s backend = %(sshd_backend)s -
查看
利用
fail2ban-client命令工具可以查看相关信息,比如ban的ip,也可以通过这个命令进行解禁。/var/log/fail2ban.log为fail2ban的日志文件。
软件安装
可以下tarball源码,自己编译,自己安装,优点是可定制化,缺点是难度高,需要懂相关语言。一般仅仅使用软件,直接下载编译好的二进制文件即可。
可以下载好二进制文件,比如下载到U盘,挂载进系统,然后安装即可,也可以使用在线安装机制。
目前二进制安装根据发行版主要有2种方式:
-
dpkg
Debian,Ubuntu等采用这种方式
-
RPM
Centos采用这种方式
不管采用哪种方式,实际都是将程序按一定规范编译打包,制作成软件。打包成对应的规范就可以被对应的安装方式识别。
实际上dpkg和RPM也不仅仅用来安装二进制,软件release时,一般会出2个版本,以rpm为例,一个是编译版xxx.rpm,一个是源码版xxx.src.rpm,源码版可以由RPM编译成xxx.rpm二进制版,然后才能安装。
采用上述安装方式会先检测软件依赖,如果依赖没有安装,那么就不予安装。
安装成功会将软件信息写入dpkg或RPM数据库,方便查询、升级、卸载。
RPM
RPM数据库位于/var/lib/rpm目录下,这个数据库很重要,因为软件升级、查询等都要经过这个数据库比对。
如果数据有问题可以使用rpm --rebuilddb重建数据库
上面提到过,RPM安装时要检查依赖软件是否已安装,如果没有安装,那么本次安装就失败了。
有没有什么办法,让软件在安装时,自动安装依赖,就像Maven下载依赖包一样,整个依赖链上的都会下载下来,有,那就是yum机制。
使用yum安装时,会先向软件库(可以设置源)下载清单,然后通过清单和本机RPM数据库对比,下载依赖,然后再安装目标程序。yum作用是处理依赖链,真正干安装这个活的还是rpm。
安装
[root@study ~]# rpm -ivh package_name
选项与参数:
-i :install 的意思
-v :察看更细部的安装信息画面
-h :以安装信息列显示安装进度还有些选项
--test # rpm -ivh package_name --test 可以用来测试该软件是否能够安装到本机中,比如依赖是否满足
--nosignature # 绕过数字签名检查,除非你明确知道来源,否则尽量不要使用
--prefix # 安装到非正规路径,软件默认都会按照FHS的规范安装到指定的目录更新
rpm -Uvh package_name # 软件已安装则升级,没安装会去安装
rpm -Fvh package_name # 只升级不安装查询
[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 文件内的信息,而非已安装的软件信息!注意!卸载
rpm -eYUM
yum可以实现在线安装,升级,查询,必须要有对应的yum server,因为数据都来源于这个yum server。
查询
[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 的功能!相关指令不仅仅是本机查询,还会去yum server上查询。比如yum search 会去yum server上查询相关软件。
yum list updates # 查询可供升级的软件
yum provides passwd # 查询提供这个文件的软件有哪些yum repolist all # 可以查看设置的所有yum server软件库安装
[root@study ~]# yum [option] [安装与升级的工作项目] [相关参数]
选项与参数:
install :后面接要安装的软件!
update :后面接要升级的软件,若要整个系统都升级,就直接 update 即可移除
yum remove package_name配置软件源
一般系统会有3个源的配置,base,updates,extras
vim /etc/yum.repos.d/CentOS-Base.repo # 修改base源,主要是baseurl地址的修改,还有其他源同样可以修改正常如果要增加软件源(不是修改已有的base,updates,extras等),最好是在yum.repos.d目录下新建.repo文件。
如果因为意外造成本机的清单和软件库的清单不同步,软件就可能出现无法更新的问题。比如修改了软件源,但是没修改库名称,可能造成不同步,这时候需要进行清理。
yum clean all增加其他源:
很多源都是针对特定的方向的软件集合
比如现在要增加一个epel源
vim /etc/yum.repos.d/epel.repo
[epel]
name = epel packages
baseurl = https://dl.fedoraproject.org/pub/epel/7/x86_64/
gpgcheck = 0 # 不验证数字签名,如果要验证,需要指定gpgkey = /****,指定公钥的文件位置
enabled = 0 # 不启用对于不启用的软件源,如果要安装这个源里的软件,要么提前启用,要么安装时临时启用
yum --enablerepo=epel install package_name更换国内源
-
备份/etc/yum.repos.d目录
-
下载源,命名为Centos-Base.repo
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo -
添加epel源
# 安装epel源 yum install -y https://mirrors.aliyun.com/epel/epel-release-latest-8.noarch.rpm # 替换阿里云镜像 sed -i 's|^#baseurl=https://download.example/pub|baseurl=https://mirrors.aliyun.com|' /etc/yum.repos.d/epel* sed -i 's|^metalink|#metalink|' /etc/yum.repos.d/epel* -
更新缓存
yum clean all yum makecache # 避免每次都从服务器上请求
如果提示Repository extras is listed more than once in the configuration,可以把extras.repo禁用掉
SSH
连接验证步骤
密钥验证过程:
-
TCP连接
-
使用DH算法商量出相同密钥,建立加秘通道
本质上就是双方基于公共算法,都生成一对公私钥对,然后交换公钥,使用对方的公钥和自己的私钥可以计算出一个相同的key,这个key将被用于加密通信。
-
client使用private key推导出签名发送给server
ssh-keygen -lf xxx 公私钥pairs推导出的签名是一样的。
-
server使用public key推导出签名,看能否匹配
-
使用匹配的public key加密一个随机字符串,发送给client
-
client使用private key解密,并对解密结果进行hash签名,发送给server
-
server对随机字符串进行同样的hash,然后比对,成功则验证完成
密钥验证可以一定程度上防止中间人攻击,除非public key泄露,建议使用。
密码验证过程:
- 建立连接,并协商密钥过程一样
- server收到请求后,将自己的public key发给client
- client使用public key加密账号密码,发送给server
- server使用private key解密,然后验证账号密码
这个过程有个严重问题,无法确认server为目标服务器,还是中间人伪造的。DH协商是不能确定目标是谁的,它只管协商密钥。而server返回的public key,client也是没有强制验证手段的,所以完全有可能是中间人发回来的public key。
在登录验证(密码或密钥)的时候一般都会出现类似这样的提示:
ssh root@xxxxxx
The authenticity of host 'xxxxx (xxxx)' can't be established.
ED25519 key fingerprint is SHA256:sa5vDYS0yhdMRXO6CgMrp9AcQoVQRiDw6TnzTKesnzQ.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
....提示无法确认目标,但是告诉你对方的公钥指纹是SHA256:xxxx。这就需要人为验证了,比如使用安全的手段登录(物理登录)然后查看主机的公钥指纹(不是你的登录公钥):
ssh-keygen -E sha256|md5 -lf /etc/ssh/ssh_host_xxxxx_key.pub上面的输入yes后,服务器的公钥就会存储在client的:
~/.ssh/known_hosts下次再登录就没有相关提示了。
进程相关
关于SSH连接的过程:
- 客户端(比如xshell)连接linux
- 连接成功后SSHD守护进程,创建子进程 sshd: root[priv](和用户有关)
- sshd: roo[priv]创建子进程sshd: root@pts/0,虚拟终端进程
- 虚拟终端进程又创建bash(shell)子进程
通信过程:
客户端通过socket将命令传给虚拟终端,虚拟终端作为bash的输入,bash得到输入命令后,根据命令创建对应的子进程。
这个过程也能解释为什么ssh一断开,有些进程就直接停止运行了,因为父进程终止了。
端口转发
如果在远程服务器上端口绑定在了127.0.0.1:9229,意味着,这个端口外部无法访问,此时可以通过端口转发建立隧道,将9229映射到本机的某个端口:
比如:
ssh -L 9339:localhost:9229 user@host -p port # 22端口可以省略这个意思是将host服务器上的9229端口映射到本机的9339端口,这2个端口的连接是通过user@host来建立的隧道完成。
localhost是相对于host主机来说的,实际上你完成可以将另一台服务器通过user@host和本机建立隧道。
同样的也可以建立反向隧道,也就是将本机的端口映射到远程服务器上,在远程服务器上可以通过localhost:port直接访问本机映射的端口。
ssh -R 9339:localhost:9229 user@host -p port密钥登录
很多时候频繁的输入密码是个很麻烦且危险的事,可以通过SSH生成密钥对,将公钥上传到服务器上,本地用私钥进行登录。
ssh-keygen -t ed25519 -C ”xxx@email.com“ # 生成密钥对
ssh-copy-id -p <port_number> user@server_ip_address # 公钥上传服务器
# 可以使用-i指定要传输的xxx.pub公钥文件,登录的时候也可以使用-i指定私钥文件,如果不愿意每次登录都指定(默认只会读取个人文件中的.ssh下的私钥),可以在当前bash中使用alias
# 没有ssh-copy-id时,可以直接把公钥写入~/.ssh/authorized_keys文件中
cat xxx_id_rsa.pub | ssh -p <port_number> user@server_ip_address 'cat - >> ~/.ssh/authorized_keys'对于需要连接多个linux host时,可以使用~/.ssh/config来进行配置:
Host ubuntu-ztjt # 可以使用规则进行匹配
HostName 192.168.1.222
User ztjt
Port 22
IdentityFile ~/.ssh/ubuntu-ztjt_id_rsa # 指定私钥然后可以通过ssh ubuntu-ztjt进行连接。
使用密钥登录时,就可以关掉PasswordAuthentication了。
需要注意的时,有时候关闭了
PasswordAuthentication,但是并没有生效,可以使用sudo sshd -T检查下配置,比如ubuntu,默认的有个/etc/ssh/sshd_config.d/50-cloud-init.conf配置文件,需要把这里的也改了才会生效。
SSH-AGENT
功能
对于需要连接多个服务端,可以使用ssh_config配置。但是这个配置还需要对应到具体的私钥上,更重要的是无法实现在目标服务器上直接登录另一个服务器功能。
可以使用ssh-agent,2个核心功能:
-
client连接时,自动尝试它管理的所有private key(实际上是指纹)去连接。不需要人为去对应选择哪一个私钥。
-
forwad agent功能:
传统: client → A,client → B
agent: client → A → B
A可以在没有B的private key情况下使用forward agent能力直接登录B,当然前提是client有B的private key。
这是怎么实现的?
当在A上使用ssh客户端连接B时,会首先查看有没有SSH_AUTH_SOCK这个环境变量,有则和这个socket通信,这个socket本质是由sshd创建的,sshd将请求转发到当前连接的ssh client,client又会将请求转发到ssh-agent上,ssh-agent开始处理连接,进入常规流程。
当你使用ssh-agent登录到A上时,且A的sshd_config上开启了AllowAgentForwarding yes,A上自动会有SSH_AUTH_SOCK这个环境变量。
上面有2个转发过程,A上的sshd需要转发到client,client需要转发到ssh-agent,所以要使用forward agent功能需要开启:
-
A的sshd需要开启
AllowAgentForwarding yes,这个默认开启。 -
client的ssh需要开启
# 允许进行转发的主机,*为所有 Host * ForwardAgent yes
client是怎么转发到ssh-agent的,也是通过SSH_AUTH_SOCK这个环境变量。
当开启ssh-agent时:
-
linux:
eval `ssh-agent` -
windows: 启动OpenSSH Authentication Agent服务
win10可能出现1058错误。解决:
Get-Service ssh-agent Get-Service ssh-agent | Select StartType Get-Service ssh-agent | Set-Service -StartupType Automatic Start-Service ssh-agentpowershell中运行,再去服务中开启即可。
以linux为例,启动时会自动出现2个环境变量:
SSH_AUTH_SOCK=/tmp/ssh-AjtQyLw5MQyQ/agent.383531
SSH_AGENT_PID=383532 #PID一般就是SOCK + 1必须要有这2个变量,否则就无法使用ssh-agent的服务。
使用
-
启动ssh-agent,见上。
-
配置forward,见上。
-
将私钥添加进ssh-agent:
ssh-add ~/.ssh/xxxkey其他:
-D 删除ssh-agent中所有私钥(指纹) -d key_file 删除指定私钥 -L 列出agent当前主机上所有公钥参数,即公钥文件中的内容 -l 列出agent当前已保存的指纹信息 -t 设置私钥(指纹)的有效期。默认单位为秒,可以指定m(分钟)、h(小时)、d(天)、w(周) -x 使用一个密码将agent锁起来(lock),锁起来的agent将不再提供任何服务 -X 解锁agent
-
配置ssh client
如果不想每次都输入
ssh user@host -p,可进行host配置,配置见密钥登录部分。同时可以配置允许forward的host。
Host ubuntu-ztjt # 可以使用规则进行匹配 HostName 192.168.1.222 User ztjt Port 22 ForwardAgent yes IdentityFile ~/.ssh/xxx_ed25519 # windows系统 gitee,github需要设置这个,原因不明linux: /etc/ssh/ssh_config,windows: ~/.ssh/config
文件传输
可以使用基于SSH的scp命令传输文件。
scp /path/to/local/file user@remote:/path/to/destination/ #本地传给远程
scp user@remote:/path/to/remote/file /path/to/destination/ #远程传到本地
scp -r /path/to/local/directory user@remote:/path/to/destination/ #将整个目录复制过去
scp -r --exclude='*.log' --exclude='*.bak' /path/to/source user@remote:/path/to/destination #排除某些文件还可以结合tar命令来进行远程传输、规定文件:
tar czf - /local/dir | ssh user@remote "cd /remote/dir; tar xzf -" # 将/local/dir这个目录及包含的子文件和目录打包到输出流,然后管道到输入流,被tar xzf -使用,也就是解压到/remote/dir目录下ssh user@remote "cd /remote/dir; tar czf - ." | tar xzf - # 连接远程,打包当前目录下的所有子文件和子目录(不包含目录本身),管道到当前并解压。ssh user@remote "cd /remote/dir; tar czf archive.tar.gz file1 file2 dir1" # 在远程计算机上将文件和目录打包成 tar.gz 归档文件
ssh user@remote "cd /remote/dir; tar xzf archive.tar.gz" # 在远程计算机上解压缩 tar.gz 归档文件tar czf - . | ssh user@remote "cat > archive.tar.gz" # 压缩后直接管道到后面的命令,cat拿到输入流,进行输出,输出重定向到archive.tar.gz,这就是打包并复制了,少了解压的步骤。
tar xzf nodejs.tar.gz -C /path/to/destination # -C指定解压路径,默认是当前目录