[关闭]
@mrz1 2017-12-28T11:10:12.000000Z 字数 10024 阅读 714

2017-12-22课程笔记(select 函数 以及 grub 破解root口令)

笔记


检查磁盘空间利用率

  1. max=5
  2. df -h |grep "/dev/sd" |while read disk ;do
  3. per=`echo $disk |sed -r 's/.* ([0-9]+)% .*/\1/'`
  4. name=`echo $disk | cut -d' ' -f1`
  5. [ "$per" -gt "$max" ] && echo $name 空间利用率超过了 ${max}%
  6. done

PS1、PS2、PS3

PS1 命令提示符设置
PS2 多行重定向的提示符
PS3 select的提示符

select循环与菜单

  1. select variable in list ;do
  2. 循环体命令
  3. done

select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3 提示符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量REPLY 中

select与case

  1. select 是个无限循环,因此要记住用break 命令退出循环,或用exit 命令终止脚本。也可以按ctrl+c 退出循环
  2. select 经常和case 联合使用
  3. 与for 循环类似,可以省略in list,此时使用位置参量

select 例子

  1. [root@centos6 ~]#vim select.sh
  2. # Date: 2017-12-23
  3. # FileName: select.sh
  4. .......
  5. # -------------------------------------------------------------
  6. PS3="请输入查询编号查询价格:"
  7. select menu in 宫爆鸡丁 拉面 鲍鱼 小龙虾 退出;do
  8. case $REPLY in
  9. 1)
  10. echo '宫爆鸡丁 ¥15'
  11. ;;
  12. 2)
  13. echo '拉面 ¥15'
  14. ;;
  15. 3)
  16. echo '鲍鱼 ¥30'
  17. ;;
  18. 4)
  19. echo '小龙虾 ¥50'
  20. ;;
  21. 5)
  22. break
  23. ;;
  24. *)
  25. echo '$REPLY 输入错误 '
  26. echo '请重新输入'
  27. ;;
  28. esac
  29. done

运行结果:

  1. [root@centos6 ~]#bash select.sh
  2. 1) 宫爆鸡丁 3) 鲍鱼 5) 退出
  3. 2) 拉面 4) 小龙虾
  4. 请输入查询编号查询价格:1
  5. 宫爆鸡丁 15
  6. 请输入查询编号查询价格:2
  7. 拉面 15
  8. 请输入查询编号查询价格:3
  9. 鲍鱼 30
  10. 请输入查询编号查询价格:4
  11. 小龙虾 50
  12. 请输入查询编号查询价格:5

