shell腳本進階

一、流程控制

過程式編程語言:順序執行、選擇執行、循環執行

1.1 條件語句

1.1.1 if條件選擇語句

 選擇執行: (注意: if 語句可嵌套)

v  單分支:if  判斷條件;then

          條件為真的分支代碼

            fi

v 雙分支:if  判斷條件; then

           條件為真的分支代碼

           else

           條件為假的分支代碼

           fi

v 多分支: if  判斷 條件 1 ; then

                if-true

           elif  判斷 條件 2 ; then

                if-ture

           elif  判斷 條件 3 ; then

                if-ture

                …

               else

               all-false

           fi

v  逐條 件進行判斷,第一次遇為“真”條件時,執行其分支,而后結束整個if 語句

1.1.2 if 實例

v       根據命令的退出狀態來執行命令

if ping -c1 -W2 station1 &> /dev/null; then

echo 'Station1 is UP'

elif grep "station1" ~/maintenance.txt &> /dev/null;then

echo 'Station1 is undergoing maintenance

else

echo 'Station1 is unexpectedly DOWN!'

exit 1

fi

1.1.3 case條件判斷

適合于離散值的匹配;如:value 1,35 cmd1;value 24,6 cmd2…   read p please input a number  value

case  變量引用($)  in                如:case  $value  in  

PAT1)                 1|3|5)

分支1                 echo a

        ;;                  ;;

PAT2)                 2|4|6)

分支2                 echo b

;;                  ;;

*)                  *)

默認分支                 echo d

;;                  ;;

esac                  esac

case 支持glob 風格的通配符:

*:  任意長度任意字符  ;  ?:  任意單個字符  ;  [] :指定范圍內的任意單個字符  ;  a|b: a b

1.1.4 練習

1 、編寫腳本/root/bin/createuser.sh ,實現如下功能:使用一個用戶名做為參數,如果指定參數的用戶存在,就顯示其存在,否則添加之;顯示添加的用戶的id 號等信息

   read -p "please give me a user:" u

   useradd $u &> /dev/null

  if [ $? -eq 0 ];then

      echo "user $u is already added sucessfully"  ;  id $u

  else

      echo "user is exit"

   fi

2、編寫腳本/root/bin/yesorno.sh ,提示用戶輸入yes no,并判斷用戶輸入的是yes 還是no, 或是其它信息

   read -p "please input yes or no:" i

   case $i in

  [yY]|[yY][eE][sS])

      echo yes

      ;;

  [nN]|[nN][oO])

      echo no

      ;;

  *)

      echo your answer is wrong

      ;;

  esac

3 、編寫腳本/root/bin/filetype.sh, 判斷用戶輸入文件路徑,顯示其文件類型(普通,目錄,鏈接,其它文件類型)

  for file in $D

  do

      if [ -L $file ];then

          echo -e "\033[32m$file\033[0m is a link file"

      elif [ ! -L $file -a -d $file ];then

          echo -e "\033[34m$file\033[0m is a directory"

      elif [ ! -L $file -a -f $file ];then

          echo -e "\033[37m$file\033[0m is a normal file"

      elif [ ! -L $file -a -c $file ];then

          echo -e "\033[47;33m$file\033[0m is a character device file"

      elif [ ! -L $file -a -b $file ];then

          echo -e "\033[33m$file\033[0m is a block device file"

      elif [ ! -L $file -a -p $file ];then

          echo -e "\033[35m$file\033[0m is a pipe file"

      elif [ ! -L $file -a -s $file ];then

          echo -e "\033[31m$file\033[0m is a socket file"

      else

          echo -e "\033[47;30mIt's not a directory\033[0m"

      fi

  done

4 、編寫腳本/root/bin/checkint.sh, 判斷用戶輸入的參數是否為正整數。

  read -p "please input a number:" n

  [ -z $n ] && echo "please input a int" && exit 123

  num=`echo $n | egrep -o "\-?[[:digit:]]+"` #\-? 判斷是否出現\為轉義符號

 if [ "$num" == "$n" ];then

      if [ "$num" -le 0 ];then

          echo your input is a negative integer   #負整數

      elif [ "$num" == 0 ];then

          echo your input is zero                 #0

      else

          echo your input is positive integer     #正整數

      fi

 else

      echo your input is not a integer            #不是一個整數

 fi

1.2 循環語句

循環執行:將某代碼段重復運行多次

重復運行多少次:循環次數事先已知;循環次數事先未知

有進入條件和退出條件:for, while, until

1.2.1 for循環

for  變量名  in 列表;do

循環體

done

執行機制

依次將列表中的元素賦值給“變量名”;  每次賦值后即執行一次循環體;  直到列表中的元素耗盡,循環結束

列表生成方式:

(1)  直接給出列表

(2)  整數列表:(a) {start..end}  ; (b) $(seq [start [step]] end)  如:seq 1 10 表示1-10列表豎行顯示

             (適用于數值運算)        seq 0 2 10 表示顯示0 2 4 6 8 102為步長

(3)  返回列表的命令:$(COMMAND)

(4)  使用glob, 如:*.sh

(5)  變量引用;$@, $*

1.2.2 for練習

v 1、判斷/var/ 目錄下所有文件的類型

