Linux(16):Shell編程(3)

vim 編程環境配置:

.vimrc 文件配置以下:(.vimrc文件放到家目錄下:/root ;而後退出 xshell 再登錄進來xshell)

set nocompatible 
set history=100
filetype on
filetype plugin on
filetype indent on 
set autoread 
set mouse=c
syntax enable 
set cursorline
hi cursorline guibg=#00ff00
hi CursorColumn guibg=#00ff00
set foldenable
set foldmethod=manual
set foldcolumn=0
setlocal foldlevel=3
set foldclose=all           
nnoremap <space> @=((foldclosed(line('.')) < 0) ? 'zc' : 'zo')<CR>
set expandtab
set tabstop=4
set shiftwidth=4
set softtabstop=4
set smarttab
set ai  
set si 
set wrap 
set sw=4        
set wildmenu 
set ruler 
set cmdheight=1 
set lz 
set backspace=eol,start,indent 
set whichwrap+=<,>,h,l 
set magic 
set noerrorbells
set novisualbell
set showmatch 
set mat=4 
set hlsearch
set ignorecase
set encoding=utf-8
set fileencodings=utf-8
set termencoding=utf-8
set smartindent
set cin
set showmatch
set guioptions-=T
set guioptions-=m
set vb t_vb=
set laststatus=4
set pastetoggle=<F9>
set background=dark
highlight Search ctermbg=black  ctermfg=white guifg=white guibg=black
autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()"
func SetTitle()  
    if expand("%:e") == 'sh'  
        call setline(1, "#!/bin/bash")
        call setline(2, "##############################################################")  
        call setline(3, "# File Name: ".expand("%"))
        call setline(4, "# Version: V1.0")
        call setline(5, "# Author: neo")                        # 做者
        call setline(6, "# Organization: anonymous")            # 公司名
        call setline(7, "# Created Time : ".strftime("%F %T"))
        call setline(8, "# Description:")
        call setline(9, "##############################################################")
    endif  
endfunc 

if結構條件句:

# 一、單分支if條件句語法:
if 條件表達式
then 
    指令    
fi

# 二、雙分支if條件句語法:
if 條件表達式
then
    指令
else
    指令
fi
    
# 三、多分支if條件句語法:
if 條件表達式1
then
    指令1
elif 條件表達式2
  then
    指令2
else
    指令3
fi
    
    
# if條件單分支與條件測試編程對比實踐:
# 例1:若是不存在 /backup 目錄就建立
#!/bin/bash
path="/backup"

[ -d $path ] || mkdir /backup -p

if [ -d $path ]
then 
    :        # shell 中 , : 表示什麼都不作
else
    mkdir $path -p
fi 

[ ! -d $path ] && mkdir $path -p

if [ ! -d $path ]
  then
    mkdir $path -p
fi

# 例2:開發shell腳本判斷系統剩餘內存的大小,若是低於 100MB 就提示內存不足,不然提示內存充足
# 分析: 1)提取系統內存   2) if進行判斷
# 獲取內存的命令: free -m 
[root@m01 ~]# free -m
             total       used       free     shared    buffers     cached
Mem:           474        214        259          0         78         33
-/+ buffers/cache:        102        371                                
Swap:          767          0        767
[root@m01 ~]# 

# linux默認把剩餘的內存都看成 buffers/cache 對待,因此上面的 371 就表示剩餘的內存(單位是 MB)
# 取出 剩餘內存371的方法以下:
[root@m01 ~]# free -m|awk 'NR==3{print $4}'
371
[root@m01 ~]# free -m|awk 'NR==3{print $NF}'        # $NF 表示的最後一個Field(列),即輸出最後一個字段的內容
371

# 例題2的示例:
[root@m01 practice]# cat get_memory_size.sh
#!/bin/bash
##############################################################
# File Name: get_memory_size.sh
# Version: V1.0
# Author: neo
# Organization: anonymous
# Created Time : 2019-06-27 23:38:55
# Description:
##############################################################
mem=`free -m|awk 'NR==3{print $NF}'`
if [ $mem -lt 100 ]
then
    echo "memory insufficient"
else
    echo "memory is sufficient"
fi
[root@m01 practice]# bash get_memory_size.sh
memory is sufficient


# 注意: read 讀入沒辦法用 $# 

函數:

函數的概念與做用:java

函數的做用就是將程序裏屢次被調用的相同代碼組合起來(函數體),併爲其取個名字(即函數名),其它全部想重複調用這部分代碼的地方都只
須要調用這個名字就能夠了。當須要修改這部分重複代碼時,也只須要改變函數體內的一部分代碼便可實現全部調用的修改,也能夠把函數獨立寫
到文件裏,當須要調用函數時,再加載進來使用。