常用信号 (kill -l 所有)

  1. HUP 1 终端断线
  2. INT 2 中断(同 Ctrl + C
  3. QUIT 3 退出(同 Ctrl + \)
  4. TERM 15 终止
  5. KILL 9 强制终止
  6. CONT 18 继续(与STOP相反, fg/bg命令)
  7. STOP 19 暂停(同 Ctrl + Z

信号捕捉trap

trap '触发指令' 信号
自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行原操作
trap ''
信号忽略信号的操作
trap '-'
信号恢复原信号的操作
trap -p
列出自定义信号操作

trap示例

  1. #!/bin/bash
  2. trap 'echo Don not break' INT
  3. trap -p
  4. for((i=0;i<=10;i++));do
  5. sleep 1
  6. echo $i
  7. done
  8. trap ''
  9. int
  10. trap -p
  11. for((i=11;i<=20;i++));do
  12. sleep 1
  13. echo $i
  14. done
  15. trap '-'
  16. int
  17. trap -p
  18. for((i=21;i<=30;i++));do
  19. sleep 1
  20. echo $i
  21. done

函数介绍

函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程

它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分

函数和shell程序比较相似,区别在于:
Shell程序在子Shell中运行
而Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改

系统中定义函数位置cat /etc/init.d/functions

定义函数

函数由两部分组成:函数名和函数体
help function

  1. 语法一:f_name(){...函数体...}
  2. 语法二:function f_name{...函数体...}
  3. 语法三:function f_name(){...函数体...}

函数使用

函数的定义和使用:
可在交互式环境下定义函数
可将函数放在脚本文件中作为它的一部分
可放在只包含函数的单独文件中
调用:函数只有被调用才会执行(source点命令)
调用:给定函数名
函数名出现的地方,会被自动替换为函数代码
函数的生命周期:
被调用时创建,返回时终止

函数返回值

函数有两种返回值:
函数的执行结果返回值:
使用echo等命令进行输出
函数体中调用命令的输出结果
函数的退出状态码:
默认取决于函数中执行的最后一条命令的退出状态码
自定义退出状态码,其格式为
return 从函数中返回,用最后状态命令决定返回值
return 0 无错误返回。
return 1-255 有错误返回

交互式环境下定义和使用函数

示例:dir() {> ls-l> }
定义该函数后,若在$后面键入dir,其显示结果同ls-l的作用相同dir

该dir函数将一直保留到用户从系统退出,或执行了如下所示的unset命令:unsetdir

在脚本中定义及使用函数

函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用
调用函数仅使用其函数名即可
示例:

  1. cat func1
  2. #!/bin/bash
  3. # func1
  4. hello(){
  5. echo "Hello there today's date is `date +%F`"
  6. }
  7. echo "now going to the function hello"
  8. hello
  9. echo "back from the function"

使用函数文件

可以将经常使用的函数存入函数文件,然后将函数文件载入shell

文件名可任意选取,但最好与相关任务有某种联系。例如:functions.main

一旦函数文件载入shell,就可以在命令行或脚本中调用函数。可以使用set命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数

若要改动函数,首先用unset命令从shell中删除函数。改动完毕后,再重新载入此文件

创建函数文件 函数文件示例:

  1. cat functions.main
  2. #!/bin/bash
  3. #functions.main
  4. findit(){
  5. if [ $# -lt 1 ] ; then
  6. echo "Usage:findit file"
  7. return 1
  8. fi
  9. find / -name $1 print
  10. }

载入函数

函数文件已创建好后,要将它载入shell

定位函数文件并载入shell的格式:. filename 或source filename

注意:此即<点> <空格> <文件名>这里的文件名要带正确路径

示例:上例中的函数,可使用如下命令:. functions.main

检查载入函数

使用set命令检查函数是否已载入。set命令将在shell中显示所有的载入函数
示例:

  1. set findit=( )
  2. {
  3. if [ $# -lt 1 ]; then
  4. echo "usage :findit file";
  5. return 1
  6. fi
  7. find / -name $1 -print
  8. }

执行shell函数

要执行函数,简单地键入函数名即可
示例:
findit groups
/usr/bin/groups
/usr/local/backups/groups.bak

删除shell函数

  1. 现在对函数做一些改动后,需要先删除函数,使其对shell不可用。使用unset命令完成删除函数
  2. 命令格式为:unset function_name
    示例:unset findit 再键入set命令,函数将不再显示
  3. 环境函数
    使子进程也可使用
    声明:export -f function_name
    查看:export -f 或declare -xf

函数参数

函数可以接受参数:
传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如“testfuncarg1 arg2 ...”4
在函数体中当中,可使用2, ...调用这些参数;还可以使用*, $#等特殊变量

函数变量

变量作用域:
环境变量:当前shell和子shell有效
本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数
局部变量:函数的生命周期;函数结束时变量被自动销毁

注意:如果函数中有局部变量,如果其名称同本地变量,使用局部变量

在函数中定义局部变量的方法local NAME=VALUE

函数递归示例

函数递归:函数直接或间接调用自身 注意递归层数

递归实例:

阶乘是基斯顿·卡曼于1808 年发明的运算符号,是数学术语一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且有0的阶乘为1,自然数n的阶乘写作n!

  1. n!=1×2×3×...×n
  2. 阶乘亦可以递归方式定义:0!=1n!=(n-1)!×n
  3. n!=n(n-1)(n-2)...1
  4. n(n-1)! = n(n-1)(n-2)!

示例:1

  1. fact.sh
  2. #!/bin/bash
  3. fact() {
  4. if [ $1 -eq 0 -o $1 -eq 1 ]; then
  5. echo 1
  6. else
  7. echo $[$1*$(fact $[$1-1])]
  8. fi
  9. }
  10. fact $1

实例:1简写

  1. fact () {
  2. [ "$1" -eq 0 ] && echo 1 && return
  3. echo $[`fact $[$1-1]`*$1]
  4. }
  5. read -p "阶乘算法,请输入数字:"n
  6. fact $n

fork炸弹

fork炸弹是一种恶意程序,它的内部是一个不断在fork进程的无限循环,实质是一个简单的递归程序。由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资源
函数实现
:(){ :|:& };:
bomb() { bomb | bomb & }; bomb
脚本实现

  1. cat Bomb.sh
  2. #!/bin/bash
  3. ./$0|./$0&

练习

  1. 编写函数,实现OS的版本判断
  1. osversion () {
  2. echo `sed -r 's/.* ([0-9]+)\..*/\1/' /etc/centos-release`
  3. }
  1. 编写函数,实现取出当前系统eth0的IP地址
  1. osversion () {
  2. num=`sed -r 's/.* ([0-9]+)\..*/\1/' /etc/centos-release`
  3. if [ $num -eq 6 ];then
  4. echo `ip addr|grep "scope global"|sed -r "s/.* (.*)\/.*/\1/"`
  5. fi
  6. if [ $num -eq 7 ];then
  7. echo `ifconfig ens33 |grep netmask|tr -s " " :|cut -d: -f3`
  8. fi
  9. }
  10. osversion
  1. 编写函数,实现打印绿色OK和红色FAILED
  1. [root@centos6 ~]#. /etc/init.d/functions //直接调用系统脚本
  2. [root@centos6 ~]#action "234567890"
  3. 234567890 [ OK ]
  4. [root@centos6 ~]#action "234567890" false
  5. 234567890 [FAILED]
  1. 编写函数,实现判断是否无位置参数,如无参数,提示错误

练习

编写服务脚本/root/bin/testsrv.sh,完成如下要求
1. 脚本可接受参数:start, stop, restart, status
2. 如果参数非此四者之一,提示使用格式后报错退出
3. 如是start:则创建/var/lock/subsys/SCRIPT_NAME, 并显示“启动成功”考虑:如果事先已经启动过一次,该如何处理?
4. 如是stop:则删除/var/lock/subsys/SCRIPT_NAME, 并显示“停止完成”考虑:如果事先已然停止过了,该如何处理?
5. 如是restart,则先stop, 再start考虑:如果本来没有start,如何处理?
6. 如是status, 则如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示“SCRIPT_NAMEis running...”如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“SCRIPT_NAME is stopped...”其中:SCRIPT_NAME为当前脚本名
7. 在所有模式下禁止启动该服务,可用chkconfig和service命令管理
参考:

  1. #! /bin/bash
  2. # chkconfig: 35 99 00 //3和5模式是on 99编号最后打开服务 00优先关闭服务
  3. # description: this is a test service
  4. case $1 in
  5. start)
  6. touch /app/testsrv
  7. echo testsrv is starting
  8. sleep 5 // 开机时为了能看到这个服务
  9. ;;
  10. stop)
  11. rm -f /app/testsrv
  12. echo testsrv is stopped
  13. ;;
  14. restart)
  15. echo testsrv is stopped
  16. echo testsrv is starting
  17. ;;
  18. status)
  19. [ -f /app/testsrv ] && echo testsrv is running || echo testsrv is stopped
  20. ;;
  21. esac
  22. chmod +x testsrc 添加执行权限
  23. chkconfig --add testsrv 添加到服务列表中
  24. chkconfig --list testsrv 查看所有模式对这个模式开还是关

