shell腳本編程進階

在linux shell中,一般咱們將一些命令寫在一個文件中就算是一個shell腳本了,可是若是須要執行更爲複雜的邏輯判斷,咱們就須要使用流程控制語句來支持了。
所謂流程控制既是經過使用流程控制語句對程序流程的選擇、循環、轉向和返回等進行控制。流程控制是全部編程語言分重要組成部分,linux shell一樣有一套本身的流程控制語句,其中主要包括條件語句(if),循環語(for,while),選擇語句(case)。html

條件選擇if語句

單分支

if判斷條件;then 條件爲真的分支代碼 fi

雙分支

if 判斷條件; then 條件爲真的分支代碼 else 條件爲假的分支代碼 fi

多分支

if 判斷條件1; then 條件爲真的分支代碼 elif 判斷條件2; then 條件爲真的分支代碼 elif 判斷條件3; then 條件爲真的分支代碼 else 以上條件都爲假的分支代碼 fi

逐個條件進行判斷,第一次爲「真」條件時,接着執行其分支,然後結束整個if語句linux

條件判斷case語句

case 變量引用 in #變量的引用加$ PAT1) 分支1 ;; PAT2) 分支2 ;; ... \*) 默認分支 ;; esac

case支持glob風格的通配符:
*: 任意長度任意字符
?: 任意單個字符
[]:指定範圍內的任意單個字符
a|b: a或bgit

練習 1、編寫腳本/root/bin/createuser.sh,實現以下功能:使用一個用戶名作爲參數,若是
指定參數的用戶存在,就顯示其存在,不然添加之;顯示添加的用戶的id號等信息

#!/bin/bashshell

read -p "please input username:" username
useradd $username &> /dev/null
if [ $? -eq 0 ];then
    echo "add $username user" && id $username
else
    echo "the user already exits"
fi編程

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

#!/bin/bashbash

read -p "Do you agree? yes or no: " ANS
if [ -z "$ANS" ] ;then
   echo "Please input yes or no"
   exit
fi
case $ANS in
[Yy]|[Yy][Ee][Ss])
   echo "Your answer is YES"
   ;;
[Nn]|[Nn][Oo])
   echo "Your answer is NO"
   ;;
*)
   echo "Your answer is fales"
esac網絡

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

#!/bin/bash編程語言

read -p "input file or dir:" choose
[ -z "$choose" ] && echo "Please input a file or dir"
if [ -d "$choose" ] ;then
   echo "$choose is directory"
elif [ -L "$choose" ] ;then
   echo "$choose is a link"
elif [ -f "$choose" ] ;then
   echo "$choose is a common file"
else
   echo "$choose is other type"
fi模塊化

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

#!/bin/bash函數

read -p "input a digit:" NUM
if [[ "$NUM" =~ ^[0-9]+$ ]] ;then
   echo "$NUM is a int"
fi

循環

循環執行

  將某代碼段重複運行屢次

  重複運行多少次

    循環次數事先已知

    循環次數事先未知

  有進入條件和退出條件

for, while, until

for循環