v 2、 添加10個用戶user1-user10 ,密碼為8 位隨機字符

  read -p "how many users do you want to add: " N

  #1-$N中所有數據添加

 for j in $(seq 1 $N)

  do

  #添加用戶,但不顯示過程

      useradd user$j &> /dev/null

  #取隨機8位數,作為用戶的密碼

      cat /dev/urandom |tr -dc "[^[:alnum:]]"|head -c 8|passwd user$j &> /dev/null

  done

v 3、/etc/rc.d/rc3.d 目錄下分別有多個以K 開頭和以S 開頭的文件 ;分別 讀取每個文件,以K 開頭的文件輸出為文件加stop,以S 開頭的文件輸出為文件名加start

K34filename stop”  “S66filename start

  for j in $(ls -1 /etc/rc.d/rc3.d/);do

      if [[ $j =~ ^S.* ]];then           FileC1=`echo $j | cut -c1`

          echo -e "$j\tstart"   case $FileC1 in

      elif [[ $j =~ ^K.* ]];then   K)

          echo -e "$j\tstop"    echo -e $j\tstop

      else         ;;

          echo "it's not service file"

      fi

   done

v 4、編寫腳本 ,提示輸入正整數n 的值,計算1+2++n 的總和

  read -p "give me a number:" n

  sum=0

  for((i=0;i<=$n;i++))

  do

     sum=$[$sum+$i]

  done

  echo $sum