练习

编写脚本/root/bin/copycmd.sh
1. 提示用户输入一个可执行命令名称
2. 获取此命令所依赖到的所有库文件列表
3. 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下如:
/bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd==> /mnt/sysroot/usr/bin/passwd
提示:which ls 查询ls命令对应路径
4. 复制此命令依赖到的所有库文件至目标目录下的对应路径下:
如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
提示:ldd /bin/ls 命令依赖到的所有库文件
5. 每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,并重复完成上述功能;直到用户输入quit退出

练习

  1. 编写函数实现两个数字做为参数,返回最大值
  2. 斐波那契数列又称黄金分割数列,因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、......,斐波纳契数列以如下被 以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2)
    利用函数,求n阶斐波那契数列
  3. 汉诺塔(又称河内塔)问题是源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘,利用函数,实现N片盘的汉诺塔的移动步骤

启动流程及排错

监控服务

  1. yum install telnet-server 安装

  2. vim /etc/xinet.d/telnet
    disable=no 编写文件
    或者 命令生成 chkconfig telnet on

  3. chkconfig --list 所有服务

在LVM情况下,误删除BOOT下文件和/ETC/FSTAB文件,如何恢复之?

误删除BOOT下文件和/ETC/FSTAB文件
可以参考:实验误删除 initramfs