# shell函數的優點:
1. 把相同的程序段定義成函數,能夠減小整個程序的代碼量,提高開發效率
2. 增長程序的可讀、易讀性,提高管理效率
3. 能夠實現程序功能模塊化,使得程序具有通用性(可移植性)    

# 對於shell來講,Linux系統裏面的近2000個命令均可以說是shell的函數

函數的語法:

# 語法1:
function 函數名(){
    指令集
    return 返回值
}

# 語法2:
function 函數名 {        # 這種定義方式時, 函數名 和 {  之間必需要有一個空格
    指令集
    return 返回值
}

# 語法3:(推薦)
函數名(){
    指令集
    return 返回值
}

shell函數的執行:linux

帶參數的函數的執行:面試

注意: 上圖中的第3條表示,$0 依然是腳本的名字,而不是函數所在腳本的名字shell

局部變量 和 函數的返回值

[root@m01 func]# cat func_04.sh
#!/bin/bash
##############################################################
# File Name: func_04.sh
# Version: V1.0
# Author: neo
# Organization: anonymous
# Created Time : 2019-06-28 10:25:16
# Description:
##############################################################

function func01(){
    local i="local neo"    # local 變量名 ---> 定義局部變量,該變量只能在函數內部使用
    echo "I am $i"
    return 120             # 函數的返回值
}

echo "local var val:$i"    # 局部變量在函數外部不能被調用 

func01
[root@m01 func]# sh func_04.sh 
local var val:
I am local neo
[root@m01 func]# echo $?    # exit [<n>]    狀態碼n能夠不指定,默認是上一條命令的退出狀態碼。
120
[root@m01 func]# 
    
# 在函數內的變量最好加上 local ,即把函數內的變量定義成 局部變量,避免變量衝突

監控網站URL是否正常的常見方法

# 方法一、 wget 命令:
        --spider            # 模擬爬蟲
        -q                    # 安靜訪問
        -o /dev/null        # 不輸出 
        -T                     # --timeout 超時時間
        -t                    # --tries   重試次數

[root@m01 func]# wget --spider -T 5 -q -o /dev/null -t 2 www.baidu.com
[root@m01 func]# echo $?          # 經過 echo $? 檢測 wget 的URL是否正常
0
[root@m01 func]# 

# 方法二、 curl 命令:
            -I                        # 看響應頭
            -s                        # 安靜訪問
            -o /dev/null            # 不輸出
            -w %{http_code}            # 返回狀態碼;200爲正常
            -m01                    # 超時時間
[root@m01 func]# curl www.baidu.com -s &>/dev/null 
[root@m01 func]# echo $?    # 也是經過查看 curl 的執行結果來判斷 URL 是否正常
0
[root@m01 func]# curl -I -m 5 -s -w "%{http_code}\n" -o /dev/null www.baidu.com
200                            # 也可經過查看 狀態碼 查看 URL 是否正常

# 示例代碼:
[root@m01 func]# cat checkurl.sh 
#!/bin/bash
##############################################################
# File Name: checkurl.sh
# Version: V1.0
# Author: neo
# Organization: anonymous
# Created Time : 2019-06-29 09:19:34
# Description:
##############################################################
function usage(){           # 輸入有誤時的函數
    echo "Usage:$0 url"
    exit 1
}

function checkurl(){        # 檢測網站是否正常的函數 
    wget -q -o /dev/null -t 2 -T 5 $1
    if [ $? -eq 0 ]
    then
        echo "$1 is ok"
    else
        echo "$1 failed"
    fi
}

function main(){            # 至關於 入口函數
    if [ $# -ne 1 ]
    then
        usage               # 若是輸入的參數個數不爲1,則調用 usage 函數
    fi

    checkurl $1             # 調用檢測url的函數   
}

main $*                     # $* :把全部的參數都傳給 main 函數
[root@m01 func]# sh checkurl.sh 
Usage:checkurl.sh url
[root@m01 func]# sh checkurl.sh www.baidu.com 2
Usage:checkurl.sh url
[root@m01 func]# sh checkurl.sh www.baidu.com 
www.baidu.com is ok

case 條件句

case結構條件句至關於多分支的 if/elif/else 條件句,可是它比這些條件句看起來更規範工整,常被用於實現系統服務啓動腳本等企業應用場景中。
# case語句的語法:
case "變量" in 
    值1)
        指令1...
        ;;
    值2)
        指令2...
        ;;
    值3)
        指令3...
        ;;
    *)
        指令4...
esac

# 示例代碼:
[root@m01 func]# cat case01.sh 
#!/bin/bash

cat <<EOF
    1. install lamp
    2. install lnmp
    3. exit
EOF

read -p "pls input an integer from above:" num

# 1. 判斷是否爲數字
expr 2 + $num &>/dev/null
if [ $? -ne 0 ]
then
    echo "Usage:$0 {1|2|3}"
    exit 1
fi

