shell程式設計進階
流程控制
if
單條件
if 判斷條件;then
條件為真的分支程式碼
fi
雙分支
if 判斷條件; then
條件為真的分支程式碼
else
條件為假的分支程式碼
fi
多分支
if 判斷條件1; then
條件為真的分支程式碼
elif判斷條件2; then
條件為真的分支程式碼
elif判斷條件3; then
條件為真的分支程式碼
else
以上條件都為假的分支程式碼
fi
case
case支援glob風格的萬用字元:
*: 任意長度任意字元
?: 任意單個字元
[]:指定範圍內的任意單個字元
a|b: a或b
case 變數引用 in
PAT1) 分支1;;
PAT2) 分支2;;
...
*) 預設分支;;
esac
編寫一個指令碼,實現執行它,則會顯示當前的日期,格式為:2018年06月14日 15時30分18秒 星期四
#!/bin/bash
w=$(date +%w)
case $w in
1) week="一";;
2) week="二";;
3) week="三";;
4) week="四";;
5) week="五";;
6) week="六";;
*) week="日";;
esac
echo "$(date "+%Y年%m月%d日 %H時%M分%S秒") 星期$week"
for
for 變數名 in 列表;do
迴圈體
done
給系統中所有uid大於300的使用者發一封郵件,內容:"你好,使用者xxx, 端午快樂"
#!/bin/bash
for n in $(cat /etc/passwd |cut -d: -f3);do
if [ $n -gt 300 ];then
UserName=`id -un $n`
echo "你好, 使用者$UserName,端午快樂" |mail -s "端午祝福" $UserName
fi
done
while
while CONDITION; do
迴圈體
done
a=0,列印0-9
#!/bin/bash
a=0
while [ $a -lt 10 ];do
echo $a
a=$[$a+1]
done
until
與while相反,條件為加時迴圈
until CONDITION; do
迴圈體
done
a=0,列印0-9
#!/bin/bash
a=0
until [ $a -gt 9 ];do
echo $a
a=$[$a+1]
done
continue
提前結束第N層的本輪迴圈,最內層為第1層
#!/bin/bash
for n in {1..10};do
if [ $n -eq 5 ];then
continue
fi
echo $n
done
break
提前結束第N層迴圈,最內層為第1層
#!/bin/bash
for n in {1..10};do
if [ $n -eq 5 ];then
break
fi
echo $n
done
shift
用於將參量列表list左移指定次數,參量列表list一旦被移動,最左端的那個引數就從列表中刪除
#!/bin/bash
while [ $# -gt 0 ];do
echo $*
shift
done
編寫一個依次建立指定使用者的指令碼,如/root/bin/createuser.sh zhangsan lisi wangsu
#!/bin/bash
while [ $# -gt 0 ];do
if id $1 &> /dev/null ;then
echo "$1 is already exist"
else
useradd $1
echo "$1 created"
fi
shift
done
練習
-
編寫指令碼/root/bin/createuser.sh,實現如下功能:使用一個使用者名稱做為引數,如果指定引數的使用者存在,就顯示其存在,否則新增之;顯示新增的使用者的id號等資訊
#!/bin/bash read -p "Please enter a username: " username if `id ${username} &> /dev/null`;then echo "User already exists" else useradd ${username} echo "${username} is to created" cat /etc/passwd |grep "^${username}:" fi
-
編寫指令碼/root/bin/yesorno.sh,提示使用者輸入yes或no,並判斷使用者輸入的若是y,Y,Yes,YES,yES 等則顯示YES,輸入其他的顯示NO
#!/bin/bash read -p "Are you agree?yes or no: " bool bool=`echo ${bool}|tr [:upper:] [:lower:]` if [[ yes =~ ${bool} ]];then echo "Your answer is yes" else echo "your answer is no" fi
-
編寫指令碼/root/bin/filetype.sh,判斷使用者輸入檔案路徑,顯示其檔案型別(普通,目錄,連結,塊裝置,符號裝置,管道,套接字)
#!/bin/bash read -p "Please enter a path: " path if `ls ${path} > /dev/null`;then filetype=`ls -ld ${path} |grep -o "^."` case ${filetype} in -) echo "The file is ordinary file";; d) echo "The file is directory file";; l) echo "The file is link file";; b) echo "The file is block file";; c) echo "The file is char file";; p) echo "The file is pipe file";; s) echo "The file is socket file";; *) echo "The file is others";; esac else echo "No such file or directory" fi
-
編寫指令碼/root/bin/checkint.sh,判斷使用者輸入的引數是否為正整數
#!/bin/bash read -p "Please enter a string: " string if [[ ${string} =~ ^[[:digit:]]+$ ]];then echo "The string is int" else echo "The string is others" fi
-
編寫指令碼var_filetype.sh,判斷/var/目錄下所有檔案的型別
#!/bin/bash for filename in `ls /var`;do # echo ${filename} filetype=`ls -ld "/var/${filename}" |grep -o "^."` case ${filetype} in -) echo "${filename} is ordinary file";; d) echo "${filename} is directory file";; l) echo "${filename} is link file";; b) echo "${filename} is block file";; c) echo "${filename} is char file";; p) echo "${filename} is pipe file";; s) echo "${filename} is socket file";; *) echo "${filename} is others";; esac done
#!/bin/bash for filename in `ls /var`;do if [ -f /var/${filename} ];then echo "${filename} is ordirary file" elif [ -d /var/${filename} ];then echo "${filename} is directory file" elif [ -L /var/${filename} ];then echo "${filename} is link file" elif [ -b /var/${filename} ];then echo "${filename} is block file" elif [ -c /var/${filename} ];then echo "${filename} is char file" elif [ -p /var/${filename} ];then echo "${filename} is pipe file" elif [ -S /var/${filename} ];then echo "${filename} is socket file" else echo "${filename} is others" fi done
#!/bin/bash for file in $(find /var);do if [ -f $file ]; then echo "$file is a regular file" elif [ -b $file ]; then echo "$file is a block file" elif [ -c $file ]; then echo "$file is a character file" elif [ -d $file ]; then echo "$file is a directory" elif [ -h $file ]; then echo "$file is a symbolic link" elif [ -p $file ]; then echo "$file is a named pipe" elif [ -S $file ]; then echo "$file is a socket" fi done
-
新增10個使用者user1-user10,密碼為8位隨機字元
#!/bin/bash for n in $(seq 1 10);do useradd user$n &> /dev/null password=$(cat /dev/urandom |tr -cd [[:alpha:][:punct:]] |head -c8) echo ${password} | passwd --stdin user$n &> /dev/null echo "user$n add successed, password is ${password}" done
-
編寫指令碼rc3.d.sh,檢視/etc/rc.d/rc3.d目錄下分別有多個以K開頭和以S開頭的檔案;分別讀取每個檔案,以K開頭的輸出為檔案加stop,以S開頭的輸出為檔名加start,如K34filename stop S66filename start
#!/bin/bash echo "Top K is `ls /etc/rc.d/rc3.d/|grep "^K"|wc -l`" echo "Top S is `ls /etc/rc.d/rc3.d/|grep "^S"|wc -l`" for filename in `ls /etc/rc.d/rc3.d/`;do top=`echo ${filename}|grep -o "^."` if [ ${top} == K ];then echo "${filename} stop" elif [ ${top} == S ];then echo "${filename} start" else continue fi done
#!/bin/bash echo "Top K is `ls /etc/rc.d/rc3.d/|grep "^K"|wc -l`" echo "Top S is `ls /etc/rc.d/rc3.d/|grep "^S"|wc -l`" ls /etc/rc.d/rc3.d/|sed -n "s/^K.*/& stop/p" ls /etc/rc.d/rc3.d/|sed -n "s/^S.*/& start/p"
-
編寫指令碼sum.sh,提示輸入正整數n的值,計算1+2+…+n的總和
#!/bin/bash read -p "Please enter a int: " int sum=0 for i in `seq 1 $int`;do let sum+=i done echo $sum
#!/bin/bash read -p "Please enter a int: " int seq -s + 1 $int|bc
-
編寫指令碼int3.sh,計算100以內所有能被3整除的整數之和
#!/bin/bash sum=0 for i in `seq 1 100`;do if [ `echo $[${i}%3]` == 0 ];then sum=$[$sum+$i] else continue fi done echo $sum
-
編寫指令碼hoststate.sh,提示請輸入網路地址,如192.168.0.1,判斷輸入的主機線上狀態
#!/bin/bash read -p "Please enter a IPv4 address: " ip if `ping -c1 -w1 ${ip} &> /dev/null`;then echo "The host is up" else echo "The host is down" fi
-
編寫指令碼99.sh,列印九九乘法表
#!/bin/bash for i in `seq 1 9`;do for j in `seq 1 ${i}`;do echo -e "$i*$j=$[$i*$j]\t\c" done echo done
-
編寫指令碼createhtml.sh,在/testdir目錄下建立10個html檔案,檔名格式為數字N(從1到10)加隨機8個字母,如:1AbCdeFgH.html
#!/bin/bash mkdir /testdir &> /dev/null for i in {1..10};do random_string=$(cat /dev/urandom |tr -cd [:alpha:] |head -c8) touch /testdir/$i${random_string}.html done
-
編寫triangle.sh,指令碼列印等腰三角形
#!/bin/bash read -p "請輸入需要生成的等腰三角形的行數:" zongline for curline in $(seq 1 $zongline);do spacenum=$[$zongline-$curline] anum=$[2*$curline-1] for kongge in $(seq 1 $spacenum);do echo -e "" "\c" done for a in $(seq 1 $anum);do echo -e "a\c" done echo done
-
編寫指令碼caipiao.sh,填5個數字,猜中多少按以下方式輸出
0 3 5 9 3
如果猜中一個,則輸出First blood
如果猜中兩個,則輸出Double kill
如果猜中三個,則輸出Triple kill
如果猜中四個,則輸出Quadra kill
如果全中,則輸出“大吉大利,今晚吃雞”#!/bin/bash read -p "Please enter a number: " a read -p "Please enter a number: " b read -p "Please enter a number: " c read -p "Please enter a number: " d read -p "Please enter a number: " e A=`echo $[$RANDOM%10]` B=`echo $[$RANDOM%10]` C=`echo $[$RANDOM%10]` D=`echo $[$RANDOM%10]` E=`echo $[$RANDOM%10]` echo "$A$B$C$D$E" a=`[ $a -eq $A ];echo $?` b=`[ $b -eq $B ];echo $?` c=`[ $c -eq $C ];echo $?` d=`[ $d -eq $D ];echo $?` e=`[ $e -eq $E ];echo $?` i=$[$a+$b+$c+$d+$e] case $i in 5) echo "No kill";; 4) echo "First blood";; 3) echo "Double kill";; 2) echo "Triple kill";; 1) echo "Quadra kill";; 0) echo "大吉大利,今晚吃雞" esac
#!/bin/bash lucky_num=$(cat /dev/urandom | head -100|tr -c [:digit:] "@" |tr -d @|cut -c1-5) echo "The lucky number has been generated" read -p "Please enter your results: " input_num echo "lucky_num is $lucky_num" echo "input_num is $input_num" get_num_lens=0 for i in `seq 1 5`;do r1=`echo $lucky_num|grep -o "[[:digit:]]"| sed -n "$i p"` r2=`echo $input_num|grep -o "[[:digit:]]"| sed -n "$i p"` if [ $r1 -eq $r2 ];then get_num_lens=$[$get_num_lens+1] fi done case $get_num_lens in 1) echo "First blood";; 2) echo "Double kill";; 3) echo "Triple kill";; 4) echo "Quadra kill";; 5) echo "大吉大利,今晚吃雞";; *) echo "sorry~";; esac
-
編寫指令碼,求100以內所有正奇數之和
#!/bin/bash sum=0 for i in `seq 1 100`;do if [ $[$i%2] -eq 1 ];then sum=$[$sum+$i] fi done echo sum=$sum
編寫指令碼,提示請輸入網路地址,如192.168.0.0,判斷輸入的網段中主機線上狀態,並統計線上和離線主機各多少
編寫指令碼,列印九九乘法表
-
編寫指令碼,利用變數RANDOM生成10個隨機數字,輸出這個10數字,並顯示其中的最大值和最小值
#!/bin/bash for i in `seq 1 10`;do j=$RANDOM echo $j if [ $i == 1 ];then max=$j min=$j else if [ $j -ge $max ];then max=$j fi if [ $j -le $min ];then min=$j fi fi done echo max:$max echo min:$min
-
編寫指令碼,實現列印國際象棋棋盤
#!/bin/bash for i in {1..8};do for j in {1..8};do if [ $[$i%2] == 1 ];then if [ $[$j%2] == 1 ];then echo -e "\033[47;37m \033[0m\c" else echo -e "\033[40;37m \033[0m\c" fi else if [ $[$j%2] == 1 ];then echo -e "\033[40;37m \033[0m\c" else echo -e "\033[47;37m \033[0m\c" fi fi done echo done
-
後續六個字串:efbaf275cd. 4be9c40b8b. 44b2395c46. f8c8873ce0. b902c16c8b. ad865d2f63是通過對隨機數變數RANDOM隨機執行命令:
echo $RANDOM|md5sum|cut –c1-10
後的結果,請破解這些字串對應的RANDOM值#!/bin/bash i=0 while [ $i -le 32767 ];do str=`echo $i|md5sum|cut -c1-10` # echo $str case $str in efbaf275cd) echo "efbaf275cd:$i";; 4be9c40b8b) echo "4be9c40b8b:$i";; 44b2395c46) echo "44b2395c46:$i";; f8c8873ce0) echo "f8c8873ce0:$i";; b902c16c8b) echo "b902c16c8b:$i";; ad865d2f63) echo "ad865d2f63:$i";; esac i=$[$i+1] done
-
隨機生成10以內的數字,實現猜字遊戲,提示比較大或小,相等則退出
#!/bin/bash random=$[$RANDOM%10] while true;do read -p "Please enter a int less than 10: " i if [ $i -eq $random ];then echo "bingo" break elif [ $i -gt $random ];then echo "greater" else echo "less" fi done
-
用檔名做為引數,統計所有引數檔案的總行數
#!/bin/bash sum=0 while [ $# -gt 0 ];do lines=`cat $1|wc -l` shift sum=$[$sum+$lines] done echo $sum
用二個以上的數字為引數,顯示其中的最大值和最小值
特殊用法
while
依次讀取/PATH/FROM/SOMEFILE檔案中的每一行,且將行賦值給變數xxx
while read xxx; do
迴圈體
done < /PATH/FROM/SOMEFILE
將COMMAND執行的結果依次讀取然後將每行依次賦值給變數xxx
COMMAND |while read xxx; do
迴圈體
done
掃描/etc/passwd檔案每一行,如發現GECOS欄位為空,則填充使用者名稱和單位電話為62985600,並提示該使用者的GECOS資訊修改成功
#!/bin/bash
while read line ;do
gecos=$(echo $line |cut -d: -f5)
if [ -z "$gecos" ];then
UserName=$(echo $line |cut -d: -f1)
usermod -c "$UserName 62985600" $UserName
echo "$UserName's gecos changed"
fi
done < /etc/passwd
找出分割槽利用率大於10%的分割槽
#!/bin/bash
df |grep /dev/sd |while read line;do
used=$(echo $line |tr -s " " % |cut -d% -f5)
name=$(echo $line |cut -d" " -f1)
if (( $used > 10 ));then
echo "$name will be full:$used%"
fi
done
for ((i=1;i<=100;i++));do
let sum+=i
done
echo sum=$sum
for
for ((控制變數初始化;條件判斷表示式;控制變數的修正表示式));do
迴圈體
done
select
主要用於建立選單,按數字順序排列的選單項將顯示在標準錯誤上,並顯示PS3 提示符,等待使用者輸入。使用者輸入選單列表中的某個數字,執行相應的命令。使用者輸入被儲存在內建變數REPLY中。常於case配合
select variable in list;do
迴圈體命令
done
設計點菜系統,列出主選單,選擇後選擇後,提示使用者,要選幾份,輸入完後提示是否還要繼續選,如繼續選,返回到主選單,然後繼續選,如不要繼續選,則會列印消費單後退出
#!/bin/bash
PS3="Please choose your food: "
echo > /tmp/list
echo "請問吃什麼"
getBill() {
for i in $(cat /tmp/list |cut -d: -f4|tr -d 元);do
let total+=i
done
echo -e "\n總計:${total}元" >> /tmp/list
cat /tmp/list
}
getCount() {
read -p "Please enter count(int): " count
sum=$[$(echo $price|cut -d: -f2)*$count]
echo "${price}元:${count}份:${sum}元" >> /tmp/list
while true;do
select ack in $*;do
case $REPLY in
1) break 2
;;
2) getBill
exit
;;
esac
done
done
}
getPrice() {
while true;do
select price in $*;do
case $REPLY in
1) echo $price;
getCount "繼續點菜" "結算"
break 3
;;
2) echo $price;
getCount "繼續點菜" "結算"
break 3
;;
3) echo $price;
getCount "繼續點菜" "結算"
break 3
;;
4) break 3;;
esac
done
done
}
while true;do
select menu in 飯 面 餃子 不吃 結算;do
case $REPLY in
1) getPrice "炒飯:10" "蓋飯:12" "木桶飯:15" "返回"
;;
2) getPrice "炒麵:15" "蓋面:16" "拉麵:10" "返回"
;;
3) getPrice "豬肉大蔥:20" "素三鮮:15" "韭菜雞蛋:18" "返回"
;;
4) exit
;;
5) getBill
exit
;;
esac
done
done
trap
訊號捕捉
trap '觸發指令' 訊號:自定義程式收到系統發出的指定訊號後,將執行觸發指令,而不會執行原操作
trap '' 訊號:忽略訊號的操作
trap '-' 訊號:恢復原訊號的操作
trap -p:列出自定義訊號操作
#!/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
函式
語法一
function f_name{
...函式體...
}
語法二
function f_name(){
...函式體...
}
語法三
f_name(){
...函式體...
}
返回值
預設預設取決於函式中執行的最後一條命令的退出狀態碼
也可以通過return自定義狀態碼,0表示無錯誤返回,1-255表示由錯誤返回
定義
互動式環境下定義
將函式放在指令碼檔案中作為它的一部分
可放在只包含函式的單獨檔案中
載入函式檔案
./source PATH/SOMEFILE:載入指定函式檔案
set function_name:檢查函式是否已載入當前shell
unset function_name:刪除當前shell中的此函式
分類
內部函式:變數僅對當前函式有效,local定義區域性變數
全域性函式:變數對當前shell有效,預設函式中的變數為全域性變數
環境函式:變數對當卡nshell及子shell有效,export -f/declare -xf定義全域性變數
引數
在函式體中當中,可使用$1, $2, ...呼叫這些引數;還可以使用$@, $*, $#等特殊變數
#!/bin/bash
func() {
echo func:1st is $1
echo func:2nd is $2
echo func:all are $*
echo func:the arg number is $#
echo func:the func name is $0
shift
echo func:1st is $1
}
func a b c d
陣列
宣告
預設定義陣列時,若不宣告陣列的型別,則設定為索引陣列,若不指定索引,則用0,1,2,3,4...
declare -a ARRAY_NAME:宣告數值索引陣列
declare -A ARRAY_NAME: 宣告關聯索引陣列,可以自定義索引格式
注意:兩者不可相互轉化
declare -a:顯示所有數值索引陣列
declare -A:顯示所有關聯索引陣列
[root@centos6 ~]# declare -A height=([zhangsan]=180 [lisi]=170 [wangwu]=158)
賦值
ARRAY_NAME[INDEX]=VALUE
ARRAY_NAME=(VAL1 VAL2 VAL3 ...)
ARRAY_NAME=([0]=VAL1 [3]=VAL2 ...)
read -a ARRAY
引用
${ARRAY_NAME[INDEX]}:引用陣列元素
${ARRAY_NAME[*]}:引用陣列所有元素
${#ARRAY_NAME[*]}:陣列的長度(陣列中元素的個數)
unset ARRAY[INDEX]:刪除陣列中的某元素,導致稀疏格式
unset ARRAY:刪除整個陣列
資料處理
${ARRAY[*]:offset:number}:陣列切片,offset表示要跳過的元素個數,number表示要取出的元素個數
ARRAY[${#ARRAY[*]}]=value:向陣列中追加元素
[root@centos6 ~]# declare -a|grep name
declare -a name='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")'
[root@centos6 ~]# echo ${name[*]:2:3}
3 4 5
示例
寫一指令碼會生成一個名為digit的陣列,包含10個隨機數,再顯示最大值,最小值
#!/bin/bash
getArr() {
for((i=0;i<$1;i++));do
random[$i]=$RANDOM
done
echo ${random[*]}
}
getMax() {
while [ $# -gt 0 ];do
if [ -z $max ];then
max=$1
else
[ $1 -gt $max ] && max=$1
fi
shift
done
echo $max
}
getArr 10
getMax ${random[*]}
#!/bin/bash
for i in {0..9}
do
array_random[$i]=$RANDOM
done
echo ${array_random[*]}
max_num() {
maxnum=${array_random[0]}
for i in {1..9}
do
if [ ${array_random[$i]} -gt $maxnum ];then
maxnum=${array_random[$i]}
fi
done
echo '最大值:' $maxnum
}
min_num() {
minnum=${array_random[0]}
for i in {1..9}
do
if [ ${array_random[$i]} -lt $minnum ];then
minnum=${array_random[$i]}
fi
done
echo '最小值:' $minnum
}
max_num
min_num
定義一個陣列,陣列中的元素是/var/log目錄下所有以.log結尾的檔案,並統計其下標為偶數的檔案中的行數之和
#!/bin/bash
arrLog=(/var/log/*.log)
for n in $(seq 0 $[${#arrLog[*]}-1]);do
if [ $[$n%2] -eq 0 ];then
echo ${arrLog[$n]}
let lines+=$(cat ${arrLog[$n]}|wc -l) # let lines+=$(wc -l < ${array[$i]})
fi
done
echo "lines: $lines"
練習
-
編寫函式,實現OS的版本判斷
#!/bin/bash judge_version() { version=$(cat /etc/redhat-release |sed -n "s/.* \([0-9]\)\..*/\1/p") [ $version == 6 ] && return 0 || return 1 } judge_version
-
編寫函式,實現取出當前系統eth0的IP地址
#!/bin/bash get_ipv4() { ip=$(ifconfig $1| sed -n "s/[[:space:]]\+inet addr:\([0-9\|.]\+\) .*/\1/p") return 0 } get_ipv4 eth0
-
編寫函式,實現列印綠色OK和紅色FAILED
#!/bin/bash . /etc/init.d/functions print_green_ok() { action $1 true } print_red_failed() { action $1 false } print_green_ok nihao print_red_failed nihao
-
編寫函式,實現判斷是否無位置引數,如無引數,提示錯誤
#!/bin/bash judge_arguments() { [ $1 == 0 ] && echo "Please enter arguments" } judge_arguments $#
-
編寫服務指令碼/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為當前指令碼名#!/bin/bash srv_name=$(basename $0) srv_find() { find /var/lock/subsys/$srv_name &> /dev/null } srv_echo() { echo "$srv_name is $1" } srv_start() { if srv_find;then srv_echo "running..." else touch /var/lock/subsys/$srv_name srv_echo "start" fi } srv_stop() { if srv_find;then rm -rf /var/lock/subsys/$srv_name srv_echo "stop" else src_echo "stopped..." fi } srv_restart() { if srv_find;then rm -rf /var/lock/subsys/$srv_name touch /var/lock/subsys/$srv_name else touch /var/lock/subsys/$srv_name fi srv_echo "restart" } srv_status() { srv_find && srv_echo "running..." || srv_echo "stopped..." } main() { case $1 in start) srv_start ;; stop) srv_stop ;; restart)srv_restart ;; status) srv_status ;; *) echo "Please enter a argument: start or stop or restart or status" exit ;; esac } main $1
-
編寫指令碼/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 get_path() { which $1|grep -o "/.*/$1$" } mkdir_all() { cd $2 for i in $(dirname $1|tr / ' ');do mkdir $i &> /dev/null cd $i done } cp_cmd() { mkdir_all $(get_path $1) $2 cp $(get_path $1) . for n in $(ldd $(get_path $1)|grep -o "/[^[:space:]]\+");do echo $n mkdir_all $n $2 p $n . done } while true;do read -p "Please enter a executable cmd name or quit: " cmd [ $cmd == quit ] && exit if $(which $cmd &> /dev/null);then cp_cmd $cmd /app/nihao else echo "Your answer is not a executable cmd" fi done
-
編寫函式實現兩個數字做為引數,返回最大值
#!/bin/bash get_max() { [ $1 -gt $2 ] && max=$1 || max=$2 [ $max -gt 255 ] && echo "Please enter a 0~255 int" || return $max } get_max $1 $2 echo $?
-
斐波那契數列又稱黃金分割數列,因數學家列昂納多·斐波那契以兔子繁殖為例子而引入,故又稱為“兔子數列”,指的是這樣一個數列:0、1、1、2、3、5、8、13、21、34、……,斐波納契數列以如下被以遞迴的方法定義:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2)
利用函式,求n階斐波那契數列
-
輸入若干個數值存入陣列中,採用冒泡演算法進行升序或降序排序
#!/bin/bash declare -A arr # 注意宣告位置,在函式內宣告就只作用在函式內 get_arr() { for n in $(seq 1 $1);do index=$RANDOM arr[$index]=$index done echo ${arr[*]} } get_sort() { while [ ${#arr[*]} -gt 1 ];do max=0 for i in ${arr[*]};do # 注意刪除元素後其他元素的索引不變 [ $i -gt $max ] && max=$i done echo $max unset arr[$max] done echo ${arr[*]} } get_arr 10 get_sort
將下圖所示,實現轉置矩陣matrix.sh,將列轉換成行顯示
1 2 3 1 4 7
4 5 6 ===> 2 5 8
7 8 9 3 6 9
#!/bin/bash
get_matrix() {
for i in $(seq 1 $1);do
for j in $(seq 1 $2);do
eval "arr$i[$j]=$[$RANDOM%10]"
done
eval echo "\${arr$i[*]}"
done
}
trans_matrix() {
for m in $(seq 1 $2);do
for n in $(seq 1 $1);do
eval echo -n "\${arr$n[$m]}' '"
done
echo
done
}
get_matrix 3 6
echo
trans_matrix 3 6
高階字串
切片
${#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字元之間的所有字元
查詢替換
${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中的所有大寫字母轉換為小寫
高階變數
declare
宣告指定型別的變數,常用選項:
- -r:宣告或顯示只讀變數
- -i:宣告或顯示整數型變數
- -a:宣告或顯示索引陣列
- -A:宣告或顯示關聯陣列
- -f:顯示已定義的所有函式名
- -F:僅顯示已定義的所有函式名
- -x:宣告或顯示環境變數和函式
- -l:宣告變數為小寫字母
- -u:宣告變數為大寫字母
eval
eval命令將會首先掃描命令列進行所有的置換,然後再執行該命令。該命令適用於那些一次掃描無法實現其功能的變數.該命令對變數進行兩次掃描
eval tempvar=$$variable1
tempvar=${!variable1}
[root@server ~]# CMD=whoami
[root@server ~]# echo $CMD
whoami
[root@server ~]# eval $CMD
root
[root@server ~]# n=10
[root@server ~]# echo {0..$n}
{0..10}
[root@server ~]# eval echo {0..$n}
0 1 2 3 4 5 6 7 8 9 10
[root@server ~]# N=NAME
[root@server ~]# NAME=fanjie
[root@server ~]# N1=${!N}
[root@server ~]# echo $N1
wangxiaochun
[root@server ~]# eval N2=\$$N
[root@server ~]# echo $N2
fanjie
mktemp
建立並顯示臨時檔案,可避免衝突,常用選項:
- -d:建立並顯示臨時目錄
[root@centos6 ~]# mktemp /app/tempXX
mktemp: too few X's in template `/app/tempXX'
[root@centos6 ~]# mktemp /app/tempXXX
/app/tempmEL
[root@centos6 ~]# mktemp
/tmp/tmp.7ey38eMKh8
[root@centos6 ~]# mktemp -d /app/tempXXXXXXXX
/app/tempYb2pAQ7c
[root@centos6 ~]# mktemp -d
/tmp/tmp.HHoPgpEe4K
install
安裝複製檔案,可指定許可權屬主和屬組,install [OPTION]... SOURCE... DIRECTORY,常用選項:
- -T SOURCE DEST:單檔案
- -t DIRECTORY SOURCE
- -d DIRECTORY...:建立空目錄
- -m MODE:指定許可權,預設是755
- -o OWNER:指定屬主
- -g GROUP:指定陣列
[root@centos6 ~]# install -m 700 -o fanjie -g admins /etc/passwd /app/
[root@centos6 ~]# install –m 770 –d /testdir/installdir
expect
expect 是由Don Libes基於Tcl( Tool Command Language )語言開發的,主要應用於自動化互動式操作的場景,藉助Expect處理互動的命令,可以將互動過程如:ssh登入,ftp登入等寫在一個指令碼上,使之自動化完成。尤其適用於需要對多臺伺服器執行相同操作的環境中,可以大大提高系統管理人員的工作效率,常用選項:
- -c:從命令列執行expect指令碼,預設expect是互動地執行的
- -d:可以輸出輸出除錯資訊
expect中相關命令
spawn:啟動新的程式
send:用於向程式傳送字串
expect:從程式接收字串
interact:允許使用者互動
exp_continue:匹配多個字串在執行動作後加此命令
#!/usr/bin/expect
spawn scp /etc/fstab 192.168.8.100:/app
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send “magedu\n" }
}
expect eof
#!/usr/bin/expect
spawn ssh 192.168.8.100
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send “magedu\n" }
}
interact
#expect eof
#!/usr/bin/expect
set ip 192.168.8.100
set user root
set password magedu
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
interact
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
interact
#./ssh3.exp 192.168.8.100 root magedu
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "]#" { send "useradd haha\n" }
expect "]#" { send "echo magedu |passwd --stdin haha\n" }
send "exit\n"
expect eof
#./ssh4.exp 192.168.8.100 root magedu
#!/bin/bash
ip=$1
user=$2
password=$3
expect <<EOF
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "]#" { send "useradd hehe\n" }
expect "]#" { send "echo magedu |passwd --stdin hehe\n" }
expect "]#" { send "exit\n" }
expect eof
EOF
#./ssh5.sh 192.168.8.100 root magedu
相關文章
- shell程式設計,實戰高階進階教學程式設計
- 併發程式設計進階程式設計
- Shell程式設計程式設計
- 程式設計師的進階之路程式設計師
- Shell程式設計 --- Shell介紹程式設計
- shell程式設計五程式設計
- shell程式設計二程式設計
- Shell程式設計-shell變數1程式設計變數
- Go進階之網路程式設計Go程式設計
- iOS進階課程-Newsstand程式設計iOS程式設計
- 【Go進階—併發程式設計】ContextGo程式設計Context
- 【Go進階—併發程式設計】WaitGroupGo程式設計AI
- 【Go進階—併發程式設計】MutexGo程式設計Mutex
- Shell程式設計-02-Shell變數程式設計變數
- Linux之shell程式設計Linux程式設計
- Shell程式設計-基礎程式設計
- Shell程式設計-read命令程式設計
- shell 程式設計簡記程式設計
- Linux Shell程式設計(1)Linux程式設計
- Linux Shell程式設計(2)Linux程式設計
- shell程式設計基礎程式設計
- Shell 程式設計入門程式設計
- 初識shell程式設計程式設計
- spark學習筆記--進階程式設計Spark筆記程式設計
- Rust 程式設計影片教程(進階)——022 模式Rust程式設計模式
- Rust 程式設計影片教程(進階)——002 traitRust程式設計AI
- Python程式設計進階,常用8大技巧!Python程式設計
- Shell程式設計-11-子Shell和Shell巢狀程式設計巢狀
- 高階shell程式設計筆記(第三十三章 雜項)程式設計筆記
- Rust 程式設計影片教程(進階)——027_1 高階特性Rust程式設計
- Java-進階篇【網路程式設計】---09Java程式設計
- Rust 程式設計視訊教程(進階)——022 模式Rust程式設計模式
- Rust 程式設計視訊教程(進階)——002 traitRust程式設計AI
- 程式設計師的macOS系列:高效Alfred進階程式設計師MacAlfred
- Rust 程式設計影片教程(進階)——001 泛型Rust程式設計泛型
- Spring MVC 函數語言程式設計進階SpringMVC函數程式設計
- Shell程式設計——極簡教程程式設計
- shell程式設計–bash變數程式設計變數