天天看點

腳本進階腳本進階for循環while循環until循環(與while邏輯相反)循環控制語句continue循環控制語句break循環控制shift指令select循環與菜單函數介紹信号捕捉trap數組字元串處理變量指派expect介紹

腳本進階

循環

信号捕捉

函數

數組

進階字元串操作

進階變量

expect

程式設計中的邏輯處理:

  • 順序執行
  • 選擇執行
  • 循環執行

循環

  • 循環執行

    将某代碼段重複運作多次

    重複運作多少次

      循環次數事先已知

      循環次數事先未知

    有進入條件和退出條件

  • for, while, until

for循環

  • for 變量名 in 清單;do

      循環體

    done

  • 執行機制:

    依次将清單中的元素指派給“變量名”; 每次指派後即執行一次循環體; 直到清單中的元素耗盡,循環結束

for NAME [in WORDS ... ] ; do COMMANDS; done
	其中 NAME 表示直接是變量名
case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
 	case中的WORD則表示變量值  case $var in ....
 	表示時case與其他表示有差别~~~
           
清單生成方式:
  • (1) 直接給出清單
  • (2) 整數清單:

    {start…end}

    $(seq [start [step]] end)

  • (3) 傳回清單的指令

    $(COMMAND)

  • (4) 使用glob,如:*.sh
  • (5) 變量引用

    $@, $*

for特殊格式(類似c語言風格的循環)

  • 雙小括号方法,即((…))格式,也可以用于算術運算
  • 雙小括号方法也可以使bash Shell實作C語言風格的變量操作
  • for循環的特殊格式:

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

      循環體

    done

  • 控制變量初始化:僅在運作到循環代碼段時執行一次
  • 控制變量的修正表達式:每輪循環結束會先進行控制變量修正運算,而後再做條件判斷
help for:
其中for (( exp1; exp2; exp3 )); do COMMANDS; done
或者for (( exp1; exp2; exp3 )); do
	COMMANDS
done
①注意:連着寫CMD末尾有 ; 分号 (循環的語句跟{}類似,指令行直接寫循環時注意CMD;)
②其中for (( exp1; exp2; exp3 )); do COMMANDS; done  == 
(( EXP1 ))
    	while (( EXP2 )); do
    		COMMANDS
    		(( EXP3 ))
    	done
  兩種形式等價:是以在for (( exp1; exp2; exp3 ))中
  		若exp1有多個變量初始化時,之間使用 , 隔開
  		eg:for((sum=0,i=1;i<=100;i++));do let sum+=i;done; echo $sum
           

for循環練習

  • 1、判斷/var/目錄下所有檔案的類型
  • 2、添加10個使用者user1-user10,密碼為8位随機字元
  • 3、/etc/rc.d/rc3.d目錄下分别有多個以K開頭和以S開頭的檔案;分别讀取每個檔案,以K開頭的輸出為檔案加stop,以S開頭的輸出為檔案名加start,如K34filename stop S66filename start
  • 4、編寫腳本,提示輸入正整數n的值,計算1+2+…+n的總和
  • 5、計算100以内所有能被3整除的整數之和
  • 6、編寫腳本,提示請輸入網絡位址,如192.168.0.0,判斷輸入的網段中主機線上狀态
  • 7、列印九九乘法表
  • 8、在/testdir目錄下建立10個html檔案,檔案名格式為數字N(從1到10)加随機8個字母, 如:1AbCdeFgH.html
  • 9、列印等腰三角形

while循環

  • while CONDITION; do

      循環體

    done

  • CONDITION:循環控制條件;進入循環之前,先做一次判斷;每一次循環之後 會再次做判斷;條件為“true”,則執行一次循環;直到條件測試狀态為“false” 終止循環
  • 是以:CONDTION一般應該有循環控制變量;而此變量的值會在循環體不斷地被修正
  • 進入條件:CONDITION為true
  • 退出條件:CONDITION為false

特殊用法

  • while循環的特殊用法(周遊檔案的每一行)

    while read line; do

      循環體

    done < /PATH/FROM/SOMEFILE

  • 依次讀取/PATH/FROM/SOMEFILE檔案中的每一行,且将行指派給變量line
