Linux 第43,44天 函数和系统启动流程详解

时间: 20180903

时间: 20180904


目录

函数

函数返回值

函数文件

函数递归

fork×××

trap信号捕捉

脚本总结

脚本编写

编写函数,实现OS的版本判断

编写函数,实现取出当前系统eth0的IP地址

编写函数,实现打印绿色OK和红色FAILED

编写函数,实现判断是否无位置参数,如无参数,提示错误

编写服务脚本,实现服务的start,stop,status,restart

编写脚本: 复制命令和命令所调用的模块cpCMD.sh

系统启动顺序(CentOS6)

恢复mbr的bootloader(三个阶段都损坏都可以用以下命令来修复)

grub三个阶段出现损坏时状态现象

删除/boot文件夹并修复



函数

由若干条shell命令组成的语句块,实现代码重用和模块化编程,它与shell程序形式上

相似,不同的是它不是一个单独的进程,不能独立运行,两者区别在于shell程序在子shell

中运行,而shell函数则是在当前shell中运行。因此在当前shell中,函数可以对shell

中变量进行修改,除非在函数内部定义变量时前边加上local,如果加上此参数则表明

该变量只在此函数内部使用和外部其它变量没有关系


函数定义

function name { COMMANDS ; }

name () { COMMANDS ; }

function name () { COMMANDS ; }


显示所定义的函数

declare -f FUNC_name

如不加函数名则显示系统中当前shell所定义的function


撤消所定义的函数

unset FUNC_name


环境函数

declare -xf funcName

即将当前脚本中的函数被子shell中的脚本引用


函数参数

函数可以接受参数,当执行函数时在其后方加上的参数则可以使用$1,$2...来引用

和脚本后加参数引用原理相同,切记函数接受参数必须是调用函数名后边加参数


函数返回值

函数有两种返回值

1. 使用echo等命令进行输出

2. 函数体中调用命令的输出结果

函数的退出状态码

默认取决于函数中执行最后一条命令的退出状态码

自定义退出状态码其格式为

return 函数执行遇到return时则不会再执行函数的后续命令,

而是将函数的执行状态码即

return后跟的数值返回给脚本。

0无错误返回,1-255有错误返回


函数文件

函数可以定义在一个单独的文件里,当某脚本需要用到此前定义的函数文件时,只需要

使用source命令或.后边加上函数文件所在的路径,即可为此脚本引用函数文件里所定义

的函数。


函数递归

函数直接或间接调用自身

注意递归层数,如果太多,或所指定的参数未给

执行时有可能会导致系统崩溃(切记,切记)


递归实例

计算一个数的阶乘,如和的阶乘就是5*4*3*2*1, 依次类推

#!/bin/bash

fact(){

    if [ "$1" -eq 1 ];then

        echo 1

    else

        echo $[$1*$(fact $[$1-1])]

    fi

}

fact $1


fork×××

这是一种恶意程序,它的内部是一个不断在fork进程的无限循环,实质是一个简单的

递归程序。由于程序是递归,如果没有任何限制,这会导致这个简单的程序迅速耗尽系

统里的所有资源

:(){:|:&};:

上述含义,:为函数名称,{:|:&}调用函数本身并将其返回值通过管道传递给函数:,然后

后台执行,最后一个:表示调用该函数,由此可见该函数便会形成死循环,此时便会快速

将系统的内存资源耗尽,导致系统无法正常运行

脚本实现

#!/bin/bash

./$0|./$0&


trap信号捕捉

trap '触发指令' 信号

自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行默认操作

trap '' 信号

忽略信号的操作

trap '-' 信号

恢复原信号的操作

trap -p 列出自定义的信号操作



脚本总结

1. 脚本函数必须先定义后使用

2. 脚本运行是开启一个子shell来运行脚本

3. 脚本中的变量是全局变量,生效范围为此脚本运行声名变量直至脚本结束,或遇到撤消

变量结束,函数定义局部变量使用local命令,即生效范围只在函数体内有效



脚本编写


编写函数,实现OS的版本判断

get_OS(){

sed -rn 's/.* ([[:digit:]]+)\..*/\1/p' /etc/centos-release

}

编写函数,实现取出当前系统eth0的IP地址

get_OS(){

    sed -rn 's/.* ([[:digit:]]+)\..*/\1/p' /etc/centos-release

}

get_IP(){

    if ip addr show $1 &>/dev/null; then

        ip addr show $1 | grep -oE '([[:digit:]]{1,3}\.){3}[[:digit:]]{1,3}'|head -n1

    else

        echo 'Error net Interface'

    fi

}

编写函数,实现打印绿色OK和红色FAILED

echo_OKorNO(){

    if [ -n "$1" ] && [[ "$2" =~ [Oo][Kk] ]];then

        echo -e "$1\t\t\t\t\t\033[1;32m[   OK   ]\033[0m"

    elif [ -n "$1" ] && [[ "$2" =~ [Ff][aA][iI][lL][eE][dD] ]];then

        echo -e "$1\t\t\t\t\t\033[1;31m[ FAILED ]\033[0m"

    else

        echo "Usage: echo_OKorNO ServiceName <OK|FAILED>"

    fi

}


编写函数,实现判断是否无位置参数,如无参数,提示错误

test_Args(){

if [ "$#" -eq 0 ];then

echo "Error, No arguments"

return 2

else

echo "Your argument is $*"

return 0

fi

}


编写服务脚本/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_NAME is running...”如果/var/lock/subsys/SCRIPT_NAME文件

不存在, 则显示“SCRIPT_NAME is stopped...”其中:SCRIPT_NAME为当前脚本名