# 判斷執行處理
case $num in
    1)
        echo "install lamp..."
        ;;
    2)
        echo "install lnmp..."
        ;;
    3)
        echo "bye"
        exit 
        ;;
    *)
        echo "Uage:$0 {1|2|3}"
        exit 1
esac
[root@m01 func]# sh case01.sh 
    1. install lamp
    2. install lnmp
    3. exit
pls input an integer from above:1
install lamp...
[root@m01 func]# sh case01.sh 
    1. install lamp
    2. install lnmp
    3. exit
pls input an integer from above:3
bye
[root@m01 func]# sh case01.sh 
    1. install lamp
    2. install lnmp
    3. exit
pls input an integer from above:6
Uage:case01.sh {1|2|3}

示例1:給不一樣內容加不一樣的顏色編程

[root@m01 func]# cat case02.sh
#!/bin/bash
##############################################################
# File Name: case02.sh
# Version: V1.0
# Author: neo
# Organization: anonymous
# Created Time : 2019-06-30 23:38:25
# Description:
##############################################################
red="\033[31m"
green="\033[32m"
yellow="\033[33m"
blue="\033[34m"
tail="\033[0m"

function color(){
case $1 in
    red)
        echo -e "${red}$2${tail}"
        ;;
    green)
        echo -e "${green}$2${tail}"
        ;;
    yellow)
        echo -e "${blue}$2${tail}"
        ;;
    blue)
        echo -e "${blue}$2${tail}"
        ;;
    *)
        echo {Usage:$0 colorfunction color char}
        exit 1
esac
}

cat <<EOF
1.apple
2.pear
3.banana
4.cherry
EOF

read -p "pls input a number:" num

case $num in
    1)
        color red apple
        ;;
    2)
        color green pear
        ;;
    3)
        color yellow banana
        ;;
    4)
        color blue cherry
        ;;
    *)
        echo "Usage:$0 {1|2|3|4}"
        exit 1
esac
[root@m01 func]# sh case02.sh
1.apple
2.pear
3.banana
4.cherry
pls input a number:1
apple
[root@m01 func]#

示例2:開發網絡服務rsync服務的啓動腳本實踐vim

利用case語句開發Rsync服務啓動中止腳本,本例採用case語句以及新的思路來實現。數組

# 分析:
    1. 啓動命令: rsync --daemon
    2. 中止進程: pkill rsync
                  killall rsync
                  kill 進程號     # 推薦這種方式


[root@m01 ~]# rsync --daemon
Failed to parse config file: /etc/rsyncd.conf        # 這臺主機上沒有 rsync 環境
[root@m01 ~]# touch /etc/rsyncd.conf                # 建立一個 rsyncd.conf 的空文件,就能建立一個最簡單的 rsync 環境,此時 rsync 就能啓動
[root@m01 ~]# rsync --daemon
[root@m01 ~]# 
[root@m01 ~]# lsof -i:873
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rsync   15961 root    4u  IPv4  89573      0t0  TCP *:rsync (LISTEN)        # rsync 已經啓動
rsync   15961 root    5u  IPv6  89574      0t0  TCP *:rsync (LISTEN)
[root@m01 ~]# pkill rsync
[root@m01 ~]# lsof -i:873
[root@m01 ~]# rsync --daemon
[root@m01 ~]# killall rsync
[root@m01 ~]# lsof -i:873
[root@m01 ~]# rsync --daemon
[root@m01 ~]# lsof -i:873
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rsync   16068 root    4u  IPv4  90215      0t0  TCP *:rsync (LISTEN)
rsync   16068 root    5u  IPv6  90216      0t0  TCP *:rsync (LISTEN)
[root@m01 ~]# kill 16068
[root@m01 ~]# lsof -i:873
[root@m01 ~]# 

示例代碼1:基本的 rsync 啓動腳本bash

[root@m01 func]# cat rsyncd.sh 
#!/bin/bash
##############################################################
# File Name: rsyncd.sh
# Version: V1.0
# Author: neo
# Organization: anonymous
# Created Time : 2019-07-01 23:34:57
# Description:
##############################################################

case "$1" in 
    start)
        rsync --daemon
        if [ $? -eq 0 ]
        then
            echo "rsync startup ok"
        else
            echo "rsync startup failed"
        fi
        ;;
    stop)
        killall rsync
        if [ $? -eq 0 ]
        then
            echo "rsync stop ok"
        else
            echo "rsync stop failed"
        fi
        ;;
    restart)
        killall rsync && sleep 1 && rsync --daemon       # sleep 1  ---> 中止1秒 (注意:重啓中間要停一下)
        if [ $? -eq 0 ]
        then
            echo "rsync restart ok"
        else
            echo "rsync restart failed"
        fi
        ;;
    *)
        echo "Usage:$0 {start|stop|restart}"
        exit 1