v 5、編寫腳本 ,提示請輸入網絡地址,如192.168.0.0 ,判斷輸入的網段中主機在線狀態

   read -p "Please give a network:" ip

   pingip=`echo "$ip"| cut -d. -f1-3`.

   if echo "$ip" | egrep'\<(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}

              ([0-9]|[1-9 ][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>' &>/dev/null;then

  #test only 15 host

      for i in `seq 240 255`

      do

          if ping -c1 -W1 $pingip$i &> /dev/null;then

              echo "$pingip$i is on work"

          else

              echo "$pingip$i is out of work"

          fi

      done

  else

      echo "$ip is useless"

  fi

v 6、 打印 九九 乘法表

 #方法1for循環 if語句             #方法2for循環 for語句

 for i in {1..9}                 for i in {0..9}

 do                   do

     for j in {1..9}                 for j in $(seq $i)

     do                   do

     if [ $j -le $i ];then                echo -ne $i*$j=$[$i*$j]\t

         echo -ne "$i*$j=$[i*j]\t"   #不換行打印i*j=*TAB        done

     else                  echo

         break                   #結束這一層的循環;一般在if中使用   done

     fi

     done

     echo                        #顯示打印內容

 done

 

v 7、在/testdir 目錄下創建10html文件, 文件名格式為數字N(從1 10 )加隨機8個字母,如1AbCdeFgH.html

  if [ -a /testdir ];then

      echo "/testdir is alreadly existing"

  else

      mkdir /testdir

  fi

  for i in $(seq 10);do

      for j in `cat /dev/urandom|tr -dc "a-zA-Z"|head -c 8`

      do

          cd /testdir

          touch $i$j.html

      done

      echo "$i$j.html has been created"

  done

1.2.3 while 循環

while CONDITION; do

循環體

done

    CONDITION :循環控制條件;進入循環之前,先做一次判斷;每一次循環之后會再次做判斷;條件為“true” ,則執行一次循環;直到條件測試狀態為“false” 終止循環。

v  因此:CONDTION 一般應該有循環控制變量;而此變量的值會在循環體不斷地被修正

v  進入條件:CONDITION true

v  退出條件:CONDITION false

1.2.4 while練習

1、編寫腳本,求100 以內 所有正奇數之和.

  sum=0;i=1

  while ((i<$n))

  do

      sum=$[$sum+$i]  

      let i=$[$i+2]

  done

  echo "sum=$sum"

v  2、編寫腳本, 提示請輸入網絡地址,如192.168.0.0 ,判斷輸入的網段中主機在線狀態 ,并統計在線主機和離線主機各多少。

  read -p "Please give a network:" ip

  pingip=`echo "$ip"| cut -d. -f1-3`.

  if echo "$ip" | egrep '\<(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9

  ][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\>' &>/dev/null;then

  #test only 15 host

      for i in `seq 240 255`

      do

          if ping -c1 -W1 $pingip$i &> /dev/null;then

              echo "$pingip$i is on work"

          else

              echo "$pingip$i is out of work"

          fi

      done

  else

      echo "$ip is useless"

  fi     unset ip pingip i

v  3、編寫腳本,打印 九九乘法表

  #方法3while循環             #方法3until循環

  i=1                i=1

  while [ $i -le 9 ];do               #$i的值小于9,就執行以下循環  until ((i>9))

      j=1               do

      while [ $j -le $i ];do          #$j的值小于$i,就執行以下循環   let j=1

          echo -en "$i*$j=$[i*j]\t"           until ((j>i))

          let j++                     #$j=$j+1       do

      done                echo -en $i*$j=$[$i*$j]\t

      let i++                         #$i=$i+1,重新開始循環    let j++

      let j=1                         #j的值從1開始,重新開始循環  echo

      echo               done

  done

v  4、編寫腳本,利用變量RANDOM 生成10 個隨機數字,輸出這個10 數字,并顯示其中的最大值和最小值

  max=$[$RANDOM]           #變量賦值也可以用let max=$RANDOM

  min=$[$RANDOM]           #變量賦值也可以用$(( ));

  #[ $max -lt $min ]&&let mid=$min&&let min=$max&&let max=$mid  #舉一個例子

  #echo "random number 1 is : $max"

  #echo "random number 2 is : $min"

  for ((i=1;i<=10;i++));do

          ran=$[$RANDOM]          #與隨機生成的中間參數做比較

          echo "random number $i is : $ran"

          [ $max -lt $ran ]&&let max=$ran

          [ $min -gt $ran ]&&let min=$ran

  done

  echo "======================================="

  echo "max number is $max , min number is $min"

v  5、編寫腳本,實現打印國際象棋棋盤

  read -p "How many lines will you want to make for chess:" line

  for i in $(seq $line);do                    #控制行數

      for j in $(seq $line);do                #控制列數

          let sum=$[i+j]                      #把不同的兩行合并成一個單元

          if [[ $sum%2 -eq 0 ]];then          #取余,當為單數的話打印一種顏色,為雙數打印另一種

              echo -en "\e[47m  \e[0m"        #打印空格顏色為黑色

          else

              echo -en "\e[40m  \e[0m"        #打印空格顏色為白色

          fi         z=$[$sum%2]

      done       [ $z -eq 0 ] && echo -ne "\033[47;1m  \033[0m"||echo -ne "\033[40;1m  \033[0m"

      echo

  done

  unset i j sum

v  6、后續六個字符串:154773ae5d 、bc3f3efe68、ada7aa2054 、4ee771de1f 2ebd3caa45 、3417171ac1是通過對RANDOM 隨機數變量執行命令:md5sum|cut -c1-10后 的結果,請破解這些字符串對應的的RANDOM值。

  a=(

  154773ae5d

  bc3f3efe68

  ada7aa2054

  4ee771de1f

  2ebd3caa45

  3417171ac1

  )                     #a是一個數組

  for n in {0..65535};do

      md5=`echo $n | md5sum |cut -c1-10`    

      for m in ${a[@]};do                    #${a[@]} 表示數組中的子集   

          if [[ "$md5" == "$m" ]];then

              echo -e $md5 "–>" $n

          fi

      done

  done

  unset n m md5

1.2.5 until 循環

v until CONDITION; do

循環體

v done

v 進入條件: CONDITION  false

v 退出條件: CONDITION  true

1.3 循環控制語句

1.3.1 continue循環控制語句

v continue [N] :提前結束第N 層的本輪循環,而直接進入下一輪循環判斷;最內層為第1層;用于循環體中

while CONDTIITON1; do

CMD1

if  CONDITION2; then

continue

fi

CMDn

done

1.3.2 break循環控制語句

v break [N] :提前結束第N 層循環,最內層為第1層 ;用于循環體中,退出整個循環,繼續執行循環后的命令

while CONDTIITON1; do

CMD1

if CONDITION2; then

break

fi

CMDn

done

1.3.3 shift循環控制命令

v shift [n]

v 用于將參量列表 list  左移指定次數,缺省為左移一次。

v 參量列表 list 一旦被移動,最左端的那個參數就從列表中刪除。while 到循環遍歷位置參量列表時,常用到 shift

v    ./doit.sh a b c d e f g h

v    ./shfit.sh a b c d e f g h

示例:doit.sh

#!/bin/bash

# Name: doit.sh

# Purpose: shift through command line arguments

# Usage: doit.sh [args]

while (( $# > 0 )) # or [ $# -gt 0 ]do

echo $*

shift

done

示例:shift.sh

#!/bin/bash

# Using 'shift' to step through all thepositional parameters.

until [ -z "$1" ]do

echo "$1"

shift

done

echo

exit 0

1.3.4創建無限循環

while true; do

循環體

done

until false; do

循環體

done

1.3.5 練習

1、每隔3秒鐘到系統上獲取已經登錄的用戶的信息;如果發現用戶hacker 登錄,則將登錄時間和主機記錄日志/var/log/login.log , 并退出腳本。     until false;do

while true ;do            until who | grep ^hacker\> &> /dev/null;do

if who | grep ^hacker\> &> /dev/null;then             sleep 3

break           done

fi           echo $(date +: %F &T)hacker logged on >> /var/log/login.log

sleep 3

done

echo $(date +: %F &T)hacker logged on >> /var/log/login.log

v 2、隨機生成10 以內的數字,實現猜字游戲,提示比較大或小,相等則退出。

#!/bin/bash

suiji=$[$RANDOM%10+1]            #隨機生成10以內的數字

read -p "我猜:" shuru

until [[ $suiji -eq $shuru ]]; do

  [ $shuru -lt $suiji ] && echo "小了"

  [ $shuru -gt $suiji ] && echo "大了"

  read -p "我猜:" shuru

done

echo "猜中了,退出"

v 3、用文件名做為參數,統計所有參數文件的總行數特殊用法。

 

1.3.6 循環的特殊用法

while特殊用法

遍歷文件的每一行:while read line; do

循環體

done < /PATH/FROM/SOMEFILE

依次讀取/PATH/FROM/SOMEFILE 文件中的每一行,且將行賦值給變量line。

練習

掃描/etc/passwd 文件每一行,如發現GECOS 字段為空,則填充用戶名和單位電話為62985600 ,并提示該用戶的GECOS信息修改成功。

while read line;do

if [ -z `awk -F: {print $5} $line` ] ; then              if [-z `echo $line|cut -d: -f5`] ;then

chfn -p 62985600 -f 62985600 `awk -F: {print $1} $line` &> /dev/null

echo The user GECOS have been changed successful

fi

done < etc/passwd

unset line

for特殊用法

v  雙小括號方法,即(()) 格式,也可以用于算術運算

v  雙小括號方法也可以使bash Shell 實現C 語言風格的變量操作

#I=10    ;    #((I++))

for 循環的特殊格式:

for (( 控制變量初始化; 條件判斷表達式; 控制變量的修正表達式))

do

循環體

done

v  控制變量初始化:僅在運行到循環代碼段時執行一次

v  控制變量的修正表達式:每輪循環結束會先進行控制變量修正運算,而后再做條件判斷

1.3.7 select 循環與菜單

select variable(變量)  in list

do

循環體命令

done

v  select循環主要用于創建菜單,按數字順序排列的示 菜單項將顯示在標準錯誤上,并顯示 PS3提示符,等待用戶輸入。

用戶輸入菜單列表中的某個數字,執行相應的命令

v  用戶輸入被保存在內置變量 REPLY  中。

select case

vselect 是個無限循環,因此要記住用 break 命令退出循環,或用exit按命令終止腳本。也可以按 ctrl+c退出循環。

vselect 和經常和 case 聯合使用

v與 for循環類似,可以省略 in list ,此時使用位置參量

1.3.8 trap信號捕捉

trap ' 觸發指令'  信號

自定義進程收到系統發出的指定信號后,將執行觸發指令,而不會執行原操作

trap ' ' 信號:忽略信號的操作

trap '-' 信號:恢復還信號的操作

trap -p:列出自定義信號操作

1.3.9 trap 示例

#!/bin/bash

trap 'echo signal:SIGINT"' int

trap -p

for((i=0;i<=10;i++))

do

sleep 1

echo $i

done

trap '' int

trap -p

for((i=11;i<=20;i++))

do

sleep 1

echo $i

done

trap '-' int

trap -p

for((i=21;i<=30;i++))

do

sleep 1

echo $i

done

二、函數介紹

v  函數function 是由若干條shell 命令組成的語句塊,實現代碼重用和模塊化編程。

v它與shell 程序形式上是相似的,不同的是它不是一個單獨的進程,不能獨立運行,而是shell 程序的一部分。只能被調用。

v  函數和shell 程序比較相似,區別在于:

? Shell 程序在子Shell 中運行。

? Shell 函數在當前Shell 中運行。因此在當前Shell 中,函數可以對shell 中變量進行修改。

匿名函數:{cmd1;cmd2;cmd3},不定義在set的函數變量中。

2.1定義函數

v  函數由兩部分組成:函數名f_name和函數體。

v  語法一:

function f_name {

函數體

}

v  語法二:

function f_name () {

函數體

}

v最常用語法三:

f_name (){

函數體

}

2.2函數使用

v  函數的定義和使用:

1.可在交互式環境下定義函數 ; 2.可將函數放在腳本文件中作為它的一部分 ; 3.可放在只包含函數的單獨文件中。

v  調用:函數只有被調用才會執行

函數的調用:給定函數名;函數名出現的地方,會被自動替換為函數代碼。

函數的生命周期:被調用時創建,返回時終止,只能在當前shell中進行。

2.2.1函數返回值

函數有兩種返回值:

v   函數的執行結果返回值:

(1)  使用echo等命令進行輸出  ;  (2)  函數體中調用命令的輸出結果。

v  函數的退出狀態碼:

(1)  默認取決于函數中執行的最后一條命令的退出狀態碼  ;

(2)  自定義退出狀態碼, 其格式為:在函數中 return #從函數中返回,用最后狀態命令決定返回值。

return 0 無錯誤返回。退出函數,但是繼續執行函數后面的命令;return 1-255 有錯誤返回。不執行后面任務。

echo $? 的值為return 返回的值)

function函數存放目錄:/etc/init.d/functions在自己腳本中調用的話,用source  /root/bin/f_name 就可執行函數

 交互式環境下定義和使用函數(不常用)

v  示例:

$dir() {

> ls -l

> }

v  定義該函數后,若在$ 后面鍵入dir ,其顯示結果同ls -l的作用相同。

$dir 函數:

v 該dir 函數將一直保留到用戶從系統退出(僅對當前終端有效),或執行了如下所示的unset 命令:$ unset dir

unset f_name :刪除函數 ;set f_name :查看定義的函數

在腳本中定義及使用函數

v  函數在使用前必須定義,因此應將函數定義放在腳本開始部分,直至shell 首次發現它后才能使用

v  調用函數僅使用其函數名即可。

v  示例:

$cat func1

#!/bin/bash

# func1

hello()

{

echo "Hello there today's date is `date +%F`"

}

echo "now going to the function hello"

hello

echo "back from the function"

2.2.2使用函數文件

v 可以將經常使用的函數存入函數文件,然后將函數文件載入shell 。

v 文件名可任意選取,但最好與相關任務有某種聯系。例如:functions.main

v 一旦函數文件載入shell ,就可以在命令行或腳本中調用函數??梢允褂?/span>set 命令查看所有定義的函數,其輸出列表包括已經載入shell 的所有函數。

v 若要改動函數,首先用unset 命令從shell 中刪除函數。改動完畢后,再重新載入此文件。

創建函數文件

v  函數文件示例:

$cat functions.main

#!/bin/bash

#functions.main

findit()

{

if [ $# -lt 1 ] ; then

echo "Usage:findit file"

return 1

fi

find / -name $1 print

}

載入函數

v  函數文件已創建好后,要將它載入shell

v  定位函數文件并載入shell 的格式:.  filename source filename

隨后,函數就被載入到set 所定義的函數里了,就可以在腳本里直接使用函數名了

v  注意:此即< > < 空格> < 文件名>

這里的文件名要帶正確路徑

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

檢查載入函數

v  使用set 命令檢查函數是否已載入。set 命令將在shell 中顯示所有的載入函數。

v  示例:

$set

findit=( )

{

if [ $# -lt 1 ]; then

echo "usage :findit file";

return 1

fi

find / -name $1 -print

}

2.2.3執行shell 函數

v  要執行函數,簡單地鍵入函數名即可:

$findit groups

/usr/bin/groups

/usr/local/backups/groups.bak

刪除shell 函數

v  現在對函數做一些改動。首先刪除函數,使其對shell 不可用。使用unset 命令完成此功能.

v  命令格式為:unset function_name

v  示例 :$unset findit   ; 再鍵入set 命令,函數將不再顯示

2.3函數參數

v  函數可以接受參數:

傳遞參數給函數:調用函數時,在函數名后面以空白分隔給定參數列表即可;例如testfunc arg1 arg2 …

在函數體中當中,可使用$1, $2, … 調用這些參數;還可以使用$@, $*, $# 等特殊變量

2.3.1函數變量

變量作用域:

環境變量:當前shell 和子shell 有效

本地變量:只在當前shell 進程有效,為執行腳本會啟動專用子shell 進程;因此,本地變量的作用范圍是當前shell 腳本程序文件,包括腳本中的函數。

局部變量:函數的生命周期;函數結束時變量被自動銷毀

v   注意:如果函數中有局部變量,如果其名稱同本地變量,使用局部變量。

v  在函數中定義局部變量的方法:local NAME=VALUE

2.3.2函數遞歸

函數直接或間接調用自身;注意遞歸層數

v  遞歸實例:階乘是基斯頓·于卡曼于1808年發明的運算符號,是數學術語一個正整數的階乘(factorial )是所有小于及等于該數的正整數的積,并且有0 的階乘為1 。自然數n 的階乘寫作n!。

n!=1 ×2 ×3 ××n。

階乘亦可以遞歸方式定義:0!=1 ,n!=(n-1)! ×n。

n!=n(n-1)(n-2)…1   ; n(n-1)! = n(n-1)(n-2)!

函數遞歸示例: fact.sh

#!/bin/bash

#

fact() {

if [ $1 -eq 0 -o $1 -eq 1 ]; then

echo 1

else

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

fi

}

fact $1

注意:引入變量先要用read

2.3.3練習

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_NAME is running…

如果/var/lock/subsys/ SCRIPT_NAME 文件不存在,則顯示“ SCRIPT_NAME is stopped…

其中: SCRIPT_NAME 為當前腳本名

(7) 在所有模式下禁止啟動該服務,可用chkconfig service 命令管理

lockfile=/var/log/subsys/SCRIPT_NAME

usagte(){

    echo "Usage: $prog {start|stop|restart|status}"

}

if [ $# -lt 1 ]; then

    usage

    exit 1

fi

start(){

    if [ -e $lockfile ]; then

        echo "$prog is already running."

        return 0

    else

        touch $lockfile

        [ $? -eq 0 ] && echo "Starting $prog finished."

    fi

}

stop(){

    if [ -e $lockfile ]; then

        rm -f $lockfile && echo "Stop $prog ok."

    else

        echo "$prog is stopped yet."

    fi

}

status(){

    if [ -e $lockfile ]; then

        echo "$prog is running."

    else

        echo "$prog is stopped."

    fi

}

case $1 in

start)

       start

       ;;

stop)

       stop

       ;;

restart)

       stop

       start

       ;;

status)

       status

       ;;

*)

       usage

esac

2 、編寫腳本/root/bin/copycmd.sh

(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

ch_root="/mnt/sysroot"

[ ! -d $ch_root ] && mkdir $ch_root

bincopy() {

      if which $1 $>/dev/null; then

          local cmd_path="which –skip-alias $1"

          local bin_dir="dirname $cmd_path"

          [ -d ${ch_root}${bin_dir} ] || mkdir -p ${ch_root}${bin_dir}

          [ -f ${ch_root}${cmd_path}] || cp $cmd_path ${ch_root}${bin_dir}

          return 0

      else

          echo "Command not found."

          return 1

      fi

}

libcopy() {

      local lib_list=$(ldd `which –skip-alias $1` | grep -Eo '/[^[:space:]]+')

      for loop in $lib_list;do

          local lib_dir=`dirname $loop`

          [ -d $ {ch_root}${lib_dir} ] || mkdir -p ${ch_root}${lib_dir}

          [ -f $ {ch_root}${loop} ] || cp $loop ${ch_root}${lib_dir}

      done

}

read -p "Please input a command:" command

while [ "$command" != "quit" ]; do

     if bincopy $command ; then

        libcopy $command

     fi

     read -p "Please input a command or quit: "command

done

3 、編寫函數實現兩個數字做為參數,返回最大值.

#!/bin/bash

source funs.sh

funs.sh

#!/bin/bash

echo "please enter two number"

read a

read b

if test $a -eq $b;then

echo "two same: "$a

elif test $a -gt $b;then

echo "big is: "$a

else

 echo "big is: "$b

fi

4 、編寫函數實現數字的加減乘除運算,例如輸入 1 + 2 ,將得出正確結果。

#!/bin/bash

source funs.sh

jia   $1 $2

jian  $1 $2

cheng $1 $2

chu   $1 $2

 

funs.sh

#!bin/bash

echo "1st arg is $1"

echo "2nd arg is $2"

jia   (){

          local a=$[$1+$2]

          echo $a

         }

jian  (){

          local a=$[$2-$1]

          echo $a

         }

cheng (){

          local a=$[$1*$2]

          echo $a

         }

chu   (){

          local a=$[$1/$2]

          echo $a

         }

5 、斐波那契數列又稱黃金分割數列,因數學家列昂納多· 斐波那契以兔子繁殖為例子而引入,故又稱為“兔子數列”,指的是這樣一個數列:0 、1 、1 、2 、3 、5 、8 、13 、21 34 、…… ,斐波納契數列以如下被以遞歸的方法定義:F 0 =0 ,F 1 =1 ,F n =F(n-1)+F(n-2) n2)利用函數 ,求n 階斐波那契數列。

fact() {

    if [ $1 -eq 0 ]

    then

        echo 0

    elif [ $1 -eq 1 ]

    then

        echo 1

    else

        echo $[$(fact $[$1-2])+$(fact $[$1-1])]

    fi

}

6 、漢諾塔(又稱河內塔)問題是源于印度一個古老傳說。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64 片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。并且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。

利用函數,實現N 片盤的漢諾塔的移動步驟。

#!/bin/bash

step=0

hanoi(){

[[ ! $1 = ~ ^[1-9][0-9]*$ ]]&&echo "error! please input a positive interger" && exit

if [ $1 -eq 1 ]; then

         let step++

         echo "$step: move plate $1   $2 —–> $4"

else

         hanoi "$[$1-1]" $2 $4 $3

         let step++

         echo "$step: move plate $1   $2 —–> $4"

         hanoi "$[$1-1]" $3 $2 $4

fi

}

read -p "please input the number of plates: "number

hanoi $number A B C

三、數組

v  變量:存儲單個元素的內存空間

v  數組:存儲多個元素的連續的內存空間,相當于多個變量的集合。

數組名和索引

索引:編號從0 開始,屬于數值索引

注意:索引可支持使用自定義的格式,而不僅是數值格式,即為關聯索引 ,bash4.0 版本之后開始支持。

bash 的數組支持稀疏格式(索引之間不連續)

聲明數組:

declare -a ARRAY_NAME 可以不聲明,但是建議聲明

declare -A ARRAY_NAME:  關聯數組 ;必須要先聲明才能使用

3.1數組賦值

v  數組元素的賦值:

(1)  一次只賦值一個元素;

ARRAY_NAME[INDEX]下標=VALUE

weekdays[0]="Sunday" ; weekdays[4]="Thursday"  稀疏格式

(2)  一次賦值全部元素:ARRAY_NAME=("VAL1" "VAL2" "VAL3" …)

生成列表可以用ARRAY_NAME=;ARRAY_NAME=({1..10});ARRAY_NAME=*

(3)  只賦值特定元素:指定下標,直接賦值

ARRAY_NAME=[0]="VAL1" [3]="VAL2" …

(4)  交互式數組值對賦值:read -a ARRAY

3.2引用數組

v  引用數組元素:${ARRAY_NAME[INDEX]}   注意:省略[INDEX] 表示引用下標為0 的元素

數組的長度( 數組中元素的個數): 當不知道數組中存在多少元素

${ARRAY_NAME[*]}、${ARRAY_NAME[@]}:查看顯示數組中所有元素

${#ARRAY_NAME[*]}、${#ARRAY_NAME[@]}:查看顯示數組的元素個數 ,新加的元素的下標就等于元素的個數

如果數組要新添加一個元素 name[${ARRAY_NAME[@]}]=var

v  示例:生成10 個隨機數保存于數組中,并找出其最大值和最小值

#!/bin/bash

declare -a rand

declare -i max=0

declare -i min=32767

for i in {0..9}; do

rand[$i]=$RANDOM

echo ${rand[$i]}

[ ${rand[$i]} -gt $max ] && max=${rand[$i]}

[ ${rand[$i]} -lt $min ] && min=${rand[$i]}

done

echo "Max: $max Min:$min"

v  編寫腳本 ,定義一個數組,數組中的元素是/var/log 目錄下所有以.log 結尾的文件;要統計其下標為偶數的文件中的行數之和。

#!/bin/bash

#

declare -a files

files=(/var/log/*.log)

declare -i lines=0

for i in $(seq 0 $[${#files[*]}-1]); do fileline=`wc -l ${file[$i]} |cut -d " " -f1`

if [ $[$i%2] -eq 0 ];then            ——》for i in $(seq 0 2 $[${#file[*]}-1];do

let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1) [ $[$i%2] -eq 0 ] && let lines+=$fileline

fi

done

echo "Lines: $lines."

3.3數組數據處理

引用數組中的元素:

所有元素:${ARRAY[@]}  ${ARRAY[*]}

數組切片${ARRAY[@]:offset:number} offset個元素;取隨后的number個元素

offset:  要跳過的元素個數 ; number:  要取出的元素個數

取偏移量之后的所有元素:${ARRAY[@]:offset}

向數組中追加元素:ARRAY[${#ARRAY[*]}]=var

刪除數組中的某元素:導致稀疏格式:unset ARRAY[INDEX]

關聯數組:declare -A ARRAY_NAME  注意:必須先聲明,再調用

  ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2…)

現有的數組只能先unset ,再重新開始設置

練習1 、輸入若干個數值存入數組中,采用 冒泡算法進行升序或降序排序

#!/bin/sh

echo "please input a number list:"

read -a arr

 for (( i=0 ; i<${#arr[@]} ; i++ ))

do

  for (( j=${#arr[@]}- 1 ; j>i ; j– ))

  do

    #echo $j

    if  [[ ${arr[j]} -lt ${arr[j-1]} ]]

    then

       t=${arr[j]}

       arr[j]=${arr[j-1]}

       arr[j-1]=$t

    fi

  done

done

echo "after ascending sorting:"

echo ${arr[@]}

=================================================

for (( i=0 ; i<${#arr[@]} ; i++ ))

do

  for (( j=${#arr[@]}- 1 ; j>i ; j– ))

  do

    #echo $j

    if  [[ ${arr[j]} -gt ${arr[j-1]} ]]

    then

       t=${arr[j]}

       arr[j]=${arr[j-1]}

       arr[j-1]=$t

    fi

  done

done

echo "after descending sorting:"

echo ${arr[@]}

3.4字符串處理

 bash的字符串處理工具

3.4.1字符串切片

${#var}: 返回字符串變量var 的長度

${var:offset}: 返回字符串變量var 中從第offset 個字符后(不包括第offset 個字符)的字符開始,到最后的部分,offset的取值在0 ${#var}-1 之間(bash4.2 后,允許為負值)

${var:offset:number} :返回 字符串變量var 中從第offset 個字符后(不包括第offset 個字符)的字符開始長度為number 的部分

${var: -lengh} :取字符串的最右側幾個字符

注意:冒號后必須有一空白字符

${var:offset: -lengh} :從最左側跳過offset 字符,一直取到字符串的最右側lengh個字符之前

3.4.2基于模式取子串

${var#*word} :其中word 可以是指定的任意字符

功能:自左而右,查找var 變量所存儲的字符串中,第一次出現的word,  刪除字符串開頭至第一次出現word 字符之間的所有字符。

${var##*word} :同上,不同的是,刪除的是字符串開頭至最后一次由word 指定的字符之間的所有內容

示例:file="var/log/messages 

echo ${file#*/}: log/messages ; echo ${file##*/}: messages

${var%word*} :其中word 可以是指定的任意字符;

功能:自右而左,查找var 變量所存儲的字符串中,第一次出現的word,  刪除字符串最后一個字符向左至第一次出現word 字符之間的所有字符;

${var%%word*} :同上,只不過刪除字符串最右側的字符向左至最后一次出現word 字符之間的所有字符;

file="/var/log/messages"

echo ${file%/*}: /var/log ; echo ${file%%/*}:

示例:url=http://www.magedu.com:80

echo ${url##*:} 80 echo ${url%%:*} http

3.4.3查找替換

${var/pattern/substi} :查找var 所表示的字符串中,第一次被pattern 所匹配到的字符串,以substi 替換之

${var//pattern/substi}:  查找var 所表示的字符串中,所有能被pattern 所匹配到的字符串,以substi 替換之

${var/#pattern/substi} :查找var 所表示的字符串中,行首被pattern 所匹配到的字符串,以substi 替換之

${var/%pattern/substi} :查找var 所表示的字符串中,行尾被pattern 所匹配到的字符串,以substi 替換之

3.4.4查找并刪除

${var/pattern} :查找var 所表示的字符串中,刪除第一次被pattern 所匹配到的字符串

${var//pattern} :所有

${var/#pattern} :行首

${var/%pattern} :行尾

3.4.5字符大小寫轉換

${var^^} :把var 中的所有小寫字母轉換為大寫

${var,,} :把var 中的所有大寫字母轉換為小寫

3.5變量賦值

v ${var:-value} :如果var 為空或未設置,那么返回value ;否則,則返回var的值

v ${var:+value} :如果var 不空,則返回value ,否則返回空值

v ${var:=value} :如果var 為空或未設置,那么返回value ,并將value 賦值給var ;否則,則返回var的值

v ${var:?error_info} :如果var 為空或未設置 ,那么在當前終端打印error_info;否則,則返回var的值

為腳本程序使用配置文件, 實現變量賦值

(1)  定義文本文件,每行定義“name=value

(2)  在腳本中source 此文件即可

高級變量用法有類型變量

v Shell 變量一般是無類型的,但是bash Shell 提供了declaretypeset 兩個命令用于指定變量的類型,兩個命令是等價的。

3.5.1 declare變量

v declare [ 選項]  變量名

-r:將變量設置為只讀屬性 ; -x:將變量聲明為環境變量 ;-f:顯示此腳本前定義過的所有函數名及其內容

-i:將變量定義為整型數 ; -a:將變量定義為數組 ;-F:僅顯示此腳本前定義過的所有函數名

-A:將變量定義為關聯數組

-l:將變量值轉為小寫字母 declare -l var=UPPER ; -u:將變量值轉為大寫字母 declare -u var=lower

3.5.2間接變量引用

v  如果第一個變量的值是第二個變量的名字,從第一個變量引用第二個變量的值就稱為間接變量引用。

v variable1=variable2 ; variable2=value

v variable1 的值是variable2 ,而variable2 又是變量名,variable2 的值為value ,間接變量引用是指通過variable1獲得變量值value 的行為

v bash Shell 提供了兩種格式實現間接變量引用

eval tempvar=\$$variable1 tempvar=${!variable1}

示例: [root@server ~]# N=NAME

[root@server ~]# NAME=wangxiaochun

[root@server ~]# N1=${!N}

[root@server ~]# echo $N1

wangxiaochun

[root@server ~]# eval N2=\$$N

[root@server ~]# echo $N2

wangxiaochun

3.5.3 eval 命令

v eval 命令將會首先掃描命令行進行所有的置換,然后再執行該命令。該命令適用于那些一次掃描無法實現其功能的變量. 該命令對變量進行兩次掃描(如果變量是命令,則顯示執行的結果)。

示例: [root@server ~]# CMD=whoami

[root@server ~]# echo $CMD

whoami

[root@server ~]# eval $CMD

root

3.5.4 mktemp創建臨時文件

mktemp 命令:創建的臨時文件可避免沖突

v  mktemp [OPTION]… [TEMPLATE]

TEMPLATE: filename.XXX 注意:X 至少要出現三個,創建并顯示創建的臨時文件的名字

-d:  創建臨時目錄  ; -p DIR –tmpdir=DIR :指明臨時文件所存放目錄位置

示例

#mktemp /tmp/test.XXX  計劃任務crontab -e 輸出重定向到/dev/null;或者用此臨時文件愛你

#tmpdir=`mktemp d /tmp/testdir.XXX`

#mktemp –tmpdir=/testdir test.XXXXXX

3.5.5 install安裝復制文件

v install 命令:適合安裝程序,能直接給予文件的所有者,所有組以及權限

install [OPTION]… [-T] SOURCE DEST  單文件 ; install [OPTION]… SOURCE… DIRECTORY

install [OPTION]… -t DIRECTORY SOURCE… ; install [OPTION]… -d DIRECTORY… 創建空目錄

-m MODE:指明權限 ,默認755 ; -o OWNER:指明屬主 ; -g GROUP:指明屬組

示例:

install -m 700 -o wang -g admins file1 file2 相當于cp,不過給予了權限

install m d /testdir/installdir 直接創建目錄

原創文章,作者:lyx,如若轉載,請注明出處:http://www.www58058.com/61073

(0)
lyxlyx
上一篇 2016-11-27
下一篇 2016-11-27

相關推薦

  • awk

    文本處理工具 文本處理三工具:grep,sed,awk grep,egrep,fgrep:文本過濾工具 sed:行編輯器 awk:報告生成器,格式化文本輸出; awk gawk – pattern scanning and processing language lrwxrwxrwx. 1 root root 4 May 17 19:23 /bi…

    Linux干貨 2017-05-21
  • Linux系統用戶、組

    1、資源分派:          Authentication  認證        Authorization   授權     &nbs…

    Linux干貨 2016-08-04
  • 2016/08/21:shell遺留select,包管理器rpm,yum

    select:搭配case更好的顯示選項     這個命令用來創建菜單,按數字排列,并等待用戶輸入,輸入對應數字,執行相應操作,更清楚明了     普通版:select var in list        &…

    Linux干貨 2016-08-24
  • sed工具 介紹

    sed工具 地址定界 不給地址:對全文進行處理 單地址: #:指定行 /pattern/:被此處模式所能夠匹配到的每一行 地址范圍: #,# #,+# /pat1/,/pat2/ #,/pat1/ ~:步進 1~2 奇樹行 2~2 偶數行 cat -n passwd >passwd2 新建文件 sep -n ‘/^h//^s/’…

    Linux干貨 2017-05-31
  • N24期第四周作業

    1、復制/etc/skel目錄為/home/tuser1,要求/home/tuser1及其內部文件的屬組和其它用戶均沒有任何訪問權限。 2、編輯/etc/group文件,添加組hadoop。 vim /etc/group,增加此行 3、手動編輯/etc/passwd文件新增一行,添加用戶hadoop,其基本組ID為hadoop組的id號;其家目錄為/home…

    Linux干貨 2016-11-22
  • RHEL6.9換源記

    RHEL是提供給企業使用的,雖然我們在網絡上也能下載到它的鏡像,但是我們無法使用它的服務。最近由于系統比較卡,重裝了一次系統,裝完之后,我用VMware Workstation Pro 12 加載了之前的RHEL 6.9-000002.vmdk文件之后居然發現不能掛載CD/DVD,這就不能愉快的玩了。在VMware的設置里折騰好久也沒能搞定,光盤安裝RPM包…

    2017-07-20
欧美性久久久久