Linux 第43,44天 函數和系統啓動流程詳解

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 添加某個服務的條目


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章