马哥M28三十一天、
进程管理和启动流程、
CentOS6及其之前的操作系统根进程是/sbin/init , centos5及其之前使用的安装管理工具是SysV ,CentOS6是upstart , CentOS7是systemd
单用户方式启动:修改root密码或者跳过异常服务快速启动系统; 启动菜单选择内核 a键进入编辑 rhgb quiet 后面加 1 -->esc ,b
给grub加密,不用明文。
grub-crypt >> /boot/grub/grub.conf :grub-crypt 采用是sha512加密的方式,md5不安全
在第一个title上面加上,应该在hiddenmenu行之上加上;
password --encrypted $1$d/YOm/$V6YVIw8YEs9ik.gSj/bfx1
1:加电到bootloader加载
系统加电,BIOS(基本输入输出系统)代码装载入内存
一:自检,主要负责监测系统外围关键设备(CPU、内存等)是否正常
1、根据配置的启动设备(如harddisk、cdrom、网卡--pxe方式等)去读区启动代码
A:硬盘启动:
(1)BIOS会读区硬盘第一个扇区的512Bytes中前446个字节bootloader代码,我们拷贝出硬盘第一扇区的内容
dd if=/dev/sda of=mbrFile bs=512 count=1 && file mbrFile
[plain] view plain copy
#dd if=/dev/sda of=mbrFile bs=512 count=1 && file mbrFile
记录了1+0 的读入
记录了1+0 的写出
512字节(512 B)已复制,0.000177423 秒,2.9 MB/秒
mbrFile: x86 boot sector; GRand Unified Bootloader, stage1 version 0x3, 1st sector stage2 0x449fe, GRUB version 0.94; partition 1: ID=0xee, starthead 0, startsector 1, 4294967295 sectors, extended partition table (last)\011, code offset 0x48
MBR会保存有bootloader代码,并且含有分区表记录,主要记录一些分区类型、是否是活动分区、分区跨度等信息。之后我们可以在分区上建立文件系统(常见的文件系统例如FAT、NTFS、EXT2、EXT3等等),俗称格式化。
"硬盘的第一个扇区是MBR(512字节,512 字节=446(引导程序)+64(分区表信息)+2(结束标记)),如果有安装grub,那么接下来的31KiB (62扇区)是grub引导程序的位置,也就是说,要使用grub这样的双引导程序,硬盘的第一个分区至少要从63扇区开始,而一般情况下(默认),硬盘的第一个分区是从2048扇区开始",这里63个扇区,其中第一个是MBR位置。
2.一、linux系统的启动过程 bootloader 常见包含:LILO grub spfidisk
1.加载BIOS,上电自检。因为BIOS中包含了CPU的相关信息、设备启动顺序信息、硬盘信息、内存信息、时钟信息、PnP特性
等。通过BIOS的设置,计算机就知道去读取哪个硬件设备了。
2.读取MBR,即主引导记录(注意:MBR不属于任何分区,所以使用grub-install修复boot loader即当前的grub时指定的一定是整块系统盘 /dev/sda)。(这里有几个MBR中概念:DPT:分区表,通俗说就是硬盘上记录分区信息的表。PBR:硬盘分区
引导记录,就是具体到某个分区时,上边记录着这个分区的一些信息,详细了解可度娘。)它的大小是512字节,里面存放了预
启动信息、分区表等信息。系统找到BIOS所指定的硬盘的MBR后,就会将其复制到0×7c00地址所在的物理内存中。其实被复制
到物理内存的内容就是Boot Loader,而具体到你的电脑,那就是lilo或者grub了。
3.Boot Loader。Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建
立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核做好一切准备。Boot Loader
有若干种,其中Grub、Lilo和spfdisk是常见的Loader。要了解GRUB的,可自行查阅资料。
4.Boot Loader加载内核,加载initrd。到此,这是本文要着重说明的地方。
关于GRUB:
grub引导也分为两个阶段stage1阶段和stage2阶段(有些较新的grub又定义了stage1.5阶段)。
1)、stage1:stage1是直接被写入到MBR中去的,这样机器一启动检测完硬件后,就将控制权交给了GRUB的代码。也就是上图所看到的前446个字节空间中存放的是stage1的代码。BIOS将stage1载入内存中0x7c00处并跳转执行。stage1(/stage1/start.S)的任务非常单纯,仅仅是将硬盘0头0道2扇区读入内存。而0头0道2扇区内容是源代码中的/stage2/start.S,编译后512字节,它是stage2或者stage1_5的入口。而此时,stage1是没有识别文件系统的能力的。如果感觉脑子有些晕了,那么下面的过程就直接跳过,去看stage2吧!
【外传】定位硬盘的0头0道2扇区的过程:
BIOS将stage1载入内存0x7c00处并执行,然后调用BIOS INIT13中断,将硬盘0头0道2扇区内容载入内存0x7000处,然后调用copy_buffer将其转移到内存0x8000处。在定位0头0道2扇区时通常有两种寻址方式:LBA和CHS。如果你是刨根问底儿型的爱好者,那么此时去找谷哥打听打听这两种方式的来龙去脉吧。
2)、stage2:严格来说这里还应该再区分个stage1.5的,就一并把stage1.5放在这里一起介绍了,免得大家看得心里乱哄哄的。好的,我们继续说0头0到2扇区的/stage2/start.S文件,当它的内容被读入到内存之后,它的主要作用就是负责将stage2或stage1.5从硬盘读到内存中。如果是stage2,它将被载入到0x820处;如果是stage1.5,它将被载入到0x2200处。这里的stage2或者stage1_5不是/boot分区/boot/grub目录下的文件,因为这个时候grub还没有能力识别任何文件系统。
? 如果start.S加载stage1.5:stage1.5它存放在硬盘0头0道3扇区向后的位置,stage1_5作为stage1和stage2中间的桥梁,stage1_5有识别文件系统的能力,此后grub才有能力去访问/boot分区/boot/grub目录下的 stage2文件,将stage2载入内存并执行。
? 如果start.S加载stage2:同样,这个stage2也不是/boot分区/boot/grub目录下的stage2,这个时候start.S读取的是存放在/boot分区Boot Sector的stage2。这种情况下就有一个限制:因为start.S通过BIOS中断方式直接对硬盘寻址(而非通过访问具体的文件系统),其寻址范围有限,限制在8GB以内。因此这种情况需要将/boot分区分在硬盘8GB寻址空间之前。
假如是情形2,我们将/boot/grub目录下的内容清空,依然能成功启动grub;假如是情形1,将/boot/grub目录下stage2删除后,则系统启动过程中grub会启动失败。
1.确定服务器的boot文件系统所在分区是哪块硬盘上的,首先在rescue模式下切换到正确的操作系统的根目录,然后使用grub-install /dev/sda 修复完成后,在此过程中需要注意的是可能会出现一些不能修复的bug, 是否完全完成后一定要sync同步一下,多sync几次
root (hd0,0) :说明,root是根的意思,此处就是指明(hd0.0)是根,而此第一块硬盘的第一个分区在实际自己的操作系统上就是/dev/sda1,对应就是挂在到/boot下,所以下面的"/"就是boot,而如果在安装操作系统的时候boot本身并没有独立分区,而是在根文件系统下,所以下面的使用必须相对于boot路径 kernel /boot/vmlinuz....
kernel /vmlinux.... ro root=/dev/sda2
initrd /initramfs....
#注意:如果/boot/initramfs$(uname-r)文件遭到破坏,在没有使用mkinitrd修复生成前重启计算机导致失败,必须进入rescue救援模式,使用mkinitrd工具生成
mkinitrd /boot/initramfs-$(uname -r) $(uname -r ) 最后参数应该指定准确的内核版本,并且生成的映像文件(.img)必须也是(initramfs-$(uname -r).img),格式必须准确
centos5
/boot/grub/grub.conf
/etc/inittab ---> /etc/rc.d/rc.sysinit---> /etc/fstab
---> /etc/sysctl.conf
---> /etc/rc.d/rc
---> /etc/rc.d/rcX.dge 2 /initramfs-$(uname -r).img 需要挂载/dev/sda2前提是有ext4.ko
--> /etc/rc.d/rcX.d/K.. S..
--> /etc/rc.local
重要:1.对系统重要配置文件以及脚本文件进行学习,理解逻辑思维和编程方式,进而可以详细理解系统以及服务运行;
2.学习其脚本,进行改良或者自行编写!!!
3.修改当前运行级别下的开机启动服务状态图形化工具: ntsysv; 命令行工具:chkconfig --level 2345 atd off/on
4.开机服务都在/etc/init.d/ ,对应的是当/etc/rc.d/rc.sysinit读取执行后,将运行级别传递参数给/etc/rc.d/rc,并且同时在/etc/rc#.d/.conf以及此目录下的所有对应的当前运行级别开机启动与关闭的服务都是软连接到/etc/rc.d/下的实际服务;开机服务S*,对比单个字符acs码大小进行排序(不是按照数字序号排),后启动的是高层次程序,依赖底层多,也应该先关闭;
第三十二天、
系统排错恢复;重点,强化练习实践
1.切记:在救援模式下,一定要chroot到指定目录/mnt/..,不能将文件挂载到rescure模式的根下!!
2.在命令界面下来回上下切换 shift+pageup shift+pagedown
3.[root@magedu 2018-03-26 functions]# blkid |grep sda2
/dev/sda2: UUID="f582fb22-c0bc-4fee-b42c-0c7c41708a65" TYPE="ext4" 在救援自主编写/etc/fstab时,必须将双引号去掉; 在选择内核的时候,在quiet后加 selinux=0
4.非常重要:在定位到了具体的文件是损坏了或者丢失了,1.rpm -qf /bin/filename ; 2.必须使用cp 到指定目录后,然后rpm2cpio filename |cpio -id 进行格式转换成cpio后在解压并生成指定目录,然后进入到想要指定的文件目录下拷贝指定损坏文件到指定位置!
:原则,针对问题定位如果是具体的文件的问题,通过rpm -qf filename来进行查找安装包,最小原则,rpm2cpio filename |cpio -id来进行恢复,拷贝包中具体单个文件进行恢复,不破坏其他文件配置
5.CentOS7中,救援模式选择 troubleshoot --> 检索修复/boot目录下的文件->grub2-install; 生成内核映像文件 initramfs-$(uname -r).img $(uname -r)
6.装载X11图形化界面:主要安装包组(yum grouplist 查出X windows .. 以及其他包组)
系统启动流程
进一步说明stage1 stage1.5 stage2 grub.conf:
因为stage1是直接写入到mbr中的,所以首先没有识别文件系统的能力,但是mbr不在任何分区中,所以当bios中断寻址硬盘的时候,mbr就可以将控制权直接交给boot loader即grub;
stage2是为了去读取/boot/grub/grub.conf,但是此时依然没有识别文件系统的能力,所以,stage1.5被stage1加载到内存中,在文件系统层抽象,stage1.5具有识别文件系统的能力,所以grub读取boot分区的sector上的stage2,这种情况下删除/boot/grub/stage2文件系统也能启动,但是如果是直接读取/boot/grub/stage2文件到内存,在没有stage2文件的时候是不能正常启动的(在rescue模式中重新安装grub此stage2文件也是必须使用的了)
post
stage 1 mbr
stage 1.5 grub
stage 2 /boot/grub/grub.conf
kernel
initramfs
/sbin/init
/etc/inittab
id:3:initdefault:
/etc/rc.d/rc.sysinit
/etc/fstab
/etc/rc3.d/rc
/etc/rc.d/rc3.d/S*
/etc/rc.d/rc.local
mingetty tty1-tty6
init5 X11
-
rm -rf /boot/grub/除grub.conf以外的所有文件,仍然可以启动
-
dd if=/dev/zero of=/dev/sda bs=1 count=446 破坏grub
rescue
chroot /mnt/sysimage
grub-install /dev/sdakernel /vmlinuz.... ro root=/dev/sda2 selinux=0
vim /etc/selinux/config
SELINUX=disabled
恢复 hhaaa
3.rm -rf /boot/grub/除grub.conf以外的所有文件,ERROR 15无法启动
cp /app/grub/stage2 /boot/grub
4.dd if=/dev/zero of=/dev/sda bs=1 count=10240 seek=512
rescue
chroot /mnt/sysimage
恢复/boot/grub/的Stage文件 一:从备份 二:grub-install
grub
root(hd0,0)
setup (hd0)
convert -resize 640x480 -colors 14 mage.jpg mage.xpm
post
mbr
stage 1 446
stage 1.5 root(hd0,0)
stage 2 kernel vmlinuz
init
....
rc.local
rhgb: 默认图形化启动
quiet: 启动过程不显示内核信息
/boot
vmlinuz-
initrd
grub/starge1 1_5 2 grub.conf
1.dd if=/dev/zero of=/dev/sda bs=1 count=446
stage 1阶段:grub-install
2.dd if=/dev/zero of=/dev/sda bs=1 count=10240 seek=512
stage 1.5阶段:grub-install
3.rm -rf /boot/grub/* stage 1.5 2:grub.conf
4.rm -rf /boot/* stage 1.5 2
实验:删除/etc/fstab及/boot下所有文件
a.进入Rescue,临时将/dev/sda2挂载到临时目录,然后编写/etc/fstab
b.重新进入Rescue,grub-install /dev/sda
c.编写grub.conf
1.恢复/etc/fstab :通过rpm -qf /etc/inittab来找到安装的包,然后通过rpm2info转换并解压,找到具体此文件进行复制到指定位置
如果根在LVM上,则先执行vgchange -ay,再挂载,将根临时观察法到临时目录,然后编写/etc/fstab
2.重启进入rescue,grub-install恢复/boot/grub目录
3.mount /dev/cdrom /media ; rpm -ivh /media/Packages/kernel-2.6xxx.rpm
4.vim /boot/grub/grub.conf
title
kernel
initrd
5.rpm -qf /sbin/init
upstart...rpm
6.cp /media/Packages/upstart...rpm /var/tmp
rpm2cpio upstart...rpm |cpio -id
cp sbin/init /sbin
LFS
stage 1 mbr grub-install,分区表 fdisk
stage 1.5 grub-install
stage 2 grub-install grub.conf
/boot/vmlinuz /boot/initrd
bash
ls
ping
ifconfig
pwd
1.在现有的虚拟机当中加一块硬盘20G,最好是单个磁盘文件。
2.如果当前虚拟机正在启动 echo '- - -' > /sys/class/scsi_host/host0[2]/scan
3.fdisk /dev/sdb 分2个,一个100,一个10G
4.将/dev/sdb1 /dev/sdb2格式化为ext4文件系统
5.mount /dev/sdb2 /mnt; mkdir /mnt/boot ; mount /dev/sdb1 /mnt/boot
6.grub-install --root-directory=/mnt /dev/sdb
7.cp /boot/{vmlinuz-xxx,initramfs-xx.img} /mnt/boot
8.vim /mnt/boot/grub/grub.conf
kernel /vmlinuz... ro root=/dev/sda2 selinux=0 init=/bin/bash
9.mkdir -p /mnt/{etc,dev,proc,sys,home,var,mnt,media,root,tmp,lib,usr/{bin,sbin,lib,lib64}
10.利用复制命令及其lib文件的脚本复制基本命令至/mnt下,如bash ls ifconfig ping hostname cat vi mount umount mv touch cp modprobe insmod df
11.拷贝网卡模块
modinfo e1000
cp /lib/modules/3.10.0-693.el7.x86_64/kernel/drivers/net/ethernet/intel/e1000/e1000.ko.xz /mnt/lib/modules
12.sync;sync;poweroff
13.创建新虚拟机,然后到硬盘创建步骤时,将硬盘文件从旧虚拟机的目录复制到新虚拟机的目录下。然后选择使用现有的硬盘,指定到该硬盘文件。最后开机。
1.清空/dev/sda的前446字节
2.清空/dev/sda的前10240字节,跳过512
3.删除grub.conf
4.删除/boot/grub
5.删除/boot
6.删除/etc/init/rcS.conf
7.删除/etc/rc.d/rc.sysinit
8.删除/etc/fstab
外加题:用户空间、内核空间、Tcp/ip协议栈
第三十二天、
1.kernel: 驱动程序集成到内核或模块化在内存调用
lsmod 列出已加载的所有模块
modinfo 模块名 显示某模块的详细信息
加载模块
modprobe 模块名 :modprobe 只能跟模块名,在编译内核加载模块时如果使用绝对路径则不行,使用insmod
加载模块名--使用模块名的绝对路径
insmod /mode..
卸载模块
modprobe -r 模块名
1.wget ftp://172.18.0.1/pub/Sources/sources/kernel/x.x.x.gz
2.tar -xvf x.x.x.xz
3.cp /boot/config... /root/x.x.x/.config 这样可以使用本系统的内核配置文件来替换编译内核时默认生成的config文件,能够使本系统支持
4.make menuconfig
5.make -j cpu核心数量 此为使用指定分配的cpu核心数量进行编译;使用lscpu 或 cat /proc/cpuinfo查看
注意:在编译过程中出现的报错的都不需担心,根据提示缺少的就是需要安装的包,可以使用rpm -qf qi 或者 yum list yum search ....
6.模块基本都是在内存中加载到内核,集成到内核的驱动不大
7.编译写入/boot的时候一定要注意,/boot的可用空间情况,否则可能导致失败;编译安装之后不要将新编译的内核调整为第一个,而是应该保持默认选择,手动选择启动,否则启动失败导致网卡模块加载不了~跑机房; 在进行长时间不间断的工作时,必须使用screen来进行保护进程操作
8.启动之后 cat /var/log/boot.log针对性查看是否完全成功
selinux
1.添加或者修改port类型的时候,对对应服务的配置文件首先要分清客户端(ssh_config)和服务端(如sshd_config)配置文件,然后将注释的PORT去掉注释,生效
2.思考思路重要: 1.服务端的配置的文件; 2.iptables防火墙策略; 3. selinux策略 tailf /var/log/xxxservice 根据日志semanage ...复制查看,
lsmod 列出已加载的所有模块
modinfo 模块名 显示某模块的详细信息
加载模块
modprobe 模块名
卸载模块
modprobe -r 模块名
1.wget ftp://172.18.0.1/pub/Sources/sources/kernel
2.tar -xvf x.x.x.xz
3.cp /boot/config... /root/x.x.x/.config
4.make menuconfig
4.make -j cpu核心处理器数量 :在分配好给服务器处理器的数量以及对应的核心处理器的数量后,全部指定使用会加快编译处理
5.make modules_install
6.make install
6/ make clean 清理编译后的二进制文件,保留源码文件
7.reboot
重启后可以查看启动日志
cat /var/log/boot.log
单独编译某个模块
make fs/ntfs/ntfs.ko
作业:
1、破解root口令,并为grub设置保护功能
2、破坏本机grub stage1,而后在救援模式下修复之
3、删除vmlinuz和initramfs文件后无法启动,两种方法恢复之
4、增加新硬盘,在其上制作能单独运行kernel和bash的系统
5、在U盘上定制linux,使其可启动系统,并具有网络功能
6、删除/etc/fstab和/boot目录的所有文件,并恢复之
7、编译安装kernel,启用支持ntfs文件系统功能
selinux
enforcing:强制模式
permissive: 警告模式
disabled:关闭模式
setenforce 0|1 警告|强制 使用临时禁用切换方式可以初步判断是否是selinux的问题,后续继续进行操作
sestatus 查看当前的状态
vim /etc/selinux/config
SELINUX=enforcing|permissive|disabled 决定下次开机时的selinux状态
系统启动在stage 2阶段的时,可更改内核参数,最后加上selinux=0表示disabled selinux=1表示enforcing
系统默认的文件系统以及其下的子目录和文件都是有默认的selinux安全上下文的期望值,可以通过restorecon -R 来通过期望值标签的数据库来进行恢复,而如果是新创建的文件系统或者目录是没有期望值标签的,所以引入增加期望值的方式添加到数据库中:
增加期望值 :此处 /app/website(/.)? 是利用正则表达式对website目录下判断是否含有其他的文件或者子目录,如果有则对其一并进行添加selinux标签
[root@centos7 website]# semanage fcontext -a -t httpd_sys_content_t '/app/website(/.)?'
restorecon -R /app/website/ :此处注意,是与chcon有相同之处,在对于目录及其下的子目录或者文件进行重设标签期望值的时候必须使用-R递归!
修改期望值
[root@centos7 website]# semanage fcontext -m -t var_log_t '/app/website(/.*)?'
删除期望值
[root@centos7 website]# semanage fcontext -d '/app/website(/.*)?'
增加端口号
semanage port -a -t http_port_t -p tcp 9527
生产环境为了安全起见,将一些高安全的服务端口都要进行更改,所以要使用semange port 对selinux期望策略数据库中服务bind的port进行增加策略,在进行修改配置文件使其生效
删除端口号
semanage port -d -t http_port_t -p tcp 9527
SELINUX boolean 对服务设置安全策略,对某项动作进行开关设置(on/off)
semanage boolean -l |grep serciexxx or semanage boolean -l |less 翻页查看
setsebool [-P] ftp_anon_write=on 开启匿名用户通过ftp服务上传功能 -P写入并保存设置
*****示例:通过Http协议将某用户的家目录共享出去
~userhomedir :进入某用户家目
1.首先对httpd服务进行配置,对http.conf文件 UserDir Disabled进行注释,并取消 UserDir public_html #根据注释说明应该在启用后必须在共享的用户家目录下创建 public_html;
2.当服务配置完成之后,要考虑的是防火墙或者就是selinux安全策略 semange boolean -l |grep http,此时在考虑selinux之前先通过浏览器Http进行访问 ip/~username/
结果显示forbidden,此为访问时通过使用httpd进程的用户身份对此目录没有访问权限(x),而执行某一个进程取访问某个目录或者文件的时候必须以用户的身份进行,所以httpd服务进程的用户通过ps查看是apache,而共享的用户家目录的权限对其他人来讲师---,所以此时应该使用setfacl -m u:apache:x dirname 对临时用户开启访问控制列表,针对目录最小权限是X即可
yum -y install setroubleshoot selinux排错日志管理
1.安装完成后如果有SELINUX报错警告,会在图形化界面上方有棕×××标点击查看详细信息;
2.setroubleshoot将错误信息写入/var/log/messages中,通过 tail -n 10 /var/log/messages |grep setroubleshoot可以快速查看,在命令行执行信息提示中 run后面的 sealert -l ...进行格式化显示,易读
3.在图形化界面如果关闭了报警图标不再显示,可以执行 sealert 就可重新调取selinux报警图标
4.信息来源 /var/log/audit/audit.log
SELINUX帮助文档的安装 : centos7.2 selinux-policy-devel ; centos7.3 selinux-policy-doc
- 执行mandb 因为安装完帮助文档包之后,数据库是非实时性的,需要通过mandb 或者 makewhatis(centos6)进行数据库更新写入;文档信息以及各种信息都要借助数据库
2.man -k _selinux
3.man 8 httpd_selinux 针对具体的httpd服务的selinux策略进行查看帮助文档! man 8 service_selinux
/etc/ssh/sshd_config
resuce救援模式默认是不开启selinux,所以退出后重启系统会重新打标签; 等于 restorecon [R]
1.logger “...” : logger "content.." 可以用来测试日志,手动生成 -->对应的进程是/usr/sbin/rsyslogd ,服务名称是rsyslog
如果 cp /var/log/messages /root/ ,此时复制之后的root下的messages文件ls -Z后发现是继承了root目录的标签, mv /root/messages /var/log/messages进行覆盖,此时/var/log/messages文件的标签还是root目录的不会变化; logger "..." 测试日志写入功能发现并未开启日志写入,所以:
(change context) chcon -R var_log_t /var/log/messages ,service rsyslog restart 或者 systemctl restart rsyslog (重启日志服务才能对配置以及日志文件等重新读取标签,因为进程是挑文件标签的即selinux的security context); chcon -R directory 针对目录必须是-R
cp 会使得复制后的文件继承所在当前目录的标签,而mv并不会使得文件标签有所变化: 所以,在某些场景下,文件权限以及文件其他表面数据都没有异常的情况下,用户或者进程不能正常访问文件和执行写操作了,要考虑其中之一的selinux标签策略问题
2.外加知识小结:关于用户客户端通过浏览器访问Linux服务器上的站点:主要就是通过浏览器域名和端口通过linux服务器上apache这个website用户及用户组身份进行的一系列访问(进程必须要以一个用户的身份去进行文件的访问等操作); 所以,对于权限的设定尽量不能chmod 777 user ,而是对在不同目录下的html目录进行标签重设,然后重启httpd服务,然后使用setfacl访问控制列表对某些如apache用户进行权限控制,从而达到安全的开放权限的访问目的(当然selinux是作用在最后的一层的防护,前面服务配置文件、防火墙、权限等都可优先设计);
通常情况下访问web的时候都是80,在实际环境中通过对端口的更改导致正常访问的某些服务不能访问或者链接,因为正常的建立socket是 (ip:port),端口的更改就会导致这种问题
第三十三天、 AWK 指定格式报表输出 非常重要
1.awk 如果变量RS ORS同时指定了,ORS输出记录分隔符取代的是RS,原默认换行符不替换
2.awk BEGIN'{print ARGV[ARGC-1]}' 1 2 3 ;如果想要将文件名作为参数输出而不读文件内容,使用ARGV[N]
3.awk 在使用正则匹配的时候必须使用双引号将字符串引起 df |awk '$0 ~ "/dev/sd" {printf "DEVICENAME:%-15s USEDSPACE:%s\n",$1,$3}'; !~表示左边不包含匹配
4.linux中对于未声明初始值的变量或数组在进行数学运算时,会自动识别为0
5.'pattern{action statements...}' filename 当pattern为boolean值时,1为真,0为假(这里一定要严格区分命令的退出状态返回值 $?)省略{action}部分默认打印$0即全域
为假时不执行 awk 'i=1;j=1{print i,j}' /etc/passwd --> i=1;相当于i=1{print $0};j=1{print i,j}
6.awk中对于字符以及字符串的使用必须使用双引号,否则都视为变量,没有赋值的变量如果要输出则给0,在逻辑运算中没有任何意义忽略
7、使用awk打印奇偶行:
打印奇数行: seq 10 |awk 'i=!i'
打印偶数行: seq 10 |awk '!(i=!i)'
seq 10 |sed -n 1~2p
seq 10 |sed -n 2~2p
8.BEGIN是在未读取文件内容前执行,而END则是读取文件最后一行执行,NR在END中就可以用来统计行数
[root@magedu(CentOS7) 2018-03-30 ~]# awk -F":" -v sum=0 'BEGIN{print "USERNAME salary"}{sum+=$3;printf "%-20s %s\n",$1,$3}END{sum=sum/NR;printf "avgsalary=%s\n",sum}' /etc/passwd 最后显示平均工资
[root@magedu(CentOS7) 2018-03-30 ~]# awk -F: 'BEGIN{printf "USERNAME SALARY LEVEL\n-------------------------------\n"}{if($3>3000){printf "%-20s %-10s %s\n",$1,$3,"high"}else if($3>1000){printf "%-20s %-10s %s\n",$1,$3,"soso"}else{printf "%-20s %-10s %s\n",$1,$3,"low"}}' /etc/passwd
:调试小总结,必须注意指定输入分隔符;printf要主动换行 ;else if(); 在awk的判断语句中定义变量,在整个action部分并不会全部重置(分判断情况);对于整数站位符最好使用%d; 在内置函数中比如要length(string)取长度,必须使用双引号对字符串进行引用,否则就会被识别为变量(未赋值的变量为空或0) length("string");
:在action部分使用循环时,必须注意变量初始值重置问题 n=1; while(n<=NF){..;n++} ,如果不定义n=1,则在执行完第一条记录后,后面的记录的判断条件n不会重置1,所以注意区分每条记录的字段循环处理即内部处理,初始值不重置;记录刷新重新读取新的记录则之前定义的变量初始值重置;
[root@magedu(CentOS7) 2018-03-30 ~]# awk 'BEGIN{sum=0;for(i=1;i<=100;i++){sum+=i}{print sum}}'
5050 -->注意:循环计算中,一个变量尤其是作为循环条件的变量不可能即作为计数器又作为求和等变量,必须另定义
** time awk '{..}' 使用time来进行处理用时计算,从而得出awk来计算的速度相对最快 ,所以,经常使用awk
2.awk 数组: 在使用循环如for循环的时候 for n in array ,则n表示array数组的下标
1.awk '/([[:digit:]]{1,3}.){3}.([[:digit:]]{1,3})/{print $0}' access_log
小总结:1.ip[$1] 这里awk应该根据文件的内容的具体格式进行指定具体点分隔符;
ip[$1]取的是每条记录的第一个域也就是Ip,因为变量或者数组在awk中只是隐式声明但未赋值的情况下,在参数比较或者数学运算的时候是初始值默认0的,所以可以进行++等运算,让数组key为已知条件内容Ip,值为对应的自增后的数量从而统计出Ip对应的访问数量
2. awk '!ip[$1]++' access_log 直接输出一次统计,利用取反非0不执行
[root@magedu(CentOS7) 2018-03-30 ~]# awk 'BEGIN{printf "IP IP_COUNT\n----------------------------\n"}/^[^:]/{ip[$1]++}END{for(n in ip){printf "%-18s-->%s\n",n,ip[n]}}' access_log
IP IP_COUNT
----------------------------
172.18.253.55 -->1788
172.18.251.122 -->52
172.18.251.150 -->34
172.18.251.141 -->30
172.18.251.160 -->157
172.18.251.170 -->457
172.18.251.107 -->14
172.18.251.109 -->51
172.18.251.145 -->50
172.18.0.223 -->12
172.18.253.21 -->74087
172.18.251.147 -->354
172.18.254.78 -->183
172.18.251.157 -->330
172.18.252.134 -->514
172.18.251.149 -->158
172.18.254.6 -->1643
172.18.250.183 -->81
172.18.251.21 -->81
172.18.254.34 -->659
for i in $(sipcalc ${ip_mask} | grep Usable|egrep -o "[0-9.]+" | eval echo `awk '{a[NR]=$0}END{split(a[1],b,".");split(a[2],c,".");for(i in b){if(b[i]!=c[i]){b[i]="{"b[i]".."c[i]"}"}};print b[1]"."b[2]"."b[3]"."b[4]}'` | tr " " "\n")
第三十四天
cut
cat -n
bc $[]
awk -F: '{printf "username:%-20s salary:%-10.2f shell:%s\n",$1,$3,$7}' /etc/passwd
[root@centos7 ~]# df |grep /dev/sd |awk '{printf "DevName:%s Used:%s\n",$1,$5}'
DevName:/dev/sda2 Used:19%
DevName:/dev/sda3 Used:1%
DevName:/dev/sda1 Used:55%
[root@centos7 ~]# df | awk '$0 ~ "/dev/sd" {printf "DevName:%-10s Used:%s\n",$1,$5}'
DevName:/dev/sda2 Used:19%
DevName:/dev/sda3 Used:1%
DevName:/dev/sda1 Used:55%
[root@centos7 ~]# df |awk '$1~"^/dev/sd[[:lower:]][[:digit:]]\>" && $5>=10 {printf "Filesystem: %-15s Used: %s\n",$1,$5}'
Filesystem: /dev/sda2 Used: 95%
Filesystem: /dev/sda1 Used: 48%
[root@centos7 ~]# df |awk '/\/dev\/sd[[:lower:]][[:digit:]]\>/{if($5>10){printf "DevName:%-10s Used:%s\n",$1,$5}}'
DevName:/dev/sda2 Used:19%
DevName:/dev/sda1 Used:55%
awk -F : '{print "USER USERID“;print $1":"$3} END{print "end file"}' /etc/passwd
练习:将/etc/passwd第一列当作姓名,第三列当作工资,打印报表,要求显示:
Name:zhangsan Salary:3300 Level:High
工资大于3000的,Level显示High,大于1000,小于等于3000的显示Soso,小于1000的显示LOW。
[root@LiuHongsen7 ~]# awk -F: '{if($3>3000){Level="High"}else if($3>1000 && $3<=3000){Level="Soso"}else{Level="Low"};printf "Name:%-20s Salary:%-20d Level:%s\n",$1,$3,Level}' /etc/passwd
[root@centos7 ~]# cat /root/grub2.cfg |awk '/^[[:space:]]+linux16/{n=1;while(n<=NF){print $n,length($n);n++}}'
练习:利用echo {1..10},打印如下结果
1 jishu
2 oushu
3 jishu
4 oushu
……
10 oushu
[root@nana ~]# echo {1..10} |awk '{i=1;while(i<=NF){if($i%2==0){print $i,"is oushu"} else{print $i, "is jishu"};i++}}'
1 is jishu
2 is oushu
3 is jishu
4 is oushu
5 is jishu
6 is oushu
7 is jishu
8 is oushu
9 is jishu
10 is oushu
[root@nana ~]# awk '{i=1;sum=0;while(i<=NF){sum+=$i;i++};print sum}' f1.txt 显示每行各自的总行
55
155
[root@nana ~]# awk '{i=1;while(i<=NF){sum+=$i;i++};print sum}' f1.txt 每行显示一次总和
55
210
[root@nana ~]# awk '{i=1;while(i<=NF){sum+=$i;i++}}END{print sum}' f1.txt 只显示总和
210
[root@centos7 ~]# awk '/[[:space:]]+linux16/{for(n=1;n<=NF;n++){print $n,length($n)}}' /root/grub2.cfg
linux16 7
/vmlinuz-3.10.0-693.el7.x86_64 30
root=UUID=be5fceff-51ad-43b7-82e4-84eabedb4e4f 46
ro 2
rhgb 4
quiet 5
LANG=en_US.UTF-8 16
linux16 7
/vmlinuz-0-rescue-8a71aef45fd94de19b4ba1c81c836c34 50
root=UUID=be5fceff-51ad-43b7-82e4-84eabedb4e4f 46
ro 2
rhgb 4
quiet 5
计算1加到100和为多少 : awk 内部算法问题,所以如果涉及到大量运算或者性能处理上要求速度,使用awk能够很大提高计算
使用time awk '{}' :time命令可以对命令的执行计算时间
[root@centos7 ~]# echo {1..100}|tr " " + |bc
5050
[root@centos7 ~]# for ((sum=0,i=1;i<=100;i++));do let sum+=i;done;echo $sum
5050
[root@centos7 ~]# awk BEGIN'{for(i=1;i<=100;i++){sum+=i};print sum}'
5050
[root@centos7 ~]# awk BEGIN'{i=1;while (i<=100) {sum+=i;i++};print sum}'
5050
[root@centos6 ~]# awk BEGIN'{sum=0;for(i=1;i<=100;i++){if(i%2==0){continue};sum+=i};print sum}'
2500
[root@centos6 ~]# awk BEGIN'{sum=0;for(i=1;i<=100;i++){if(i%2==1){continue};sum+=i};print sum}'
2550
[root@centos6 ~]# awk BEGIN'{sum=0;for(i=1;i<=100;i++){if(i%2==0){break};sum+=i};print sum}'
1
[root@centos6 ~]# seq 10 |awk '{if($1%2==0){next};print $1}'
1
3
5
7
9
[root@centos6 ~]# seq 10 |awk '{if($1%2!=0){next};print $1}'
2
4
6
8
10
[root@centos6 ~]# awk 'BEGIN{weekday["mon"]="Monday";weekday["tue"]="Tuesday";weekday["wen"]="Wendsday";for (n in weekday){print weekday[n]}}'
Wendsday
Monday
Tuesday
[root@centos6 ~]#awk -F: '{shell[$7]++}END{for(n in shell){print n,shell[n]}}' /etc/passwd
[root@centos6 ~]#awk '{ip[$1]++}END{for(n in ip){print n,ip[n] }}' access_log
[root@centos6 ~]#awk -F: '!shell[$0]++' /etc/passwd 去重
[root@nanyibo ~]# netstat -tan |awk '/^tcp/{state[$NF]++}END{for (n in state){print n,state[n]}}'
LISTEN 10
ESTABLISHED 1
[root@nanyibo ~]# awk 'BEGIN{srand();print int(rand()*100)}'
[root@nanyibo ~]# echo "2018:3:30 17:38:30" |awk 'sub(/:/,"-",$1)'
2018-3:30 17:38:30
[root@nanyibo ~]# echo "2018:3:30 17:38:30" |awk 'gsub(/:/,"-",$1)'
2018-3-30 17:38:30
[root@nanyibo ~]# cat netstat.log |awk '/^tcp/{split($5,ip,":");count[ip[1]]++}END{for(i in count){print i,count[i]}}'
[root@nanyibo ~]# cat awk.txt
function max(v1,v2){
v1>v2?var=v1:var=v2
return var
}
BEGIN{print max(a,b)}
[root@nanyibo ~]# awk -v a=30 -v b=20 -f awk.txt
30
[root@nanyibo ~]# awk -v a=10 -v b=20 -f awk.txt
20
***3.awk经典实例,一次处理多个文件,根据NR FNR的比较返回值进行文件内容格式化报表输出处理:
说明:由NR=FNR为真时,判断当前读入的是第一个文件a,然后使用{a[$2]=$0;next}
循环将a文件的每行记录都存入数组a,并使用$2第2个字段作为下标引用.
由NR=FNR为假时,判断当前读入了第二个文件b,然后跳过{a[$2]=$0;next},对第二个文件cdr的每一行都无条件执行{print a[$1]"|"$2},
此时变量$1为第二个文件的第一个字段,与读入第一个文件时,采用第一个文件第二个字段$2为数组下标相同.因此可以在此使用a[$1]引用数组。
accout文件:张三|000001
李四|000002
money文件: 000001|10
000001|20
000002|30
000002|15
[root@magedu 2018-03-24 app]# awk -F"|" 'NR==FNR{a[$2]=$0;next}{print a[$1],$2}' awk_test/{accout,money}
张三|000001 10
张三|000001 20
李四|000002 30
李四|000002 15
*** pattern{action...}{action...} :当action部分紧靠的前面的模式部分为真时则执行,使用Next可直接跳过当前行读取下一行进行处理;而当pattern部分为假时,则跳过第一个紧靠的action部分而执行第二个action部分-->注意!!
*** 区分next 和continue: next是跳过对当前行的处理或者其他处理(根据next的使用位置)而直接读取下一行记录处理;continue是直接跳过当前循环剩下部分进入到下一次循环
作业:计算男生总成绩,男生平均成绩,女生总成绩,女生平均成绩
mage 100 male
dongyang 90 male
yunzhen 60 female
lilin 100 female
male 190 95
female 160 80
作业:
1、统计/etc/fstab文件中每个文件系统类型出现的次数
2、统计/etc/fstab文件中每个单词出现的次数
3、提取出字符串Yd$C@M05MB%9&Bdh7dq+YVixp3vpw中
的所有数字
4、解决DOS***生产案例:根据web日志或者或者网络连接
数,监控当某个IP并发连接数或者短时内PV达到100,即调
用防火墙命令封掉对应的IP,监控频率每隔5分钟。防火墙命
令为:iptables -A INPUT -s IP -j REJECT
转载于:https://blog.51cto.com/12947626/2093350