esac
[root@m01 func]# bash rsyncd.sh start
rsync startup ok
[root@m01 func]# lsof -i:873
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rsync   16228 root    4u  IPv4  91096      0t0  TCP *:rsync (LISTEN)
rsync   16228 root    5u  IPv6  91097      0t0  TCP *:rsync (LISTEN)
[root@m01 func]# bash rsyncd.sh stop
rsync stop ok
[root@m01 func]# lsof -i:873
[root@m01 func]# bash rsyncd.sh start
rsync startup ok
[root@m01 func]# lsof -i:873
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rsync   16259 root    4u  IPv4  91271      0t0  TCP *:rsync (LISTEN)
rsync   16259 root    5u  IPv6  91272      0t0  TCP *:rsync (LISTEN)
[root@m01 func]# bash rsyncd.sh restart
rsync restart ok
[root@m01 func]# lsof -i:873
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rsync   16265 root    4u  IPv4  91312      0t0  TCP *:rsync (LISTEN)        # 重啓以後 進程號發生了改變
rsync   16265 root    5u  IPv6  91313      0t0  TCP *:rsync (LISTEN)
[root@m01 func]# 

示例代碼2:完善實用的 rsync 啓動腳本網絡

[root@m01 func]# cp rsyncd.sh rsyncd2.sh         # 作備份
[root@m01 func]# cat rsyncd2.sh
#!/bin/bash
# chkconfig: 2345 20 80                                                                                                  
# description: rsync start and stop script 

# 上面兩行的做用是讓腳本開機自啓動 (這兩行必須寫在腳本開頭)

##############################################################
# File Name: rsyncd.sh
# Version: V1.0
# Author: neo
# Organization: anonymous
# Created Time : 2019-07-01 23:34:57
# Description:
##############################################################

function start(){
    rsync --daemon
    retval=$?                       # 獲取上一條命令的執行結果做爲返回值; 外部須要調用這個 retval ,因此定義成全局變量
    if [ $retval -eq 0 ]
    then
        echo "rsync startup ok"
        return $retval                    # 專業的腳本函數須要給 返回值
    else
        echo "rsync startup failed"
        return $retval
    fi
}

function stop(){
    killall rsync
    retval=$?
    if [ $retval -eq 0 ]
    then
        echo "rsync stop ok"
        return $retval
    else
        echo "rsync stop failed"
        return $retval
    fi
}

case "$1" in 
    start)
        start
        retval=$?               # 接收 start 的執行結果並賦值給 retval 做爲返回值
        ;;
    stop)
        stop
        retval=$?
        ;;
    restart)
        stop && sleep 1 && start
        retval=$?
        ;;
    *)
        echo "Usage:$0 {start|stop|restart}"
        exit 1
esac
exit $retval                    # 把上面的執行結果返回給腳本外面
[root@m01 func]# lsof -i:873
[root@m01 func]# sh rsyncd2.sh start
rsync startup ok
[root@m01 func]# lsof -i:873
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rsync   16731 root    4u  IPv4  93672      0t0  TCP *:rsync (LISTEN)
rsync   16731 root    5u  IPv6  93673      0t0  TCP *:rsync (LISTEN)
[root@m01 func]# sh rsyncd2.sh restart
rsync stop ok
rsync startup ok
[root@m01 func]# lsof -i:873
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rsync   16737 root    4u  IPv4  93713      0t0  TCP *:rsync (LISTEN)        # 重啓以後 pid 發生了變化
rsync   16737 root    5u  IPv6  93714      0t0  TCP *:rsync (LISTEN)
[root@m01 func]# sh rsyncd2.sh stop
rsync stop ok
[root@m01 func]# sh rsyncd2.sh restart
rsync: no process killed
rsync stop failed
[root@m01 func]# echo $?
1
[root@m01 func]# 
[root@m01 func]# cp rsyncd2.sh /etc/init.d/rsyncd
[root@m01 func]# chmod +x /etc/init.d/rsyncd                    # 加上執行權限
[root@m01 func]# chkconfig --list rsyncd                        # 此時 rsync服務 沒在開機啓動管理裏面
service rsyncd supports chkconfig, but is not referenced in any runlevel (run 'chkconfig --add rsyncd')
[root@m01 func]# chkconfig --add rsyncd                            # 把 rsyncd 服務添加到開機啓動管理裏面
[root@m01 func]# chkconfig --list rsyncd
rsyncd             0:off    1:off    2:on    3:on    4:on    5:on    6:off        # 此時 rsyncd 在2345級別開機自啓動
[root@m01 func]#