(7)在所有模式下禁止启动该服务,可用chkconfig 和 service命令管理

#!/bin/bash

# chkconfig: 2345 66 15

# description: testSRV is a test service, that do nothing but to 

# to learn how to create a script for Services.


start(){

touch /var/lock/subsys/testSRV &>/dev/null

echo -e "testSRV starting\t\t\t\t\t\033[1;32m[  OK  ]\033[0m"

}

stop(){

rm -f /var/lock/subsys/testSRV &>/dev/null

echo -e "testSRV stopping\t\t\t\t\t\033[1;32m[  OK  ]\033[0m"

}

case $1 in

start)

if [ -f /var/lock/subsys/testSRV ];then

echo "The testSRV has started"

else

start

fi

;;

stop)

if [ -f /var/lock/subsys/testSRV ];then

stop

else

echo "The testSRV has stopped"

fi

;;

restart)

if [ -f /var/lock/subsys/testSRV ];then

stop

start

else

start

fi

;;

status)

if [ -f /var/lock/subsys/testSRV ];then

echo "The testSRV is running"

else

echo "The testSRV is stopped"

fi

;;

*)

echo "Ustarge: service testSRV <start|stop|status>"

;;

esac


编写脚本: 复制命令和命令所调用的模块

(1) 提示用户输入一个可执行命令名称

(2) 获取此命令所依赖到的所有库文件列表

(3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下

如:/bin/bash ==> /mnt/sysroot/bin/bash

/usr/bin/passwd ==> /mnt/sysroot/usr/bin/passwd

(4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下:

/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2

(5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,

并重复完成上述功能;直到用户输入quit退出

#!/bin/bash

# version 2


# Set a root directory

rootDir=/mnt/sysroot


# make a root directory if it is not exist.

[ -d "$rootDir" ] || mkdir $rootDir &> /dev/null


read -p "Please input a COMMAND that you want to copy: " CMD

# Copy Modules

cp_module(){

ldd $(which --skip-alias $CMD)|sed -nr 's@.* (/.*) .*@\1@p'|while 

read lib;do #此行与上一行为同一行内容

libdir=`dirname $lib`

[ -d "${rootDir}$libdir" ] || mkdir ${rootDir}$libdir &> /dev/null

[ -f "${rootDir}$lib" ] || cp -p $lib ${rootDir}$libdir &> /dev/null

done

}


# Copy CMD

cp_cmd(){

if which --skip-alias $CMD &> /dev/null; then

dir=`dirname $(which --skip-alias $CMD)`

cmdPath=$(which --skip-alias $CMD)

[ -d "${rootDir}$dir" ] || mkdir ${rootDir}$dir &> /dev/null

[ -f "${rootDir}$cmdPath" ] || cp -p $cmdPath ${rootDir}$cmdPath &>

/dev/null   #此行与上一行为同一行内容

cp_module

else

echo -e "\033[1;31mError:\033[0m You have input a wrong CMD."

fi

}


until [[ "$CMD" =~ ^([Qq]|quit|QUIT)$ ]];do

cp_cmd

read -p "Please input a COMMAND: " CMD

done



系统启动顺序(CentOS6)

1. POST

2. MBR(grub stage 1)

3. stage 1.5

4. stage 2

5. vmlinuz initramfs 并启动第一个进程init

6. /etc/inittab

7. /etc/rc.d/rc.sysinit

8. /etc/rc#.d

9. /etc/rc.d/rc.local


恢复mbr的bootloader(三个阶段都损坏都可以用以下命令来修复 )

非交互式

grub-install --root-directory= DEVICE

--root-directory=即文件系统的根目录,如未切根

--grub-shell=指定grub程序文件位置

grub交互式

root (hd0,0)

setup (hd0)


grub三个阶段出现损坏时状态现象

mbr损坏时BIOS将无法使用硬盘引导,会直接查找启动所指定的其它启动设备

stage1.5损坏时由于MBR内容没有损坏所以BIOS会认识该设备可以启动,但是由于

stage1.5损坏无法将boot分区文件系统加载导致无法读取/boot目录下文件所以

不会出现grub菜单

stage2损坏时直接启动时会报错error 15,即grub文件被误删除等

grub.conf如果此文件丢失时,系统会直接进入grub交互式界面,因为没有配置所以导致

无法引入配置文件,此时只需要手动指定其boot分区路径以及vmlinuz和initrd便

可启动系统,启动后手工添加此配置文件即可


删除/boot文件夹并修复

1. 恢复vmlinuz文件

使用centOS6的安装光盘,引导进入救援模式,

切根chroot /mnt/sysimage

挂载光盘 mount /dev/cdrom /opt

复制光盘的vmlinux至硬盘/boot分区

cp /opt/isolinux/vmlinuz /boot/vmlinuz-`uname -r`

2. 恢复initrd

执行mkinitrd命令生成initramfs文件

mkinitrd /boot/initramfs-`uname -r` `uname -r`

3. 修复grub_stage2文件

grub-install /dev/sda

4. 手工写配置文件/boot/grub/grub.conf

default 0

timeout 3

title Personal Linux

root (hd0,0)

kernel /vmlinuz-2.6.32-754.el6.x86_64 

root=/dev/mapper/vg_centos6-lv_root #此行与上一行是一行内容

initrd /initramfs-2.6.32-754.el6.x86_64.img

至此修复完成,重新启动即可恢复



ntsysv 一个文本式的图形界面可以提供修改服务脚本开机启动或禁用

--level # 指定修改某个runlevel下的服务开机启动或禁用


chkconfig 用来修改服务的开机启用或禁用

--list 列出当前服务状态

--delete 删除某个服务的条目

--add 添加某个服务的条目