启动流程

注意:正常级别下,最后启动一个服务S99local没有链接至/etc/rc.d/init.d一个服务脚本,而是指向了/etc/rc.d/rc.local脚本

不便或不需写为服务脚本放置于/etc/rc.d/init.d/目录,且又想开机时自动运行的命令,可直接放置于/etc/rc.d/rc.local文件中

/etc/rc.d/rc.local在指定运行级别脚本后运行
可以根据情况,进行自定义修改

  1. 1:2345:respawn:/usr/sbin/mingettytty1
  2. 2:2345:respawn:/usr/sbin/mingettytty2
  3. ...
  4. 6:2345:respawn:/usr/sbin/mingettytty6mingetty会自动调用login程序
  5. x:5:respawn:/etc/X11/prefdm -nodaemon

总结:/sbin/init--> (/etc/inittab) --> 设置默认运行级别--> 运行系统初始脚本、完成系统初始化--> (关闭对应下需要关闭的服务)启动需要启动服务--> 设置登录终端

CentOS 6 init程序为: upstart, 其配置文件:
/etc/inittab, /etc/init/*.conf,配置文件的语法遵循upstart配置文件语法格式,和CentOS5不同

CentOS6 启动流程

grub legacy

hexdump -C -n 512 /dev/sda 512字节
CentOS 6启动流程:
POST --> Boot Sequence(BIOS) --> Boot Loader --> Kernel(ramdisk) --> rootfs--> switchroot--> /sbin/init-->(/etc/inittab, /etc/init/*.conf) --> 设定默认运行级别--> 系统初始化脚本rc.sysinit--> 关闭或启动对应级别的服务--> 启动终端

  1. grub: GRandUnified Bootloader
  2. grub 0.97: grub legacy
  3. grub 2.x: grub2
  4. grub legacy:
  5. stage1: mbr
  6. stage1_5:mbr之后的扇区,让stage1中的bootloader能识别stage2所在的分区上的文件系统
  7. stage2:磁盘分区(/boot/grub/)
  1. 自己理解:
  2. boot 之后看到boot上面分区是ext4系统之后去找根但是不知道根在那就去找stage1_5/boot/grub/grub.conf这个文件,之后去找根

实验:1阶段446个字节修复方法;破坏/dev/sda 前446个字节

  1. dd if=/dev/zero of=/dev/sda bs=1 count=446 直接破坏446字节
  2. hexdump -C -n 512 /dev/sda 查看 后面加-V 更详细
    重启后机器会直接光盘启动(一看446个字节是空的不可引导只好就找别的,如果光盘没挂载彻底起不来错误提示)

    光盘没挂载彻底起不来

  3. 修复还需光盘引导 救援模式修复

    网络

continue

ok

ok

点击shell start shell之后 
chroot /mnt/sysimage 切换跟
greb-install /dev/sda 修复完成

实验2 : /boot/grub里面东西全部移走怎么修复

mv /boot/grub /app/ 移走
执行命令grub

grub

grub

现在删除10扇区
1. dd if=/dev/zero of =/dev/sda bs=1 count=5120 skip=512 seek=512
2. 重启之后错误提示是屏幕是黑屏。。
3. 修复还需光盘引导 救援模式修复

网络

continue

ok

ok

点击shell start shell之后
chroot /mnt/sysimage 切换跟
greb-install /dev/sda 修复完成(1 1.5 2 阶段全部都能修复)
这里 修复好了 稍等下sync 因为它写到缓存 立即重启有可能会出现问题

这个系统是个干净系统所以能启动没有进行过修复(新系统之前grub2阶段文件 没在/boot/grub里面 执行过修复命令后会把所有文件放到/boot/grub里面 所有没东西了 就启动失败)

grub安装

安装grub:
(1) grub-install
安装grub stage1和stage1_5到/dev/DISK磁盘上,并复制GRUB相关文件到DIR/boot目录下
grub-install --root-directory=DIR /dev/DISK
详解:DIR 是boot分区的上级目录 /根 ;/dev/DISK硬盘上不写在分区上是因为 grub 1阶段不属于任何分区446字节不属于任何分区 ;所以不能

(2) grub
grub> root (hd#,#)
hd硬盘的意思第一个#代表boot在那认为/boot为跟 例:root (hd0,0)、boot分区在第0个硬盘第一个分区
root (hd#,#)

grub> setup (hd#) #/boot分区在第0个硬盘

grub legacy

配置文件:/boot/grub/grub.conf<--/etc/grub.conf
stage2及内核等通常放置于一个基本磁盘分区

功用:
(1) 提供启动菜单、并提供交互式接口
a:内核参数
e: 编辑模式,用于编辑菜单
c: 命令模式,交互式接口
(2) 加载用户选择的内核或操作系统
允许传递参数给内核
可隐藏启动菜单
(3) 为菜单提供了保护机制
为编辑启动菜单进行认证
为启用内核或操作系统进行认证

grub的命令行接口

  1. help: 获取帮助列表
  2. help KEYWORD: 详细帮助信息
  3. find (hd#,#)/PATH/TO/SOMEFILE:
  4. root (hd#,#)
  5. kernel /PATH/TO/KERNEL_FILE: 设定本次启动时用到的内核文件;额外还可添加许多内核支持使用的cmdline参数
  6. 例如:max_loop=100 selinux=0 init=/path/to/init
  7. initrd/PATH/TO/INITRAMFS_FILE: 设定为选定的内核提供额外文件的ramdisk
  8. boot: 引导启动选定的内核

cat /proc/cmdline 内核参数
内核参数文档:/usr/share/doc/kernel-doc-2.6.32/Documentation/kernel-parameters.txt

识别硬盘设备(hd#,#)
hd#: 磁盘编号,用数字表示;从0开始编号

: 分区编号,用数字表示; 从0开始编号

(hd0,0) 第一块硬盘,第一个分区

手动在grub命令行接口启动系统

  1. grub> root (hd#,#)
  2. grub> kernel /vmlinuz-VERSION-RELEASE roroot=/dev/DEVICE
  3. grub> initrd/initramfs-VERSION-RELEASE.img
  4. grub> boot

配置文件:/boot/grub/grub.conf

  1. default=#: 设定默认启动的菜单项;落单项(title)编号从0开始
  2. timeout=#:指定菜单项等待选项选择的时长
  3. splashimage=(hd#,#)/PATH/XPM_FILE:菜单背景图片文件路径
  4. password [--md5] STRING: 启动菜单编辑认证
  5. hiddenmenu:隐藏菜单
  6. title TITLE:定义菜单项"标题", 可出现多次
  7. root (hd#,#):查找stage2及kernel文件所在设备分区;为grub的根
  8. kernel /PATH/TO/VMLINUZ_FILE [PARAMETERS]:启动的内核
  9. initrd/PATH/TO/INITRAMFS_FILE: 内核匹配的ramfs文件
  10. password [--md5|--encrypted ] STRING:启动选定的内核或操作系统时进行认证

如果 kernel和initrd位置写错了

1

2

重新编写 kernel与initrd 这两行顺序

  1. kernel /vmlinuz-2.6.32-696.el6.x86_64 ro root=UUID=54ed9b7b-f7a9-40d4-8bbf-15faed977b03 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet

  2. initrd /initramfs-2.6.32-696.el6.x86_64.img
    title windows server 2016

grub加密

生成grub口令
grub-md5-crypt
grub-crypt

破解root口令:启动系统时,设置其运行级别1

进入单用户模式:
(1) 编辑grub菜单(选定要编辑的title,而后使用e命令)
(2) 在选定的kernel后附加1, s, S或single都可以
(3) 在kernel所在行,键入"b"命令

破解root口令:

第一种:

破解root口令

在选定的kernel后附加1, s, S或single都可以
之后设置新口令passwd 重启完成
第二种:

1

2

第三种:
救援模式 直接能看密码是多少

第四种
密码加密

生成grub口令
grub-md5-crypt(已破解)--md5 加密密码
grub-crypt --encrypted 加密密码

password --md5 加密密码
password --encrypted 加密密码

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注