# 加載系統函數庫作輸出提示
[root@m01 func]# cp /etc/init.d/rsyncd{,.1}        # 作備份
[root@m01 func]# cat /etc/init.d/rsyncd
#!/bin/bash
# chkconfig: 2345 20 80
# description: rsync start and stop script
##############################################################
# File Name: rsyncd.sh
# Version: V1.0
# Author: neo
# Organization: anonymous
# Created Time : 2019-07-01 23:34:57
# Description:
##############################################################
. /etc/init.d/functions     # 調用系統函數庫(用於輸出提示)
function start(){
    rsync --daemon
    retval=$?                       # 獲取上一條命令的執行結果做爲返回值; 外部須要調用這個 retval ,因此定義成全局變量
    if [ $retval -eq 0 ]
    then
        action "rsync startup ok" /bin/true    # 用於輸出提示
        return $retval                    # 專業的腳本函數須要給 返回值
    else
        action "rsync startup failed" /bin/false
        return $retval
    fi
}

function stop(){
    killall rsync &>/dev/null       # &>/dev/null   不要輸出(只看返回值)
    retval=$?
    if [ $retval -eq 0 ]
    then
        action "rsync stop ok" /bin/true
        return $retval
    else
        action "rsync stop failed" /bin/false
        return $retval
    fi
}

case "$1" in 
    start)
        start
        retval=$?               # 接收 start 的執行結果並賦值給 retval 做爲返回值
        ;;
    stop)
        stop
        retval=$?
        ;;
    restart)
        stop && sleep 1 && start
        retval=$?
        ;;
    *)
        echo "Usage:$0 {start|stop|restart}"
        exit 1
esac
exit $retval                    # 把上面的執行結果返回給腳本外面
[root@m01 func]# 
[root@m01 func]# lsof -i:873
[root@m01 func]# /etc/init.d/rsyncd start
rsync startup ok                                           [  OK  ]
[root@m01 func]# /etc/init.d/rsyncd restart
rsync stop ok                                              [  OK  ]
rsync startup ok                                           [  OK  ]
[root@m01 func]# /etc/init.d/rsyncd stop
rsync stop ok                                              [  OK  ]
[root@m01 func]# /etc/init.d/rsyncd restart
rsync stop failed                                          [FAILED]
[root@m01 func]#

示例代碼3:和系統腳本相似的 rsync 啓動腳本app

# 分析:
    1. 系統腳本啓動的時候一般會定義一個鎖文件 lockfile,當系統啓動時建立一個鎖文件(能夠一般查看有沒有這個鎖文件來判斷服務有沒有成功)
    2. 當服務中止成功時,兩把鎖文件刪除
    
[root@m01 func]# cp /etc/init.d/rsyncd{,.2}        # 先備份
[root@m01 subsys]# cat /etc/rsyncd.conf            # 在 rsyncd.conf 文件中定義一個獲取 rsync服務 進程號 pid 的文件
pid file = /var/run/rsyncd.pid              
[root@m01 subsys]# rsync --daemon
[root@m01 subsys]# cat /var/run/rsyncd.pid        # 在 rsyncd.conf 中添加了 pid file 以後,啓動  rsync 服務以後,pid file 中就會保存 rsync 服務的 pid
18082
[root@m01 func]# cat /etc/init.d/rsyncd
#!/bin/bash
# chkconfig: 2345 20 80
# description: rsync start and stop script
##############################################################
# File Name: rsyncd.sh
# Version: V1.0
# Author: neo
# Organization: anonymous
# Created Time : 2019-07-01 23:34:57
# Description:
##############################################################
lockfile=/var/lock/subsys/rsync                 # 先定義一個鎖文件
rsyncd_pid_file_path="/var/run/rsyncd.pid"      # 定義 rsync 進程號的路徑

. /etc/init.d/functions     

function start(){
    rsync --daemon &>/dev/null      
    retval=$?                       
    if [ $retval -eq 0 ]
    then
        action "rsync startup ok" /bin/true    
        touch $lockfile                        # 啓動成功後,就建立一個鎖文件
        return $retval                    
    else
        action "rsync startup failed" /bin/false
        return $retval
    fi
}

function stop(){
    if test -s $rsyncd_pid_file_path                    # -s ---> 判斷文件是否存在且不爲空
    then
        rsyncd_pid=`cat $rsyncd_pid_file_path`
        if (kill -0 $rsyncd_pid &>/dev/null)      # kill -0 進程號  ---> 判斷該進程號對應的服務是否存在;存在則echo $?返回0,不存在返1
        then
            kill $rsyncd_pid 
            retval=$?
            if [ $retval -eq 0 ]
            then
                action "rsync stop ok" /bin/true
                \rm -f $lockfile           # 中止成功後就刪除鎖文件
                return $retval
            else
                action "rsync stop failed" /bin/false
                return $retval
            fi

        else        # 此種狀況是:$rsyncd_pid 對應的 rsyncd 服務不存在
            action "rsyncd service is not running" 
            return 2
        fi
            
    else    # 此種狀況是: $rsyncd_pid_file_path 對應的路徑不存在 
        action "$rsyncd_pid_file_path not exist, or rsyncd not startup" /bin/false
        return 3
    fi
}

