shell 指令碼的講解 與應用
shell指令碼程式設計
作用:通過命令列解析的方式,自動執行設定好的程式或命令程式碼。(若將指令碼掛到定時任務中,就會自動在非工作時間裡自動觸發執行程式)
Shell指令碼檔案以“.sh”結尾
規範的Shell指令碼第一行會指出由哪個程式(直譯器)來執行指令碼中的內容。在linux bash程式設計中一般為:#!/bin/bash (表示該指令碼運用/bin/bash命令進行解析)
Shell的輸出用echo命令;
Python的輸出用print命令
執行指令碼的方式:
方法一:/bin/sh是bash的軟連結,也就是說我麼既可以用sh執行也可以用bash執行指令碼
# sh yunjisuan.sh
# bash yunjisuan.sh
方法二:以絕對路徑的方式執行指令碼(前提:將該指令碼新增x執行許可權 )
# chmod +x yunjisuan.sh
# /root/benet/yunjisuan.sh
方法三:以source指令碼路徑的方式執行指令碼(等同於“.指令碼路徑” )只在當前環境生效
# source yunjisuan.sh
# . yunjisuan.sh
方法四:以相對路徑的方式執行指令碼(前提:將該指令碼新增x執行許可權 )
# ./yunjisuan.sh
寫指令碼
(1)vim編輯yunjisuan.sh
(2)檢視yunjisuan.sh指令碼
(3)執行yunjisuan.sh指令碼
指令碼中書寫的命令必須是非互動式的命令!!!
雖然指令碼可以自動化執行,但指令碼不會判斷命令是否執行成功,因此需要進行邏輯判斷
方法一:
test命令
判斷該字串表示為檔案還是目錄
-d 測試是否為目錄
-e 測試目錄或檔案是否存在
-f 測試是否為檔案
-l 測試是否為連結檔案
-r 測試當前使用者是否可讀
-w 測試當前使用者是否可寫
-x 測試當前使用者是否可執行
-s 測試檔案大小非0時為真(若為非空檔案,則為真)
-u 測試是否具有SUID屬性
-g 測試是否具有SGID屬性
-k 測試是否具有sticky bit 粘滯位屬性
-z 測試字串是否為空(zero)
file1 -nt file2測試第一個檔案是否比第二個檔案新(new then)
file1 -ot file2 測試第一個檔案是否比第二個檔案舊(old then)
file1 -ef file2 測試第一個檔案是否與第二個檔案為同一個檔案(link之類的檔案)
# test -d 目標路徑
# echo $?判斷是否是目錄,若顯示0表示真(是目錄),若顯示非0則假(不是目錄)
# test -f 目標路徑
判斷目標是不是檔案
# echo $?
$?返回值參考
0 表示執行成功
2 許可權拒絕
1~125 表示執行失敗,指令碼命令,系統命令錯誤或引數傳遞錯誤;
126 找到該命令,但無法執行
127 未找到要執行的命令
128 命令被系統強制結束
方法二:
使用“[]”,表示開啟判斷條件(“[]”兩邊須有空格)
# xx=”welcome”
# [ $xx == welcome] && echo “0” || echo “1”
0
“[]”應用於整數 (格式:整數1 操作符 整數2)
-gt(great than)表示大於
-lt(less than)表示小於
-eq(equal)表示等於
-ne (not equal)表示不等於
-ge 表示大於等於
-le表示小於等於
&& 邏輯與,表示前一指令為真,執行後一指令,否則不執行
|| 邏輯或,表示前一指令為假,執行後一指令,否則不執行
# xx=”44”
# if [ -f "$file1" ];then echo 1;else echo 0;fi
相當於# [ -f "file1" ] && echo 1 ||echo 0
# [ $xx -eq 34 ] && echo “0” || echo “1”
1
字串測試
[ -z “字串” ] 字串內容為空
[ -n “字串” ] 字串內容不為空
${#變數名} 求變數的字串位數,判斷字串是否為空
# xx=”123411”
# echo ${#xx}
6
# xx=””
# echo ${#xx}
0
指令碼的互動式輸出模式
方法一:
執行指令碼過程中,存在需要使用者輸入內容的情況,通過read命令進行互動式輸入
添加註釋給使用者:
輸入格式:read -p “文字提示” 變數名
輸0出格式:echo $變數名
建立使用者名稱和密碼
#!/bin/bash
User="yunjisuan"
Passwd="123456"
read -p "請輸入使用者名稱" user
read -p "請輸入密碼" passwd
[ $User -eq $user ] && echo "YOU ARE RIGHT" || echo “YOU ARE WRONG”
[ $Passwd -eq $user ] && echo "YOU ARE RIGHT" || echo "YOU ARE WRONG"
邏輯測試
“[]”中,-a(&&) 表示並且;
-o (||)表示或者
!邏輯否
方法二:通過引數傳遞的方式進行互動式輸入
/etc/init.d/ 服務啟動指令碼
服務啟動指令碼/etc/init.d/後面寫的內容就是引數,通過這個引數進行互動式輸入
$# 表示指令碼要處理的的引數個數
$? 表示命令或指令碼執行狀態碼
$* 表示橫向羅列指令碼要處理的所有引數(把所有引數視為整體)
[email protected] 表示橫向羅列指令碼要處理的所有引數(把所有引數視為單個引數的組合)
$0 表示指令碼檔案的絕對路徑或相對路徑(指令碼檔案的執行路徑)
$1 第一個引數
$n 第n個引數
指令碼中反引號“``”、“$()”的應用
變數的算數運算
變數的數值運算多用於指令碼程式的過程控制,只能進行簡單的整數運算,不支援小數運算,整數值得運算主要通過內部命令expr進行。
# x=11
# y=22
# expr $x \* $y
格式: expr 變數1 運算子 變數2...
++ -- 增加及減少,可前置也可放在結尾
! ~ 一元運算的正負號,非,邏輯與位的取反
\* 乘法
/ 除法
% 取餘
** 冪運算
+ 加法
- 減法
<; <=;>; >= 比較符號
== 1+= 相等,不相等
<< 向左移動
>> 向右移動
>>> 填0右移
& 位的與AND
^ 位的異或
| 位的或
&& 位的AND
|| 位的OR
?: 條件表示式
=; += ;-= ;*=等 賦值運算子
(())用法(常用於簡單的整數運算)
“(())”在命令列執行時不需要$符號,但是輸出需要$符號
“(())”裡所有字元之間有無或多個空格沒有任何影響
# b=$((1+2**3-4%3))
# echo $b
8
# echo $((1+2**3-4%3))
8
a++,a--,++a,--a區別
變數a在前,表示式的值為a,然後a自增或自減,變數a在符號後,表示式值自增或自減,然後a值自增或自減。
# a=8
# echo $a
8(a賦值為8)
# echo $((a+=1)) #相當於a=a+1
9(a賦值為a+1=9)
# echo $((a++)) #a在前,先輸出a的值,在加1
9(a賦值為上一值a為9)
# echo $a
10(a賦值上一值的9++,9+1為10)
# echo $((a--))
10(a取上一值a為10)
# echo $a
9(a取上一值10--,10-1為9)
# echo $((++a))
10(先+1,在取上一值9,1+9=10)
# echo $a
10(取上一值10)
# echo $((--a))
9(先-1,取上一值10,10-1=9)
# echo $a
9(取上一值9)
Shell指令碼中不支援“i++”表達,可以用C語言的((i++))在shell中表示
或者“let h++”
If條件語句
格式(fi 表示結束)
(一)單分支條件判斷語句
(1)
if 條件1
then
動作1
else
動作2
fi
(2)(用;分隔)
if 條件1;then
動作1
else
動作2
fi
在vim中編輯yunjisuan.sh指令碼
#!/bin/bash
read -p "請輸入一個數字:" num
if [ $num == 60 ];then
echo "猜對了"
fi
# sh yunjisuan.sh
請輸入一個數字:60
猜對了
在vim中編輯yunjisuan.sh指令碼
#!/bin/bash
read -p "請輸入一個數字:" num
if [ $num == 60 ];then
echo "猜對了"
else
echo "猜錯了"
fi
# sh yunjisuan.sh
請輸入一個數字:45
猜錯了
(二)多分支條件判斷語句(elif就是else if)
if 條件1;then
動作1
elif 條件2;then
動作2
else
動作3
fi
檢視當前檔案的絕對目錄
# dirname 目標檔案的絕對路徑
檢視當前檔案的基本檔名稱
# basename 目標檔案的絕對路徑
自定義搭建本地yum倉庫指令碼
(1)移除光碟,再掛載
(2)判斷光碟掛載
(3)掛載本地yum倉庫指令碼
(4)判斷一級目錄、二級目錄是否存在
(5)配置檔案手動生成,避免之前被修改過(重定向或echo -e)
#!/bin/bash
umount /dev/sr0&>/dev/null
[ -d /media/cdrom ]|| mkdir -p /media/cdrom(還可以用test和if的方法)
mount /dev/sr0 /media/cdrom &>/dev/null
if [ $? -ne 0 ];then
echo "請插入光碟"
exit
fi
[ -d /etc/yum.repos.d ] || mkdir -p /etc/yum.repos.d
cd /etc/yum.repos.d
mv * /tmp/
echo -e “[local]\nname=local\nbaseurl=file:///media/cdrom/\ngpgcheck=0\nenabled=1”>/etc/
yum.repos.d/localyum.repo
(或)
cat > /etc/yum.repos.d/localyum.repo << FOF
[local]
name=local
baseurl=file:///media/cdrom
gpgcheck=0
enabled=1
F0F
yum -y clean all &>/dev/null
yum makecache &>/dev/null
[ $? -eq 0 ] && echo "yum倉庫搭建完畢" || echo "快取建立失敗!"
配置檔案手動生成
用指令碼手動生成配置檔案,一般用重定向
輸入重定向通過FOF標識(任意定義,但成對出現),將FOF之間的內容輸入重定向到cat,cat再輸出重定向給/etc/yum.repos.d/yum/repo檔案
while迴圈語句
格式:
while 條件
do
迴圈體(指令)
done
休息命令:sleep 1 休息1秒,usleep 1000000 休息1秒,單位微妙
從1到100求和
#!/bin/bash
i=1
sum=0
while [ $i -lt 100 ]
do
((sum=sum+i))
((i++))
done
echo $sum
守護程序
#!/bin/bash
while true
do
uptime >> /var/log/uptime.log
sleep 2
done
倒計時
#!/bin/bash
i=10
while [ $i -gt 0 ]
do
echo $i
((i--))
done
無限迴圈
(1)
#!/bin/bash
read -p "輸入:" i
while [ $i -gt 0 ]
do
echo $i
let i++
done
(2)
#!/bin/bash
read -p "輸入:" i
while :
do
echo $i
let i++
done
強行中止
# exit
防止指令碼執行中斷的方法
1)sh while01.sh & #放在後臺執行
2)screen 分離 ctrl+a+d 檢視screen -ls進入screen -r num
3)nohup while01.sh &
for迴圈語句
格式:
for 變數名 in 變數取值列表
do
迴圈體(指令)
done
示例:迴圈
for ((i=0;i<10:i++))
do
echo $i
done
列印列表元素
for的三種輸出方式
(1)
#!/bin/bash
for i in 1 2 3 4 5
do
echo $i
done
(2)
#!/bin/bash
for i in {1..5}
do
echo $i
done
(3)
#!/bin/bash
for i in `seq 5`
do
echo $i
done
#!/bin/bash
h=0
for i in {1..10}
do
echo $h
let h++
done
開機啟動項優化
#!/bin/bash
for i in `chkconfig | grep "3:on" | awk '{print $1}'`
do
chkconfig $i off
done
if [ -e sysstat ]
then echo "sysstat exit"
else mkdir -p /media/cdrom
mount /dev/sr0 /media/cdrom
if [ $? -ne 0 ];then
echo "FAILED"
exit
else yum -y install sysstat
if [ $? -ne 0 ];then
echo "install error"
exit
else echo "install successed"
fi
fi
fi
for h in sshd network crond rsyslog sysstat
do
chkconfig $h on
done
[ $? == 0 ]&& echo "successed" || echo "failed"
在/yunjisuan目錄批量建立檔案
#!/bin/bash
Path=/yunjisuan
[ -d "$Path" ] || mkdir -p $Path
for i in `seq 10`
do
touch $Path/yunjisuan_$i.html
done
批量改名
#!/bin/bash
Path=/yunjisuan
[ -d "$Path" ] || mkdir -p $Path
for file in `ls $Path`
do
mv $Path/$file "$Path/"`echo $file | sed -r 's#yunjisuan(.*).html#linux\1.HTML#g'`
done
批量建立使用者並設定密碼
#!/bin/bash
User=yunjisuan
Path=/tmp
for user in ${User}{01..10}
do
useradd $user > /dev/null 2>&1
if [ $user -ne 0 ];then
echo "$user created failed"
echo "scripts begin to rollback"
for i in ${User}{01..10}
do
userder -r $i >/dev/null 2>&1
[ $? -eq 0 ] || exit 1
done
echo >$Path/usr_passwd
exit 1
else
passWD=`echo $RANDOM | md5sum | cut -c1-8` (表示取一大串隨機數,從這串隨機數前擷取1-8位)
[ -d $Path ] || mkdir $Path
echo $passWD | passwd --stdin $user
echo "$user:$passWD">> $Path/user_passwd
fi
done
exit 0 表示正常執行程式並退出程式
exit 1 或exit -1 表示非正常執行導致退出程式
echo -n 不換行
獲取當前目錄下的目錄名做為變數列表列印輸出
#!/bin/bash
Path=`pwd`
echo $Path
for filename in `ls`
do
[ -d ${Path}/${filename} ] && echo $filename
done
九九乘法表
#!/bin/bash
for ((i=1;i<10;i++))
do
for ((j=1;j<=i;j++))
do
echo -n "$j * $j =$((i*j))"
echo -n " "
done
echo " "
done
顯示出1-100的偶數
#!/bin/bash
for i in {1..100}
do
[ $(($i%2)) -eq 0 ] && echo $i
done
顯示出1000-2000的質數
#!/bin/bash
for i in {1000..2000}
do
[ $(factor $i | awk '{print NF}') -le 2 ] && echo $i
done
factor命令:分解因數
Case語句
用途:選單;啟動指令碼
case語句適合變數的值少,且為固定的數字或字串集合。 系統服務啟動指令碼傳參的判斷多用case語句
格式:
case "字串變數" in
值1)
指令1
;;
值2)
指令2
;;
*)
指令
esac
注意:case語句相當於一個if的多分支結構語句
值1的選項
apple)
echo -e "@RED_COLOR apple $RES"
;;
也可以這樣寫,輸入2種格式找同一個選項
apple|APPLE)
echo -e "$RED_COLOR apple $RES"
;;
服務指令碼框架
#!/bin/bash
. /etc/init.d/functions
case $1 in
start)
action "服務開始啟動" /bin/true
;;
stop)
action "服務準備停止" /bin/false
;;
restart)
action "服務準備停止" /bin/true
action "服務來時啟動" /bin/true
;;
*)
echo "請輸入正確引數"
;;
esac
在當前指令碼引用函式庫(絕對路徑)
Function對應的是action “ ” 路徑
/bin/true 表示一個標誌
設定指令碼配置啟動級別
(1)為指令碼設定啟動級別
將指令碼複製到/etc/init.d/下,vim編輯/etc/init.d/cash.sh指令碼
# chkconfig: 35 90 10
(2)在chkconfig中新增指令碼
# chkconfig --add case.sh
# chkconfig --list case.sh
(3)設定關閉cash.sh
# chkconfig case.sh off
Shell函式
不論什麼程式語言,基本只有三種程式設計的方法(指如何去編寫程式碼的方法論)
1、面向過程
2、面向物件
3、函數語言程式設計
在shell語言中,只能支援面向過程這種程式設計方法。
在shell中,function表示函式(function、return可以不寫)
格式:
function 函式名(){
命令序列
[return x]
}
函式名
函式體只有被呼叫時才會啟動,若要重複啟動該函式,只需將函式名重複n遍
原始碼編譯示意
獲取隨機數的幾種方法
(1)通過系統環境變數$RANDOM
# echo $RANDOM
6178
# echo $RANDOM
30890
# echo $((RANDOM%9)) #輸出0~9之間隨機數
2
# echo $((RANDOM%9))
# echo $((RANDOM%9))$((RANDOM%9)) #輸出00~99 隨機數
64
# echo $RANDOM|md5sum #隨機數長短不一,可以用md5sum命令統一格式化
599e328a94329684ce5c92b850d32f26 -
(2)通過openssl產生
# openssl rand -base64 8
aND8WMRM6vQ=
# openssl rand -base64 8
RsRdRq/9vi4=
# openssl rand -base64 8|md5sum
b1108cafbc2291392e41d2c914360138 -
# openssl rand -base64 10
1frkA2kIJODxqQ==
(3)通過時間獲得隨機數(date命令詳解見下頁文件)
# echo $(date +%N)
361599138
# echo $(date +%t%N)
950526316
(4)Urandom
# head /dev/urandom | cksum
621330951 2535
# head /dev/urandom | cksum
404398617 2470
(5)UUID
# cat /proc/sys/kernel/random/uuid
8a6c5bbe-2d42-44ac-9ef1-3e7683a613e3
# cat /proc/sys/kernel/random/uuid
c828c209-5b5f-4bc7-917c-678ed4215988
# uuidgen
961dc354-81b2-4564-9b85-6095ed4bc7b5
迴圈控制語句break、continue、exit、return
作用:用於迴圈結構中控制迴圈語句
break n:n表示跳出迴圈的層數,如果省略n表示跳出整個迴圈(只跳出所在位置的迴圈)
continue n:n表示退出到第n層繼續迴圈,如果省略n表示跳過本次迴圈,忽略本次迴圈剩餘程式碼,進入迴圈的下一次迴圈exit n:退出當前shell程式,n為返回值,n也可以省略,在下一個shell裡通過$?接收這個n值
return n:用在函式裡,做為函式的返回值,用於判斷函式執行是否正確。和exit一樣,如果函式裡有迴圈,也會直接退出迴圈,退出函式
break n:n表示跳出迴圈的層數,如果省略n表示跳出整個迴圈
#!/bin/bash
for ((i=0;i<=5;i++))
do
[ $i -eq 3 ] && break
echo $i
done
echo "ok"
break只跳出所在位置的一個整個迴圈迴圈
continue n:n表示退出到第n層繼續迴圈,如果省略n表示跳過本次迴圈,忽略本次迴圈剩餘程式碼,進入迴圈的下一次迴圈
#!/bin/bash
for ((i=0;i<=5;i++))
do
[ $i -eq 3 ] && continue
echo $i
done
echo "ok"
exit n:退出當前shell程式,n為返回值,n也可以省略,在下一個shell裡通過$?接收這個n值
#!/bin/bash
for ((i=0;i<=5;i++))
do
[ $i -eq 3 ] && exit 2
echo $i
done
echo "ok"
return n:用在函式裡,做為函式的返回值,用於判斷函式執行是否正確。和exit一樣,如果函式裡有迴圈,也會直接退出迴圈,退出函式
#!/bin/bash
function xxx() {
for ((i=0;i<=5;i++))
do
[ $i -eq 3 ] && return 7
echo $i
done
echo "ok"
}
xxx
echo $?
shell指令碼的除錯
(1)使用dos2unix處理指令碼
從windows編輯的指令碼到Linux下需要使用這個命令
dos2unix windows.sh
(2)使用echo命令除錯
在變數讀取或修改的前後假如echo $變數,也可在後面使用exit退出指令碼,這樣可以不用註釋後邊程式碼
(3)利用bash的引數除錯
sh [-nvx]
-n:不會執行該指令碼,僅查詢指令碼語法是否有問題,並給出錯誤提示。可用於生產伺服器那些只能執行一次不可逆的指令碼。
-v:在執行指令碼時,先將指令碼的內容輸出到螢幕上然後執行指令碼,如果有錯誤,也會給出錯誤提示。(一般不用)
-x:將執行的指令碼內容及輸出顯示到螢幕上,常用
1)要記得首先用dos2unix對指令碼格式化
2)直接執行指令碼根據報錯來除錯,有時報錯不準確。
3)sh -x除錯整個指令碼,顯示執行過程。
4)set -x和set +x除錯部分指令碼(在指令碼中設定)
5)echo輸出變數及相關內容,然後緊跟著exit退出,不執行後面程式的方式,一步步跟蹤指令碼,對於邏輯錯誤比較好用。
ping -c 1 ip地址
-c ping的次數 -i 每次ping的間隔時間 -w deadline時間
#!/bin/bash
for ip in 192.168.214.{1..254}
do
ping -c 1 $ip &> /dev/null
if [$? -eq 0 ];then
echo "$ip正常狀態"
fi
done
date命令
作用:用來顯示或設定系統的日期與時間。
引數
-d<字串>:顯示字串所指的日期與時間。字串前後必須加上雙引號;
-s<字串>:根據字串來設定日期與時間。字串前後必須加上雙引號;
-u:顯示GMT; --help:線上幫助; --version:顯示版本資訊。
%H 小時(以00-23來表示)
%I 小時(以01-12來表示)
%K 小時(以0-23來表示)
%l 小時(以0-12來表示)
%M 分鐘(以00-59來表示)
%P AM或PM
%r 時間(含時分秒,小時以12小時AM/PM來表示)
%s 總秒數。起算時間為1970-01-01 00:00:00 UTC
%S 秒(以本地的慣用法來表示)。
%T 時間(含時分秒,小時以24小時制來表示)
%X 時間(以本地的慣用法來表示)
%Z 市區
%a 星期的縮寫
%A 星期的完整名稱
%b 月份英文名的縮寫
%B 月份的完整英文名稱
%c 日期與時間,只輸入date指令也會顯示同樣的結果
%d 日期(以01-31來表示)
%D 日期(含年月日)
%j 該年中的第幾天
%m 月份(以01-12來表示)
%U 該年中的週數
%w 該周的天數,0代表週日,1代表週一,以此類推
%x 日期(以本地的慣用法來表示)
%y 年份(以00-99來表示)
%Y 年份(以四位數來表示)
%n 在顯示時,插入新的一行
%t 在顯示時,插入tab
MM 月份(必要)
DD 日期(必要)
hh 小時(必要)
mm 分鐘(必要)
ss 秒(選擇性)
例項
格式化輸出:
date +"%Y-%m-%d"
2015-12-07
輸出昨天日期:
date -d "1 day ago" +"%Y-%m-%d"
2015-11-19
2秒後輸出:
date -d "2 second" +"%Y-%m-%d %H:%M.%S"
2015-11-20 14:21.31
傳說中的 1234567890 秒:
date -d "1970-01-01 1234567890 seconds" +"%Y-%m-%d %H:%m:%S"
2009-02-13 23:02:30
普通轉格式:
date -d "2009-12-12" +"%Y/%m/%d %H:%M.%S"
2009/12/12 00:00.00
apache格式轉換:
date -d "Dec 5, 2009 12:00:37 AM" +"%Y-%m-%d %H:%M.%S"
2009-12-05 00:00.37
格式轉換後時間:
date -d "Dec 5, 2009 12:00:37 AM 2 year ago" +"%Y-%m-%d %H:%M.%S"
2007-12-05 00:00.37
加減操作:
date +%Y%m%d #顯示前天年月日
date -d "+1 day" +%Y%m%d #顯示前一天的日期
date -d "-1 day" +%Y%m%d #顯示後一天的日期
date -d "-1 month" +%Y%m%d #顯示上一月的日期
date -d "+1 month" +%Y%m%d #顯示下一月的日期
date -d "-1 year" +%Y%m%d #顯示前一年的日期
date -d "+1 year" +%Y%m%d #顯示下一年的日期
設定時間:
date -s #設定當前時間,只有root許可權才能設定,其他只能檢視
date -s 20120523 #設定成20120523,這樣會把具體時間設定成空00:00:00
date -s 01:01:01 #設定具體時間,不會對日期做更改
date -s "01:01:01 2012-05-23" #這樣可以設定全部時間
date -s "01:01:01 20120523" #這樣可以設定全部時間
date -s "2012-05-23 01:01:01" #這樣可以設定全部時間
date -s "20120523 01:01:01" #這樣可以設定全部時間
檢查一組命令花費的時間:
#!/bin/bash
start=$(date +%s)
nmap man.linuxde.net &> /dev/null end=$(date +%s)
difference=$(( end - start ))
echo $difference seconds.
#!/bin/bash
User1=daisy
Passwd1=123456
User2=helen
Passwd2=123123
lock=""
Passwd1=123456
User2=helen
#!/bin/bash
User1=daisy
Passwd1=123456
User2=helen
Passwd2=123123
lock=""
while :
do
read -p "請輸入使用者名稱:" num
echo "$lock" | grep -w "$num"
if [ $? -eq 0 ];then
echo "使用者鎖定"
continue
fi
User1=daisy
Passwd1=123456
User2=helen
Passwd2=123123
lock=""
while :
do
read -p "請輸入使用者名稱:" num
echo "$lock" | grep -w "$num"
if [ $? -eq 0 ];then
echo "使用者鎖定"
continue
fi
if [ $num != $User1 -a $num !=$User2 ];then
echo "請輸入使用者名稱有誤"
else
i=0
while :
do
read -p "請輸入密碼:" passwd
if [ $Passwd1 == $passwd -a $num == $User1 ];then
echo "密碼正確"
exit
elif [ $Passwd2 == $passwd -a $num == $User2 ];then
echo "密碼正確"
exit
else
let i++
if [ $i -eq 3 ];then
echo "密碼錯誤達3次,已鎖定"
lock=$lock" $num"
break
echo "請使用未鎖定賬號登入"
fi
echo "密碼輸入錯誤"
fi
done
fi
done