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