case "$1" in 
    start)
        start
        retval=$?               # 接收 start 的執行結果並賦值給 retval 做爲返回值
        ;;
    stop)
        stop
        retval=$?
        ;;
    restart)
        stop && sleep 1 && start
        retval=$?
        ;;
    *)
        echo "Usage:$0 {start|stop|restart}"
        exit 1
esac
exit $retval                    # 把上面的執行結果返回給腳本外面
[root@m01 subsys]# lsof -i:873
[root@m01 func]# /etc/init.d/rsyncd stop
/var/run/rsyncd.pid not exist, or rsyncd not startup       [FAILED]
[root@m01 func]# /etc/init.d/rsyncd restart
/var/run/rsyncd.pid not exist, or rsyncd not startup       [FAILED]
[root@m01 func]# /etc/init.d/rsyncd start
rsync startup ok                                           [  OK  ]
[root@m01 func]# lsof -i:873
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rsync   18740 root    4u  IPv4 102100      0t0  TCP *:rsync (LISTEN)
rsync   18740 root    5u  IPv6 102101      0t0  TCP *:rsync (LISTEN)
[root@m01 func]# /etc/init.d/rsyncd restart
rsync stop ok                                              [  OK  ]
rsync startup ok                                           [  OK  ]
[root@m01 func]# lsof -i:873
COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
rsync   18764 root    4u  IPv4 102183      0t0  TCP *:rsync (LISTEN)
rsync   18764 root    5u  IPv6 102184      0t0  TCP *:rsync (LISTEN)
[root@m01 func]# /etc/init.d/rsyncd stop
rsync stop ok                                              [  OK  ]
[root@m01 func]# 

case條件句使用總結:

while 循環語句

# while 循環的語法:
while 條件表達式
do
    指令...
done

# 示例1:每隔2秒輸出一次系統負載(負載是系統性能的基礎重要指標)狀況
[root@m01 loop]# cat loop01.sh
while true
do
    uptime >>/tmp/uptime.log
    sleep 2
done


# 後臺運行的命令: & 、nohup 、screen (運維人員經常使用) 
常見命令:
kill killall pkill    ---> 殺掉進程
ps                    ---> 查看進程
pstree                ---> 顯示進程狀態樹
top                    ---> 顯示進程
renice                ---> 改變優先權
nohup                ---> 用戶退出系統以後繼續工做(後臺運行)
pgrep                ---> 查找匹配條件的進程
strace                ---> 跟蹤一個進程的系統調用狀況
ltrace                ---> 跟蹤進程調用庫函數的狀況

while循環可能會涉及到的一些命令:

示例2:使用while循環對下面的腳本進行修改,使得當執行腳本時,每次執行完腳本之後不退出腳本了,而是繼續提示用戶輸入。

[root@m01 loop]# cat loop02.sh
while true
do
    read -p "pls input two numbers:" a b

    if [ -z "$b" ]
    then
        echo "pls input two numbers:"
        continue        # continue 表示結束本次循環
    fi
    expr 10 + $a + $b &>/dev/null
    if [ $? -ne 0 ]
    then
        echo "pls input two numbers:"
        continue
    fi

    echo "a-b=$(($a-$b))"
    echo "a+b=$(($a+$b))"
    echo "a*b=$(($a*$b))"
    echo "a/b=$(($a/$b))"
    echo "a**b=$(($a**$b))"
    echo "a%b=$(($a%$b))"
done
[root@m01 loop]# 

示例3:猜數字遊戲:首先讓系統隨機生成一個數字,給這個數字定一個範圍(1-60),讓用戶輸入猜的數字,對輸入進行判斷,若是不符合要求,就給予高或低的提示,猜對後則給出猜對用的次數,用while語句實現。

# 分析:
    1. 隨機數 ---> $RANDOM    # $RANDOM 隨機數的範圍: 0~32767
        [root@m01 loop]# echo $RANDOM
        15258
        [root@m01 loop]# echo $(($RANDOM%60))        # 取 0~60 之間的隨機數
        10

[root@m01 loop]# cat loop03.sh
#!/bin/bash
##############################################################
# File Name: loop03.sh
# Version: V1.0
# Author: neo
# Organization: anonymous
# Created Time : 2019-07-02 23:18:45
# Description:
##############################################################
val="$((RANDOM%60))"
count=0

while true
do
    read -p "pls input one number:" num
    ((count++))
    if [ -z "$num" ]
    then
        read -p "pls input one number:" num
        continue
    fi
    expr 10 + $num &>/dev/null
    if [ $? -ne 0 ]
    then
        read -p "pls input one number:" num
        continue
    fi

    if [ $val -gt $num ]
    then
        echo "try bigger"
    elif [ $val -lt $num ]
    then
        echo "try smaller"
    else
        echo "guess right"
        echo "count:$count"
        exit
    fi