for 變量名 in 列表; do 循環體 done 執行機制: 依次將列表中的元素賦值給「變量名」; 每次賦值後即執行一次循環體; 直 到列表中的元素耗盡,循環結束 列表生成方式: (1) 直接給出列表 for num in 1 2 3 4 5;do echo The number is $num ;done The number is 1 The number is 2 The number is 3 The number is 4 The number is 5 (2) 整數列表: (a) {start..end} for num in {10..1..3};do echo The numberis $num ;done The numberis 10 The numberis 7 The numberis 4 The numberis 1 (b) $(seq [start [step]] end) for num in `seq 2 4 10`;do echo The number is $num ;done The number is 2 The number is 6 The number is 10 (3) 返回列表的命令 $(COMMAND) (4) 使用glob,如:*.sh for num in "/root/bin/*.sh";do echo The filename is $num ;done The filename is /root/bin/*.sh (5) 變量引用; $@獨立, $*總體(位置變量)

多行重定向

 

練習: 用for實現 1、打印國際象棋 for i in {1..8};do for j in {1..4};do if [ $[i%2] -eq 0 ];then echo -e "\033[1;41m \033[0m\e[1;43m \e[0m\c" else echo -e "\e[1;43m \e[0m\e[1;41m \e[0m\c" fi done echo done \c=-n默認不轉行 \e \e[0m=\033 \033[0m顏色提示符 2、添加10個用戶user1-user10,密碼爲magedu for i in {1..10};do if id $i &> /dev/null ;then echo "user$i is exist" else useradd user$i &>/dev/null echo "magedu" | passwd --stdin user$i &>/dev/null echo "user $i add successful" fi done 注:批量刪除用戶for i in {1..10};do userdel -r(刪除家目錄) user$i;done 3、/etc/rc.d/rc3.d目錄下分別有多個以K開頭和以S開頭的文件;分別讀取每一個文件, 以K開頭的輸出爲文件加stop,以S開頭的輸出爲文件名加start,如K34filename stop S66filename start #!/bin/bash for i in $(ls /etc/rc.d/rc3.d/);do if [[ $i =~ ^K.* ]];then echo "$i stop" elif [[ $i =~ ^S.* ]];then echo "$i start" fi done 4、編寫腳本,提示輸入正整數n的值,計算1+2+…+100的總和 #!/bin/bash declare -i sum=0 n=100 for i in {1..100};do let sum=sum+i | sum+=i done echo sum=$sum unset sum 5、計算100之內全部能被3整除的整數之和 #!/bin/bash sum=0 for i in {1..100};do if [ $[$i%3] -eq 0 ];then let sum+=$i fi done echo $sum 6、編寫腳本,提示請輸入網絡地址,如192.168.0.0,判斷輸入的網段中主機在線狀態 net=192.168.140 for i in {1..254};do { if ping -c1 -w1 $net .$i &> /dev/null ;then echo $net.$i is up else echo $net.$i is down fi; } & 並行在後臺執行 done wait 7、打印九九乘法表 #!/bin/bash for i in {1..9};do for j in `seq 1 $i`;do result=$[$j*$i] echo -e "$j*$i=$result \c" done echo done 8、在/testdir目錄下建立10個html文件,文件名格式爲數字N(從1到10)加隨機8個字 母,如:1AbCdeFgH.html 取隨機字母openssl rand -base64 20 | tr -dc '[:alpha:]' | head -c8 9、打印等腰三角形 *的個數=line*2-1 空格=總line-當前line #!/bin/bash read -p "Please input lines:" L for i in `seq ${L}`;do for (( j=${L};j>i;j-- ));do echo -n " " done for j in `seq 1 $i`;do echo -n "*" done for (( n=1;n<i;n++ ));do echo -n "*" done echo " " done

 打印等腰三角形而且顏色隨機

#!/bin/bash
read -p "Please input lines:" L for i in `seq ${L}`;do for j in `seq $[$L-i]`;do echo -n " " done for k in `seq $[i*2-1]`;do let color=$RANDOM%7+31 echo -ne "\e[1;5;${color}m*\e[0m" done echo done

while循環

while 條件;do 循環體 done 條件(CONDITION):循環控制條件;進入循環以前,先作一次判斷;每次循環以後會再次作判斷;條件爲"ture", 則執行一次循環;直到條件測試狀態爲「false」終止循環。 所以:CONDTION通常應該有循環控制變量;而此變量的值會在循環體不斷地 被修正 進入條件:CONDITION爲true 退出條件:CONDITION爲false

 

練習:
1
、編寫腳本,求100之內全部正奇數之和 #!/bin/bash
declare
-i sum=0 i=1 while [ $i -le 100 ];do let sum=sum+i let i=i+2 done echo sum=$sum 2、編寫腳本,提示請輸入網絡地址,如192.168.0.0,判斷輸入的網段中主機 在線狀態,並統計在線和離線主機各多少

#!/bin/bash

net=192.168.140
let num=1
x=0(up的主機)
y=0(down的主機數)
while [ ${num} -le 254 ];do
ping -c1 -w1 "${net}.${num}" &>/dev/null
  if [ $? -eq 0 ];then
    echo "${net}.${num} is up"
    x=$(($x+1))
  else
    echo "${net}.${num} is down"
    y=$(($y+1))
  fi
num=$(($num+1))
done
echo "total ${x} hosts are up"
echo "total ${y} hosts are down "

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

#!/bin/bash

declare -i i=1
while [ $i -le 9 ];do
    declare -i j=1
    while [ $j -le $i ];do
       result=$[$i*$j]
       echo -e "${j}x${i}=$result\t\c" \t是產生空格並對齊;\c是不換

       let j++

    done
    echo
    let i++
done

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

#!/bin/bash

declare -i a=0
max=0
min=$RANDOM
while [ $a -le 9 ];do
num=$RANDOM
  if [ $num -le $max ];then
    if [ $num -le $min ];then
      min=$num
      fi
  else
      max=$num
  fi
  let a++:q!:
done
echo "the min number is $min,the max number is $max"

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

#!/bin/bash

let i=0
while [ $i -le 15 ];do
  for ((j=0;j<4;j++));do
    if [ $[i%4] -eq 0 -o $[i%4] -eq 1 ];then
      echo -e "\033[1;41m \033[0m\033[1;47m \033[0m\c"
    else
      echo -e "\033[1;47m \033[0m\033[1;41m \033[0m\c"

    fi
  done
  echo
  let i++
done

6、後續六個字符串:efbaf275cd、4be9c40b8b、44b2395c4六、 f8c8873ce0、b902c16c8b、ad865d2f63是經過對隨機數變量RANDOM隨機 執行命令: echo $RANDOM|md5sum|cut –c1-10 後的結果,請破解這些 字符串對應的RANDOM值while循環

 until循環

until CONDITION; do 循環體 done 進入條件: CONDITION 爲false 退出條件: CONDITION 爲true

循環控制語句continue

用於循環體中 continue [N]:提早結束第N層的本輪循環,而直接進入下一輪判斷;最內層爲第1層 while CONDTIITON1; do CMD1 ... if CONDITION2; then continue fi CMDn ... done

循環控制語句brek

用於循環體中 break [N]:提早結束第N層循環,最內層爲第1層 while CONDTIITON1; do CMD1 ... if CONDITION2; then break fi CMDn ... done

建立無限循環

while true; do

  循環體

done

until false; do

   循環體

Done

練習 1、每隔3秒鐘到系統上獲取已經登陸的用戶的信息;若是發現用戶hacker登陸, 則將登陸時間和主機記錄於日誌/var/log/login.log中,並退出腳本
#!/bin/bash

until `who | grep -o "^usr\b" &>/dev/null`;do
    sleep 3
done
echo "user is logining"
who | grep "user" >> /data/login.sh:q!

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

#!/bin/bash

i=$[$RANDOM%11]
while read -p "please input a number:" a;do
  [[ $a =~ ^[0-9]+$ ]] || { echo "please input a dight:1-10";continue; }
  if [ $i -gt $a ];then
    echo little
  elif [ $i -lt $a ];then
    echo more
  else
    echo right
    break
  fi
done

3、用文件名作爲參數,統計全部參數文件的總行數

if [ $# -eq 0 ];then  $#是全部未知變量
  echo "please input file path"
 else
  until [ -z "$1" ];do -z判斷文件是否爲空
    echo "tongji file:$1"
    echo "the file total line are: `wc -l $1 | cut -d " " -f1`「
    echo
    shift
done
echo "finish"
fi

4、用二個以上的數字爲參數,顯示其中的最大值和最小值

函數:function

是由若干條shell命令組成的語句塊,實現代碼重用和模塊化編程;函數只有被調用纔會執行

語法1: function func_name {   函數體 } 語法2:: func_name() {   函數體 }

注意:函數中變量的生效範圍是當前所在shell

函數的生命週期:被調用時建立,返回時終止

函數在使用前必須定義,所以應將函數定義放在腳本開始部分,直至shell首次發現它後才能使用,調用函數時就像使用命令同樣調用

return #:在函數中使用,跳出函數,返回值 #;若是沒有定義退出返回值則函數的默認返回值爲函數中最後一條命令的返回值

local var:聲明函數爲本地變量,只在函數內部生效

declare

  -f func_name 查看指定函數

  -xf func_name 聲明函數的生效範圍爲全局 == export -f func_name

  -i 聲明變量爲數字

  -g 在函數中使用,聲明變量爲普通變量

  declare 在函數中用隱式使用了local,定義的變量爲本地變量

函數的遞歸調用:在函數中調用函數自己

fork炸彈

bome() { bome|bome& }; bome

編寫腳本copycmd.sh

  • (1) 提示用戶輸入一個可執行命令名稱;
  • (2) 獲取此命令所依賴到的全部庫文件列表;
  • (3) 複製命令至某目標目錄(例如/mnt/sysroot)下的對應路徑下;
    • 如:/bin/bash ==> /mnt/sysroot/bin/bash
  • (4) 複製此命令依賴到的全部庫文件至目標目錄下的對應路徑下;(5)每次複製完成一個命令後,不要退出,而是提示用戶鍵入新的要複製的命令,並重復完成上述功能;直到用戶輸入quit退出;
    • 如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
複製代碼
#!/bin/bash . my_functions Ddir="/mnt/sysroot" [ ! -d "$Ddir" ] && mkdir "$Ddir" cpbin() { cmddir=`echo "$Cmd_path" |grep -o ".*/\b"` [ ! -d "${Ddir}${cmddir}" ] && mkdir -p "${Ddir}${cmddir}" cp -n "$Cmd_path" "${Ddir}${cmddir}" } libcp() { echo "$Lib_path" |while read line ;do libdir=`echo "$line" |grep -o ".*/\b"` [ ! -d "${Ddir}${libdir}" ] && mkdir -p "${Ddir}${libdir}" cp -n "$line" "${Ddir}${libdir}" 2>/dev/null done } while read -p "Input a cmd. (quit): " CMD ;do if [ "$CMD" == 'quit' ] ;then echo "Think you! Bye bye."; break; fi if ! which "$CMD" &>/dev/null ;then echo "not find $CMD, please input again." failed "copy $CMD failed." continue fi Cmd_path=`which $CMD |grep -o "/.*"` Lib_path=`ldd $Cmd_path |sed -nr 's#.*[[:space:]]+(/.*) .*#\1#p'` cpbin libcp success "copy $CMD Complete." done
複製代碼

 求斐波那契數列的第N個數

複製代碼
#!/bin/bash feibo() { if [ $1 -eq 0 ] ; then echo 0 elif [ $1 -eq 1 ] ;then echo 1 else echo $[`feibo $[$1-1]`+`feibo $[$1-2]`] fi } read -p "please a num: " n
複製代碼

 求N的階乘

複製代碼
#!/bin/bash fact() { if [ $1 -eq 0 -o $1 -eq 1 ] ;then echo 1 else echo $[$1*`fact $[$1-1]`] fi } fact $1
相關文章
相關標籤/搜索