若使用逐行處理時使用while read line這樣用法
	實際例子:檢視網絡連接配接數ss -tn 時常将ip篩選出來,然後将對應次數統計
	逐行處理時可以使用while read line
		總涉及ip通路統計ip 和 次數 然後對于不正常的通路利用防火牆隔絕,
		然後涉及兩個變量 ip 和 對應ip次數 可以分别放入兩個變量中,然後逐行處理
			ss -nt|sed -nr '/^ESTAB/s#.* (.*):.*#\1#p'|sort|uniq -c|sort -nr|while read num ip ;do echo "$num:$ip"; done 
		<可以看到連接配接數賦給了num  ipv4位址賦給變量ip>
		當然中間執行的操作可以設定為:如果1min内,連接配接數大于100,就拒絕通路(結合計劃任務)
			[ $num -eq 100 ] && iptables -A INPUT -s $ip -j REJECT
	
while read line;do CMDS;done  逐行處理示例:

1)标準輸入接收
~]# seq 5 | while read line;do echo line:$line;done
line:1
line:2
line:3
line:4
line:5

2)标準輸入重定向
]# while read line;do echo line:$line;done < /etc/issue
line:S
line:Kernel r on an m

3)實作對兩個變量同時指派:
~]# echo -e "a b\nc d" | while read x y;do echo $x $y;done
a b  <預設以空格為分割符>  空格前值賦給x 
c d <逐行處理><與read指派差不多>

~]# echo a b | { read x y;echo $x $y; } 
a b
<管道右側指令在子shell中執行,是以檢視管道右側變量的指派時應該在一個shell中檢視>
           
  • 練習

    掃描/etc/passwd檔案每一行,如發現GECOS字段為空,則将使用者名和機關電

    話為62985600填充至GECOS字段,并提示該使用者的GECOS資訊修改成功

練習總結:while read line;do CMDS;done 逐行處理,
上面的練習有種在通路的檔案然後在修改,好像會生個finenamer的檔案,
以下是我實作練習功能的腳本:<沒有直接修改/etc/passwd檔案,将檔案拷貝至/data/test目錄修改>
#!/bin/bash
file=/data/test/passwd
#判斷檔案是否存在
[ -f "$file" ] || { echo "$file is not existence."; exit 1; }
phone=62985600
 # 主要想調用action函數
. /etc/rc.d/init.d/functions
while read line ;do
# 如果GECOS字段不為空;continue,為空再執行下面的指令
	echo $line | grep -q '::' || continue
	user=`echo $line | cut -d":" -f1`