done
[root@m01 loop]# 

示例4: 分析Apache訪問日誌(access_2010-12-8.log),把日誌中每行的訪問字節數對應字段數字相加,計算出總的訪問量。給出實現程序,用while循環實現。

# while 循環讀取文件有3種方式(經常使用下面的前2種方式):
# 方式1:在while循環結尾done經過輸入重定向指定讀取的文件。
while read line        # 讀取文件內容時,是從文件由上到下讀取
do
    cmd        # 對 line 進行處理
done<FILE

# 方式2:使用cat讀取文件內容,而後經過管道進入while循環處理。
cat FILE_PATH|while read line
do
    cmd
done

# 方式3:採用exec讀取文件後,而後進入while循環處理。
exec <FILE
sum=0
while read line
do
    cmd
done

# 讀取文件內容示例
[root@m01 ~]# seq 10 >neo.log
[root@m01 ~]# cat neo.log 
1
2
3
4
5
6
7
8
9
10
[root@m01 loop]# vim while-read-from-file.sh
while read line
do
    echo "$line"
done</root/neo.log 
[root@m01 loop]# sh while-read-from-file.sh 
1
2
3
4
5
6
7
8
9
10

# 示例代碼以下:
[root@m01 loop]# cat loop04.sh
#!/bin/bash
awk '{print $10}' /root/access_2010-12-8.log|grep -v -  >/tmp/count_bytes.log
num=0

while read line
do
    ((num+=line))
done</tmp/count_bytes.log

echo $num
[root@m01 loop]# 

while循環涉及的一些命令:

for 循環語句

for循環語句和 while 循環語句相似,但 for 循環語句主要用於執行次數有限的循環,而不是用於守護進程以及無限循環。for 循環語句常見的語法有兩種
# for循環的語法:
1)普通語法
for 變量名 in 變量取值列表
do
    指令...
done

2)C語言型for循環語法
for((exp1;exp2;exp3))
do
    指令...
done

# 示例1:經過開發腳本實現僅設置 sshd rsyslog crond network sysstat  服務開機自啓動
[root@m01 loop]# cat for01.sh
#!/bin/bash
for service in `chkconfig |awk '!/crond|network|rsyslog|sshd|sysstat/{print $1}'`
do
    chkconfig $service off
done
[root@m01 loop]# 

# 示例2:計算從1加到100之和
[root@m01 loop]# cat for02.sh
#!/bin/bash
for ((i=1;i<=100;i++))      # C語言型的 for 循環
do
    ((sum+=i))
done

echo $sum

echo ===================================

for n in {1..100}
do
    ((total+=n))
done

echo $total
echo ===================================

for n in `seq 100`
do
    ((amount+=n))
done
echo $amount
echo ==================================

while ((j<=100))
do
    ((vol+=j))
    ((j++))
done

echo $vol
[root@m01 loop]# echo $((100*(100+1)/2))
5050
[root@m01 loop]# 


# 示例3:在Linux下批量修改文件名,將文件名中的「_finished」去掉。
# 準備測試數據:
mkdir /neo -p
cd /neo
touch stu_102999_1_finished.jpg stu_102999_2_finished.jpg stu_102999_3_finished.jpg 
touch stu_102999_4_finished.jpg stu_102999_5_finished.jpg
ls -l

# 以下:
[root@m01 ~]# mkdir /neo -p
[root@m01 ~]# cd /neo
[root@m01 neo]# touch stu_102999_1_finished.jpg stu_102999_2_finished.jpg stu_102999_3_finished.jpg 
[root@m01 neo]# touch stu_102999_4_finished.jpg stu_102999_5_finished.jpg
[root@m01 neo]# ls -l
total 0
-rw-r--r-- 1 root root 0 Jul  3 12:06 stu_102999_1_finished.jpg
-rw-r--r-- 1 root root 0 Jul  3 12:06 stu_102999_2_finished.jpg
-rw-r--r-- 1 root root 0 Jul  3 12:06 stu_102999_3_finished.jpg
-rw-r--r-- 1 root root 0 Jul  3 12:06 stu_102999_4_finished.jpg
-rw-r--r-- 1 root root 0 Jul  3 12:06 stu_102999_5_finished.jpg


# for循環腳本:
[root@m01 loop]# cat loop05.sh
#!/bin/bash
file_path="/neo/*.jpg"
for file in `ls $file_path`
do
    mv $file ${file/_finished/}
done

# awk 操做
[root@m01 neo]# ls *.jpg|awk -F "_finished" '{print "mv",$0,$1$2}'|sh
[root@m01 neo]# ll
total 0
-rw-r--r-- 1 root root 0 Jul  3 14:19 stu_102999_1.jpg
-rw-r--r-- 1 root root 0 Jul  3 14:19 stu_102999_2.jpg
-rw-r--r-- 1 root root 0 Jul  3 14:19 stu_102999_3.jpg
-rw-r--r-- 1 root root 0 Jul  3 14:19 stu_102999_4.jpg
-rw-r--r-- 1 root root 0 Jul  3 14:19 stu_102999_5.jpg
[root@m01 neo]# 

# rename 操做
# rename語法: rename [from] [to] file

[root@m01 neo]# rename _finished "" *.jpg                # 把文件名中的 "_finished" 改成 空
[root@m01 neo]# ll
total 0
-rw-r--r-- 1 root root 0 Jul  3 14:19 stu_102999_1.jpg
-rw-r--r-- 1 root root 0 Jul  3 14:19 stu_102999_2.jpg
-rw-r--r-- 1 root root 0 Jul  3 14:19 stu_102999_3.jpg
-rw-r--r-- 1 root root 0 Jul  3 14:19 stu_102999_4.jpg
-rw-r--r-- 1 root root 0 Jul  3 14:19 stu_102999_5.jpg
[root@m01 neo]#

條件與循環控制及程序返回值相關知識點:

shell編程數組語法及應用實踐

數組的概念:

數組也是一個變量;Shell的數組就是把有限個元素(變量或字符內容)用一個名字命名,而後用編號對它們進行區分的元素集合。
這個名字就稱爲數組名,用於區分不一樣內容的編號就稱爲數組下標。組成數組的各個元素(變量)稱爲數組的元素,有時也稱爲下標變量。

# 數組的本質仍是變量,是特殊的變量形式,如: array=(1 2 3 4 5)

數組的定義方式:

# 方法1:推薦
array=(one two three four)

# 方法2:
array=([0]=one [1]=two [2]=three [3]=four)

# 方法3:
[root@m01 ~]# array[0]=one
[root@m01 ~]# array[1]=2
[root@m01 ~]# array[2]=3
[root@m01 ~]# echo ${array[@]}
one 2 3
[root@m01 ~]# echo ${array[*]}        # 獲取全部的數組元素
one 2 3
[root@m01 ~]# 

方法4:命令的結果放到數組裏,推薦。
array=(`ls /server/scripts`)

# 操做數組元素
# 讀取數組內容 ***
[root@m01 ~]# array=(1 2 3)
[root@m01 ~]# echo ${array[0]}
1
[root@m01 ~]# echo ${array[*]}
1 2 3
[root@m01 ~]# echo ${array[@]}
1 2 3
[root@m01 ~]# echo ${#array[@]}        # 數組的長度
3
[root@m01 ~]# echo ${array[4]}

[root@m01 ~]# 

# 給數組添加內容
[root@m01 ~]# array[3]=neo
[root@m01 ~]# echo ${array[*]}
1 2 3 neo
[root@m01 ~]# array[3]=four            # 會把數組的元素覆蓋
[root@m01 ~]# echo ${array[*]}
1 2 3 four                            # 會把數組的元素覆蓋
[root@m01 ~]# 

# 刪除數組內容
[root@m01 ~]# unset array[1]        # 刪除數組下標爲1的數組元素
[root@m01 ~]# echo ${array[*]}
1 3 four
[root@m01 ~]# echo ${array[2]}
3
[root@m01 ~]# 

# for循環數組:
[root@m01 loop]# cat array_for.sh
#!/bin/bash
array=(1 2 3 4 5)
for n in ${array[*]}
do
    echo $n
done

echo =======================

for ((i=0;i<${#array[*]};i++))     # C語言型的for 循環數組;數組的下標從0開始
do
    echo ${array[i]}               # i 是下標
done
[root@m01 loop]# sh array_for.sh
1
2
3
4
5
=======================
1
2
3
4
5
[root@m01 loop]# 

Shell數組的重要命令:

# (1)定義命令
靜態數組:
array=(1 2 3)

動態數組:
array=($(ls))  或  array=(`ls`)

給數組賦值:
array[3]=42)打印命令
打印全部元素:
${array[@]}  或  ${array[*]}

打印數組長度:
${#array[@]}或${#array[*]}

打印單個元素:
${array[i]}                  #<==i是數組下標

企業實踐:利用bash for循環打印下面這句話中字母數不大於6的單詞(某企業面試真題)。
I am oldboy teacher welcome to oldboy training class

[root@m01 loop]# cat loop06.sh
#!/bin/bash
array=(I am oldboy teacher welcome to oldboy training class)

for word in ${array[*]}
do
    if [ ${#word} -le 6 ]
    then
        echo ${word}
    fi
done

echo ===================

for ((i=0;i<${#array[*]};i++))
do
    if [ ${#array[i]} -le 6 ]
    then
        echo ${array[i]}
    fi
done   
[root@m01 loop]# sh loop06.sh
I
am
oldboy
to
oldboy
class
===================
I
am
oldboy
to
oldboy
class
[root@m01 loop]#
相關文章
相關標籤/搜索