#使用的sed指令修改的原檔案,但是sed指令一般習慣使用' ' (強引用),是以之間的變量要生效可以使用'''$VAR'''
	echo $line | sed -ir '/'''$user'''/s#::#:'''$user''' '''$phone''':#' $file
	[ $? -eq 0 ] && action "$user GECOS modified" 
done < $file
# 删除腳本執行生成的finenamer檔案
rm -f ${file}r  
           

while練習

  • 1、編寫腳本,求100以内所有正奇數之和
  • 2、編寫腳本,提示請輸入網絡位址,如192.168.0.0,判斷輸入的網段中主機線上狀态,并統計線上和離線主機各多少
  • 3、編寫腳本,列印九九乘法表
  • 4、編寫腳本,利用變量RANDOM生成10個随機數字,輸出這個10數字,并顯示其中的最大值和最小值
  • 5、編寫腳本,實作列印國際象棋棋盤
  • 6、後續六個字元串:efbaf275cd、4be9c40b8b、44b2395c46、 f8c8873ce0、b902c16c8b、ad865d2f63是通過對随機數變量RANDOM随機 執行指令: echo $RANDOM|md5sum|cut –c1-10 後的結果,請破解這些 字元串對應的RANDOM值

until循環(與while邏輯相反)

  • until CONDITION; do

      循環體

    done

  • 進入條件: CONDITION 為false
  • 退出條件: CONDITION 為true

循環控制語句continue

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

    while CONDTIITON1; do

      CMD1

      …

      if CONDITION2; then

        continue

      fi

      CMDn

      …

    done

循環控制語句break

  • 用于循環體中
  • break [N]:提前結束第N層循環,最内層為第1層

    while CONDTIITON1; do

      CMD1

      …

      if CONDITION2; then

        break

      fi

      CMDn

      …

    done

循環控制shift指令

  • shift [n]
  • 用于将參量清單 list 左移指定次數,預設為左移一次。
  • 參量清單 list 一旦被移動,最左端的那個參數就從清單中删除。while 循環周遊位置參量清單時,常用到 shift
  • ./doit.sh a b c d e f g h
  • ./shfit.sh a b c d e f g h
  • 可始終針對具體的位置參數做處理
一般的判斷邏輯為:始終處理$1,循環次數$#
	while [  "$1"  ];do  或者 while [ $# -gt 0 ] # or (( $# > 0 ))
		CMD $1
		shift
	done
	< 切記不能使用for ((i=0;i<$#;i++)) 這種邏輯判斷!! 因為$#在遞減 >
           

select循環與菜單

  • select variable in list;do

      循環體指令

    done

  • select 循環主要用于建立菜單,按數字順序排列的菜單項将顯示在标準錯誤上,并顯示 PS3 提示符,等待使用者輸入
  • 使用者輸入菜單清單中的某個數字,執行相應的指令
  • 使用者輸入被儲存在内置變量 REPLY 中
  • select 是個無限循環,是以要記住用 break 指令退出循環,或用 exit 指令終止 腳本。也可以按 ctrl+c 退出循環
  • select 經常和 case 聯合使用
  • 與 for 循環類似,可以省略 in list,此時使用位置參量
  • PS2是輸入重定向的提示符
其中可以實作一個目錄中全部存放可執行腳本:
然後配合select制作成菜單選項,選擇什麼就執行相應的腳本
	執行該目錄下所有可執行程式:run-parts 指令(腳本需要執行權限) run-parts /dir
大概實作:
#!/bin/bash
PS3="Choose what you need to do: "
select opt in `ls /data/test/` ;do
    echo $opt
    echo $REPLY

#   case $opt in 
#   ...
#   esac
done
[[email protected] test]# bash select.sh  <腳本效果,選擇對應選項執行對應腳本>
1) backup.sh	  3) check_dos.sh   5) select.sh
2) check_disk.sh  4) scan_ip.sh
Choose what you need to do:
           

函數介紹

  • 函數function是由若幹條shell指令組成的語句塊,實作代碼重用和子產品化程式設計
  • 它與shell程式形式上是相似的,不同的是它不是一個單獨的程序,不能獨立運作,而是shell程式的一部分
  • 函數和shell程式比較相似,差別在于

Shell程式在子Shell中運作

而Shell函數在目前Shell中運作。是以在目前Shell中,函數可以對shell中變 量進行修改

定義函數

  • 函數由兩部分組成:函數名和函數體
  • help function
  • 文法一:(一般采用文法一簡潔)

    f_name (){

      …函數體…

    }

  • 文法二:

    function f_name {

      …函數體…

    }

  • 文法三:

    function f_name () {

      …函數體…

    }

函數使用

  • 函數的定義和使用:

    ①可在互動式環境下定義函數

    ②可将函數放在腳本檔案中作為它的一部分

    ③可放在隻包含函數的單獨檔案中

  • 調用:函數隻有被調用才會執行 調用:給定函數名 函數名出現的地方,會被自動替為函數代碼
  • 函數的生命周期:被調用時建立,傳回時終止

函數傳回值

  • 函數有兩種傳回值:
  • 函數的執行結果傳回值:

    (1) 使用echo等指令進行輸出

    (2) 函數體中調用指令的輸出結果

  • 函數的退出狀态碼:

    (1) 預設取決于函數中執行的最後一條指令的退出狀态碼

    (2) 自定義退出狀态碼,其格式為:

    return 從函數中傳回,用最後狀态指令決定傳回值

    return 0 無錯誤傳回

    return 1-255 有錯誤傳回

互動式環境下定義和使用函數

  • 示例:

    dir() {

    > ls -l

    > }

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

    dir

  • 該dir函數将一直保留到使用者從系統退出,或執行了如下所示的unset指令

    unset dir

在腳本中定義及使用函數

  • 函數在使用前必須定義,是以應将函數定義放在腳本開始部分,直至shell首次發現它後才能使用
  • 調用函數僅使用其函數名即可

使用函數檔案

  • 可以将經常使用的函數存入函數檔案,然後将函數檔案載入shell
  • 檔案名可任意選取,但最好與相關任務有某種聯系。例如:functions.main
  • 一旦函數檔案載入shell,就可以在指令行或腳本中調用函數。可以使用set指令檢視所有定義的函數,其輸出清單包括已經載入shell的所有函數
  • 若要改動函數,首先用unset指令從shell中删除函數。改動完畢後,再重新載 入此檔案
函數檔案示例:
1、系統定義的函數檔案:/etc/rc.d/init.d/functions
	系統定義了一個action()函數,功能如下:
		[[email protected] data]# . /etc/rc.d/init.d/functions
		[[email protected] data]# action "hello"
		hello                       [  OK  ]
		[[email protected] data]# action "hello" false
		hello                       [FAILED]
		         綠色OK,紅色FAILED

2、自己定義函數
以下常用的函數:
<輸入是否正确的函數>
<輸入的ip是否是合法ip函數>
<判斷輸入的是否是無符号整數>
cat	functions.main
#functions.main 
unint (){
	[[ "$1" =~ ^[0-9]+$ ]] && return 0 || return 1
}
legal_ip () {
	[[ "$1" =~ ^(([1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.){3}\
	([1]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$ ]] || return 1
}
blank (){
	[ "$1" ] && return 0 || return 1
}

           

載入函數

  • 函數檔案已建立好後,要将它載入shell
  • 定位函數檔案并載入shell的格式

    . filename 或 source filename

  • 注意:此即<點> <空格> <檔案名> 這裡的檔案名要帶正确路徑

檢查載入函數

  • 使用set指令檢查函數是否已載入。set指令将在shell中顯示所有的載入函數

執行shell函數

  • 要執行函數,簡單地鍵入函數名即可
  • 示例:

    findit groups

    /usr/bin/groups

    /usr/local/backups/groups.bak

删除shell函數

  • 現在對函數做一些改動後,需要先删除函數,使其對shell不可用。使用unset命

    令完成删除函數

  • 指令格式為:

    unset function_name

  • 環境函數

    使子程序也可使用

    聲明:export -f function_name

    檢視:export -f 或 declare -xf

函數參數

  • 函數可以接受參數:

    傳遞參數給函數:調用函數時,在函數名後面以空白分隔給定參數清單即可;

    例如“testfunc arg1 arg2 …”

  • 在函數體中當中,可使用$1, 2 , . . . 調 用 這 些 參 數 ; 還 可 以 使 用 2, ...調用這些參數;還可以使用 2,...調用這些參數;還可以使用@, $*, $#

    等特殊變量

函數變量

變量作用域:

  • 環境變量:目前shell和子shell有效
  • 本地變量:隻在目前shell程序有效,為執行腳本會啟動專用子shell程序; 是以,本地變量的作用範圍是目前shell腳本程式檔案,包括腳本中的函數
  • 局部變量:函數的生命周期;函數結束時變量被自動銷毀
  • 注意: 如果函數中有局部變量,如果其名稱同本地變量,使用局部變量
  • 在函數中定義局部變量的方法

    local NAME=VALUE

函數遞歸示例

  • 函數遞歸:

    函數直接或間接調用自身

    注意:遞歸層數

  • 遞歸執行個體:

    階乘是基斯頓·卡曼于 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)!

#!/bin/bash
#
fact() {
if [ $1 -eq 0 -o $1 -eq 1 ]; then
	echo 1
else
	echo $[$1*`fact $[$1-1]`]
fi
}
fact $1
           

fork炸彈

  • fork炸彈是一種惡意程式,它的内部是一個不斷在fork程序的無限循環,實質是一個簡單的遞歸程式。由于程式是遞歸的,如果沒有任何限制,這會導緻這個簡單的程式迅速耗盡系統裡面的所有資源
  • 函數實作
:(){ :|:& };:
bomb() { bomb | bomb & }; bomb
           
  • 腳本實作
cat Bomb.sh
#!/bin/bash
./$0|./$0&
           

腳本練習

練習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…”

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

說明:SCRIPT_NAME為目前腳本名

練習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退出

信号捕捉trap

  • 當腳本在執行過程中有時不希望被kill發送的信号打斷,因為腳本執行一半有時會影響後續的執行,此時可以采用trap将信号捕獲,進行相應的處理。
  • trap ‘觸發指令’ 信号

    程序收到系統發出的指定信号後,将執行自定義指令,而不會執行原操作

  • trap ‘’ 信号

    忽略信号的操作

  • trap ‘-’ 信号

    恢複原信号的操作

  • trap -p

    列出自定義信号操作

  • trap finish EXIT

    當腳本退出時,執行finish函數

  • 注意: 9) SIGKIL 信号不能被捕獲(man kill中有說明)
#!/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
           

數組

  • 變量:存儲單個元素的記憶體空間
  • 數組:存儲多個元素的連續的記憶體空間,相當于多個變量的集合
  • 數組名和索引

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

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

    ③bash的數組支援稀疏格式(索引不連續)

  • 聲明數組:

    declare -a ARRAY_NAME

    declare -A ARRAY_NAME 關聯數組

    注意: 兩者不可互相轉換;關聯數組必須先聲明後使用

  • 數組的最大索引即為元素個數

數組指派

  • 數組元素的指派

    (1) 一次隻指派一個元素

    ARRAY_NAME[INDEX]=VALUE

    weekdays[0]=“Sunday” weekdays[4]=“Thursday”

    (2) 一次指派全部元素

    ARRAY_NAME=(“VAL1” “VAL2” “VAL3” …)

    (3) 隻指派特定元素

    ARRAY_NAME=([0]=“VAL1” [3]=“VAL2” …)

    (4) 互動式數組值對指派 read -a ARRAY

  • 顯示所有數組:declare -a

引用數組

  • 引用數組元素

    ${ARRAY_NAME[INDEX]}

    注意:省略[INDEX]表示引用下标為0的元素

  • 引用數組所有元素

    ${ARRAY_NAME[*]}

    ${ARRAY_NAME[@]}

  • 數組的長度(數組中元素的個數)

    ${#ARRAY_NAME[*]}

    ${#ARRAY_NAME[@]}

  • 删除數組中的某元素:導緻稀疏格式 unset ARRAY[INDEX]
  • 删除整個數組

    unset ARRAY

數組資料處理

  • 引用數組中的元素:

    數組切片:

      ${ARRAY[@]:offset:number}

        offset 要跳過的元素個數

        number 要取出的元素個數

      取偏移量之後的所有元素

      ${ARRAY[@]:offset}

  • 向數組中追加元素:

    ARRAY[${#ARRAY[*]}]=value

  • 關聯數組:

    declare -A ARRAY_NAME

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

    注意:關聯數組必須先聲明再調用

練習

  • 輸入若幹個數值存入數組中,采用冒泡算法進行升序或降序排序
  • 将下圖所示,實作轉置矩陣matrix.sh
1 2 3				1 4 7
4 5 6	===>		2 5 8
7 8 9				3 6 9
           
  • 列印楊輝三角形
練習總結:
shell函數雖然不支援二維數組,
但是可以将一維數組分成行和列====>就對應成了二維數組

以矩陣的轉置進行示例:<楊輝三角我也以二維數組的方式實作的>
#!/bin/bash
declare -a matrix
declare -i line=3
# 一維數組的索引 index
declare -i index    
# 一維數組指派
matrix=(1 2 3 4 5 6 7 8 9)
#for ((i=0;i<9;i++));do	
#	matrix[$i]=$[i+1]
#done
# 将一維數組變為二維數組j行k列
for((j=0;j<3;j++));do
	for ((k=0;k<3;k++));do
		let index=j*line+k
		echo -e  "${matrix[$index]}\t\c"
	done
	echo
done
echo "=========================="
# 實作轉置
for((j=0;j<3;j++));do
    for ((k=0;k<3;k++));do
        let index=k*line+j
        echo -e  "${matrix[$index]}\t\c"
    done
    echo
done
           

字元串處理

字元串切片

  • ${#var}:傳回字元串變量var的長度
  • ${var:offset}:傳回字元串變量var中從第offset個字元後(不包括第offset個字元)的字

    符開始,到最後的部分,offset的取值在0 到 ${#var}-1 之間(bash4.2後,允許為負值)

  • ${var:offset:number}:傳回字元串變量var中從第offset個字元後(不包括第offset個字元)的字元開始,長度為number的部分
  • ${var: -length}:取字元串的最右側幾個字元

    注意:冒号後必須有一空白字元

  • ${var:offset:-length}:從最左側跳過offset字元,一直向右取到距離最右側lengh個字元之前的内容
  • ${var: -length:-offset}:先從最右側向左取到length個字元開始,再向右取到距離最右側offset個字元之間的内容

    注意:-length前空格

基于模式取子串

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

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

  • ${var##*word}:同上,貪婪模式,不同的是,删除的是字元串開頭至最後一次由word指定的字元之間的所有内容
  • ${var%word*}:其中word可以是指定的任意字元

    功能:自右而左,查找var變量所存儲的字元串中,第一次出現的word, 删除字元串最後一個字元向左至第一次出現word字元串(含)之間的所有字元

  • ${var%%word*}:同上,隻不過删除字元串最右側的字元向左至最後一次出現word字元之間的所有字元
+ 典型示例:
url=http://www.magedu.com:80
${url##*:}	80  		取端口
${url%%:*}	http		取協定	
           

查找替換

  • ${var/pattern/substr}:查找var所表示的字元串中,第一次被pattern所比對到的字元串,以substr替換之
  • ${var//pattern/substr}: 查找var所表示的字元串中,所有能被pattern所比對到的字元串,以substr替換之
  • ${var/#pattern/substr}:查找var所表示的字元串中,行首被pattern所比對到的字元串,以substr替換之
  • ${var/%pattern/substr}:查找var所表示的字元串中,行尾被pattern所比對到的字元串,以substr替換之

查找并删除

  • ${var/pattern}:删除var表示的字元串中第一次被pattern比對到的字元串
  • ${var//pattern}:删除var表示的字元串中所有被pattern比對到的字元串
  • ${var/#pattern}:删除var表示的字元串中所有以pattern為行首比對到的字元串
  • ${var/%pattern}:删除var所表示的字元串中所有以pattern為行尾所比對到的字元串

字元大小寫轉換

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

變量指派

  • 一個變量有三種情況:<eg:變量var>

    ①未定義此變量

    ②定義了此變量但未指派

    ③定義了此變量并賦予值

  • 如果希望變量var的三種情況去影響另一個變量的值時,采用此種方式:
    腳本進階腳本進階for循環while循環until循環(與while邏輯相反)循環控制語句continue循環控制語句break循環控制shift指令select循環與菜單函數介紹信号捕捉trap數組字元串處理變量指派expect介紹

進階變量用法-有類型變量

  • Shell變量一般是無類型的,但是bash Shell提供了declare和typeset(已經被declare取代)兩個指令用于指定變量的類型,兩個指令是等價的
  • declare [選項] 變量名

    -r 聲明或顯示隻讀變量

    -i 将變量定義為整型數

    -a 将變量定義為數組

    -A 将變量定義為關聯數組

    -f 顯示已定義的所有函數名及其内容

    -F 僅顯示已定義的所有函數名

    -x 聲明或顯示環境變量和函數

    -l 聲明變量為小寫字母 declare –l var=UPPER

    -u 聲明變量為大寫字母 declare –u var=lower

eval指令

  • eval指令的作用

    ①首先掃描指令行進行所有的置換

    ②然後再執行該指令

  • 該指令适用于那些一次掃描無法實作其功能的變量,該指令對變量進行兩次掃描
  • 比如:引用間接變量等
示例:
[[email protected] ~]# CMD=whoami
[[email protected] ~]# echo	$CMD
whoami
[[email protected] ~]# eval $CMD
root
[[email protected] ~]# n=10 [[email protected] ~]# echo {0..$n}
{0..10}
[[email protected] ~]# eval echo {0..$n} 0 1 2 3 4 5 6 7 8 9 10
           

間接變量引用

  • 如果第一個變量的值是第二個變量的名字,從第一個變量引用第二個變量的值就稱為間接變量引用
  • variable1的值是variable2,而variable2又是變量名,variable2的值為value,間接變量引用是指通過variable1獲得變量值value的行為

    variable1=variable2

    variable2=value

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

    eval tempvar=\$$variable1

    tempvar=${!variable1}

[[email protected] data]# var1="i am var1"
[[email protected] data]# echo $var1
i am var1
[[email protected] data]# var2=var1
[[email protected] data]# echo $var2
var1
[[email protected] data]# echo ${!var2}
i am var1
數組指派示例:
declare -i tmp
declare -a num
因為 i 作為數組的索引,是以 i 從 0 開始指派,但是位置參數又是從 1 ($1,$2..)開始的
for ((i=0;i<$#;i++));do
# 間接變量指派方式:
	eval tmp=\$$[i+1]
	num[$i]=$tmp
done
	echo ${num[@]}


           

建立臨時檔案

  • mktemp指令:建立并顯示臨時檔案,可避免沖突
  • mktemp [OPTION]… [TEMPLATE]

    TEMPLATE: filenameXXX

      X至少要出現三個

  • OPTION:

    -d: 建立臨時目錄

    -p DIR或–tmpdir=DIR:指明臨時檔案所存放目錄位置

示例:建立臨時目錄5個随機數加上時間秒數,此時檔案名相同的概念應該就很小啦~	
~]# mktemp -d /data/test/`date +%F_%T`_XXXXX
/data/test/2019-08-25_15:54:06_XUarv 
	 <預設将建立的檔案名輸出至螢幕是以可儲存至變量,供提示和log使用>
]# ls
2019-08-25_15:54:06_XUarv
           

安裝複制檔案

  • 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 srcfile desfile

    install –m 770 –d /testdir/installdir

install 的功能差不多==cp+chown+chmod+mkdir+chgrp 
	可以修改建立目錄、複制檔案的屬組、屬主和權限
	源碼編譯安裝時make install即實作相應的檔案複制,目錄建立
           

expect介紹

  expect 是由Don Libes基于Tcl( Tool Command Language )語言開發的,主要應用于自動化互動式操作的場景,借助 expect 處理互動的指令,可以将互動過如:ssh登入,ftp登入等寫在一個腳本上,使之自動化完成。尤其适用于需要對 多台伺服器執行相同操作的環境中,可以大大提高系統管理人員的工作效率。

expect指令

  • expect 文法:
  • expect [選項] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
  • 選項

    -c:從指令行執行expect腳本,預設expect是互動地執行的

    -d:可以輸出輸出調試資訊

  • expect中相關指令

    spawn 啟動新的程序

    send 用于向程序發送字元串

    expect 從程序接收字元串

    interact 允許使用者互動

    exp_continue 比對多個字元串在執行動作後加此指令

expect應用

  • expect最常用的文法(tcl語言:模式-動作)
  • 單一分支模式文法:

    expect “hi” {send “You said hi\n"}

    比對到hi後,會輸出“you said hi”,并換行

  • 多分支模式文法:

    expect “hi” { send “You said hi\n” } \

    “hehe” { send “Hehe yourself\n” } \

    “bye” { send “Good bye\n” }

  • 比對hi,hello,bye任意字元串時,執行相應輸出。等同如下:

    expect {

    “hi” { send “You said hi\n”}

    “hehe” { send “Hehe yourself\n”}

    “bye” { send " Good bye\n"}

    }