shell腳本

1/81
shell
shell變量
shell的變量
常量 固定的字符或字符串 不能變 所有被賦值的字符串都被稱爲常量
= 賦值符號
變量 值可以發生變化
y=123 變量賦值,把=右邊的內容賦值到等號左邊
變量名稱:只能由字母、數字和下劃線組成 不能以數字開頭 見名知意(變量就是會變化的量)
變量的類型:
1.自定義變量
2.環境變量
3.位置變量
4.特殊變量 預定義變量
說明:shell腳本中定義變量是無需指定變量類型的。shell腳本中的變量類型有變量的值來決定。如果值是
數字,其類型自動識別成"整型";如果值用" "雙引號、字母就自動識別成字符型。
C、java、數據庫中常見的變量類型有整型int、浮點型float、字符型char等。
1.自定義變量 局部變量
定義變量?
變量名=變量的內容

a=80

只對當前shell生效
子shell不生效
如何引用變量?

echo $a

查看所有變量(包含自定義變量和環境變量)
#set
取消變量?

unset a

完成整測試:a=80 ; echo $a ; unset a ; echo $a
2.環境變量 也稱作全局(global)變量
用來指定操作系統運行環境的一些參數
在父shell裏面設置的變量在他的子shell裏面生效的話,說明這個變量擁有繼承性,我們可以把擁有繼承性
的變量稱爲環境變量,環境變量都可以在env查看到
2/81
查看環境變量
env
常用的環境變量(環境變量名通常用大寫字母) 輸出環境變量的值: echo $HOSTNAME
HOSTNAME=client.qf.com //表示當前主機名
SHELL=/bin/bash //表示當前shell的類型
HISTSIZE=1000 //表示當前歷史記錄的條數
USER=root //表示當前登陸的用戶
PWD=/root //表示當前路徑
LANG=zh_CN.UTF-8 //表示當前使用的語言
HOME=/root //表示當前用戶的家目錄
PS1='[\u@\h \W]\$ ' //表示一級提示符
PS2='> ' //表示二級提示符
UID=0 //表示當前用戶的uid
MAIL=/var/spool/mail/root //表示當前用戶的郵箱位置
PATH=/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin 以:分
隔 存放命令的目錄 表示使用命令不需要加路徑使用 凡是在path路徑下的命令可以在任何路徑下執行

echo $RANDOM //產生0-32767的隨機數

31888

echo $(($RANDOM%10)) //產生0-9的隨機數

echo $(($RANDOM%100+1)) //產生0-100的隨機數

練習A:採用 命令的邏輯執行功能顯示當前用戶的身份判斷,判斷,如果uid的值爲0時就提示'root user',
否則提示'not root user'。腳本中要用UID這個環境變量。
[ $UID -eq 0 ] && echo 'root user.'
echo 'not root user.'
練習B:採用 命令的邏輯執行功能顯示當前用戶的身份判斷,如果USER的值爲root時就提示'root user',否
則提示'not root user'。腳本中要用USER這個環境變量。
[ $USER == "root" ] && echo 'root user.'
echo 'not root user.'
PATH環境變量:作用是記錄系統查找命令文件默認路徑的變量。在windows、Linux中都有PATH環境變
量。當用戶輸入某個命令回車後,系統會自動到當前目錄和PATH環境變量所設置的目錄下查找這個命令文
件,如果有此命令,就執行,否則提示"未找到命令...".
例:執行如下操作,熟悉PATH環境變量的功能。
echo $PATH
lsblk
xxx
AP=$PATH
echo $AP
PATH=/:/etc 臨時修改PATH環境變量的值爲/、/etc目錄
lsblk 提示“未找到命令...”
exit
重新登錄,再次執行lsblk看結果。
win7/10的cmd命令行查看PATH環境變量的值:
echo %PATH%
修改PATH 用:隔開
PATH=$PATH:/命令所在目錄的路徑
安裝apache軟件
3/81
apachectl 命令所在位置/usr/local/bin/apachectl
想在系統任意位置使用apachectl
兩種方法
1.將/usr/local/apachectl命令拷貝到/bin PATH定義的目錄下
2.設置環境變量
臨時設置
1)PATH=$PATH:/usr/local/apache/bin 自定義變量
export PATH 把自定義變量轉爲環境變量
2)export PATH=$PATH:/usr/local/apache/bin 直接設置環境變量
永久設置 寫到4個環境變量的配置文件(shell 腳本) 開機電腦自動讀取配置文件內容
/etc/profile
/etc/bashrc
~/.bash_profile
~/.bashrc
適用範圍
/etc 對所有用戶生效
~/ 對當前用戶生效
登陸shell的類型
登陸shell 4個環境變量的配置都讀 敲了登陸用戶名就是登陸shell
非登陸shell 只讀2個bashrc文件 沒有就是非登陸
例1:
[root@client Desktop]# url=www.baidu.com.cn
[root@client Desktop]# vim test.sh
#!/bin/bash
#test 自定義變量和環境變量的作用範圍
echo $url
echo $USER
echo $UID
echo $SHELL
測試:
[root@client Desktop]# bash test.sh
root
0
/bin/bash
[root@client Desktop]# . test.sh
www.baidu.com.cn
root
0
/bin/bash
例2:
[root@client Desktop]# vim test.sh
#!/bin/bash
#test 自定義變量和環境變量的作用範圍
export url=www.baidu.com.cn
echo $url
echo $USER
4/81
echo $UID
echo $SHELL
測試:
[root@client Desktop]# bash test.sh
www.baidu.com.cn
root
0
/bin/bash
[root@client Desktop]# . test.sh
www.baidu.com.cn
root
0
/bin/bash
3.位置變量,也稱位置參數
作用:是將命令執行是輸入的某個值傳遞到腳本內部使用,腳本內部用$1~${n}來接收這些參數。
$1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11}……
例3:
[root@client Desktop]# vim test.sh
#!/bin/bash
echo "歡迎使用$0腳本"
echo "第1個位置參數是$1"
echo "第2個位置參數是$2"
echo "第3個位置參數是$3"
echo "第4個位置參數是$4"
echo "第5個位置參數是$5"
echo "第6個位置參數是$6"
echo "第7個位置參數是$7"
echo "第8個位置參數是$8"
echo "第9個位置參數是$9"
echo "第10個位置參數是${10}"
echo "$0運行時的位置參數有$@"
echo "$0運行時的位置參數有$"
echo "$0腳本的PID是$$"
echo "$0腳本運行時的位置參數共$#個"
測試:
[root@client Desktop]# bash test.sh sdf qq dd ccc dsd dhjg 66 55 44 33 22 11 00
練習:編寫一個名稱爲/sh/add_users.sh的腳本,要求用 add_users.sh tom jack lucy的方式運行腳
本,在腳本中使用位置變量$@來接收用戶名tom jack lucy信息,批量創建這3個用戶,並查詢用戶的id
信息。
vim /sh/add_users.sh 腳本內容如下
#!/bin/bash
echo $@
for i in $@
do
useradd $i
id $i
done
5/81
#以調試方式運行腳本:
sh -x add_users.sh tom jack lucy
例:用read命令的-a數組選項來實現輸入多個用戶名,用for循環批量創建這些用戶。
#!/bin/bash
read -p '請輸入多個用戶名:' -a USERS
echo "您輸入了${#USERS[@]} 個用戶名:${USERS[@]}"
for i in ${USERS[@]}
do
useradd $i
id $i
done
4.預定義變量(必須記住)
$? 上一個命令的返回值 0 正確執行 非0都是錯誤執行
$0 腳本名
$$ 當前進程的PID
$
所有的參數 $@
$# 參數的個數
[root@client Desktop]# echo $$ //查看當前shell的進程號
3424
影響bash shell的其他文件
bash登陸和歡迎信息(通常用於打廣告)
/etc/issue 登陸前顯示的信息(本地登陸) ctrl alt f2
/etc/issue.net 登陸前顯示的信息(網絡登陸)
/etc/motd 登陸後顯示的信息
例0:修改本地登錄前顯示的信息。
[root@client Desktop]# vim /etc/issue 在文件最後添加如下內容
welcome to qf edu.
然後,到虛擬機裏面的界面用exit退出登錄,看登錄提示界面是否多了'welcome to qf edu.'內容。
例1:修改網絡登錄前顯示的信息。
[root@client Desktop]# vim /etc/ssh/sshd_config 在文件最後添加如下內容
Banner /etc/issue.net
[root@client Desktop]# systemctl restart sshd 或 service sshd restart
[root@client Desktop]# vim /etc/issue.net
Red Hat Enterprise Linux Server release 7.6 (Santiago)
Kernel \r on an \m
fei root yonghu jinzhi denglu 添加此行內容即可
測試
[root@today ~]# ssh 192.168.11.11
Red Hat Enterprise Linux Server release 7.6(Santiago)
Kernel \r on an \m
fei root yonghu jinzhi denglu
[email protected]'s password:
6/81
例2:
[root@client ~]# cat /etc/motd
+-------------------------------+
你當前登陸的是網站服務器!
小心你的操作
+-------------------------------+
測試:
[root@today ~]# ssh 192.168.11.11
[email protected]'s password:
Last login: Thu Apr 27 12:00:16 2017 from 192.168.11.11
+-------------------------------+

你當前登陸的是網站服務器!
小心你的操作

+-------------------------------+
變量的定義方式:
1.顯示賦值
變量名=變量內容
示例:
IPADDR=192.168.1.251
school="Hangzhou qianfeng"
today=date +%F //`和$() 叫做命令替換(命令替換) <br/>[root@client ~]# today=date +%F`
[root@client ~]# echo $today
2017-06-08
[root@client ~]# jintian=$(date +%F)
[root@client ~]# echo $jintian
2017-06-08
2.read 從鍵盤讀入變量值
read -p "提示信息:" 變量名
[root@client ~]# read -p "請輸入銀行卡帳號:" num
請輸入銀行卡帳號:4445555666
[root@client ~]# echo $num
4445555666
[root@client ~]# read -p "請輸入銀行卡密碼:" pass
請輸入銀行卡密碼:111222
[root@client ~]# echo "帳號$num 密碼$pass" >> /tmp/pass.txt
[root@client ~]# cat /tmp/pass.txt
帳號4445555666 密碼111222
-p 指定提示信息
-t 指定超時時間 默認單位:秒
-n 指定字符個數
-a 數組名 將輸入的值賦給這個數組名
例1:
7/81
創建用戶,提示輸入用戶名,依據輸入的用戶名去創建這個用戶,創建前先判斷用戶是否存在,存在提示
用戶已創建,不存在創建此用戶,提示創建完成
#!/bin/bash
read -t 30 -p "請輸入你的用戶名:" name
useradd $name &>/dev/null && echo "用戶$name創建完成" || echo "用戶$name已存在"
例2:
測試本機是否能與輸入的ip地址通信,能通信輸出ip is up,不能通信 輸出ip is down。
#!/bin/bash
read -p "請輸入ip地址:" ipaddress
ping -c 3 $ipaddress &>/dev/null && echo "ip is up" ||echo "ip is down"

ping -c 3 192.168.1.251

-c 指定數量
ping 3次自動斷開
例3:
使用read截獲銀行卡的賬戶和密碼
#!/bin/bash
#使用read截獲銀行卡的賬戶和密碼
read -p "please input bank card account:" account
stty -echo //隱藏顯示
read -p "please input bank card passwd:" -n 6 -t 60 passwd
stty echo //恢復正常
echo
echo "account:$account passwd:$passwd" >> /tmp/bank.txt
echo "account:$account passwd:$passwd" |mail -s "hello success" [email protected]
3.變量置換 變量“內容”的刪除和替換:
======“內容”的刪除========
[root@client ~]# url=www.sina.com.cn
[root@client ~]# echo ${#url} 獲取變量值的長度
15
[root@client ~]# echo ${url} 標準查看
www.sina.com.cn
[root@client ~]# echo ${url#.} 從前向後匹配,最短匹配
sina.com.cn
[root@client ~]# echo ${url##
.} 從前向後匹配,最長匹配 貪婪匹配(找到最後一個.)
cn
[root@client ~]# url=www.sina.com.cn
[root@client ~]# echo ${url}
www.sina.com.cn
[root@client ~]# echo ${url%.} 從後向前匹配,最短匹配
www.sina.com
[root@client ~]# echo ${url%%.
} 從後向前匹配,最長匹配 貪婪匹配(找到最前面一個.)
www
========變量的替換==============
[root@client tmp]# url=www.sina.com.cn
[root@client tmp]#
[root@client tmp]# echo ${url/sina/baidu}
www.baidu.com.cn
8/81
[root@client tmp]# echo ${url}
www.sina.com.cn
[root@client tmp]# echo ${url/n/N} 匹配一個替換
www.siNa.com.cn
[root@client tmp]# echo ${url//n/N} 貪婪匹配
www.siNa.com.cN
=======變量的替代============
${變量名-新的變量值}
變量沒有被賦值:會使用“新的變量值”替代
變量有被賦值(包括空值):不會被替代
[root@client tmp]# unset var1
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]# var2=111
[root@client tmp]# var3=
如果變量沒有被賦值,則顯示aaaa
[root@client tmp]# echo ${var1-aaaa}
aaaa
如果變量值有賦值,則不顯示222
[root@client tmp]# echo ${var2-222}
111
如果變量值有賦值,值爲空,則不顯示333
[root@client tmp]# echo ${var3-333}
${變量名:-新的變量值}
變量沒有被賦值(包括空值):都會使用“新的變量值”替代
變量有被賦值:不會被替代
[root@client tmp]# unset var1
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]#
[root@client tmp]# var2=
[root@client tmp]# var3=111
如果變量沒有被賦值,則顯示aaaa
[root@client tmp]# echo ${var1:-aaaa}
aaaa
如果變量有賦值,值爲空,則顯示aaaa
[root@client tmp]# echo ${var2:-aaaa}
aaaa
如果變量有賦值,則不顯示aaaa
[root@client tmp]# echo ${var3:-aaaa}
111
${變量名+新的變量值}
[root@client tmp]# unset var1
9/81
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果變量沒有被賦值,則不顯示新的值
[root@client tmp]# echo ${var1+222}
如果變量有賦值,則顯示新的值
[root@client tmp]# echo ${var2+222}
222
如果變量有賦值,值爲空,則顯示新的值
[root@client tmp]# echo ${var3+222}
222
${變量名:+新的變量值}
[root@client tmp]# unset var1
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]#
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果變量沒有被賦值,則不顯示新的值
[root@client tmp]# echo ${var1:+222}
如果變量有賦值,則顯示新的值
[root@client tmp]# echo ${var2:+222}
222
如果變量有賦值,值爲空,則不顯示新的值
[root@client tmp]# echo ${var3:+222}
${變量名=新的變量值}
[root@client tmp]# unset var1
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果變量沒有被賦值,則顯示新的值
[root@client tmp]# echo ${var1=123}
123
如果變量有賦值,則不顯示新的值
[root@client tmp]# echo ${var2=123}
aaaa
如果變量有賦值,值爲空,則不顯示新的值
[root@client tmp]# echo ${var3=123}
10/81
${變量名:=新的變量值}
[root@client tmp]# unset var1
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果變量沒有被賦值,則顯示新的值
[root@client tmp]# echo ${var1:=123}
123
如果變量有賦值,則不顯示新的值
[root@client tmp]# echo ${var2:=123}
aaaa
如果變量有賦值,值爲空,則顯示新的值
[root@client tmp]# echo ${var3:=123}
123
${變量名:num1}
${變量名:num1:num2}
PS1環境變量
默認的PS1環境變量值設置:
echo $PS1 顯示如下信息
PS1='[\u@\h \W]\$ '
說明:man bash 然後/PS1查找PS1關鍵字,大約在1555行,有如下的解釋
\u 當前登錄的用戶名
\h 當前的主機名
#設置新的PS1環境變量值:
PS1='[\u@\h \W-qf-edu]\$ '
echo $PS1 顯示如下信息
[root@node11 ~-qf-edu]
練習:將PS1環境變量分別設置成如下效果,看命令提示有何不同。
echo $PS1
PS1='[\u@\h \W]\$ ' 系統默認提示符
PS1='[\t \u@\h \w ]\$'
PS1='[\t-qf_edu \u@\h \W]\$ '
11/81
提問:在百度上查如何將PS1提示符設置成彩色字。根據網上的方法測試一下。
附錄:
允許通過插入一些反斜槓轉義的特殊字符來定製這些提示字符串,這些字符被如下解釋:
\a 一個 ASCII 響鈴字符 (07)
\d 日期,格式是 "星期 月份 日" (例如,"Tue May 26")
\D{format}
format 被傳遞給 strftime(3),結果被插入到提示字符串中; 空的 format
將使用語言環境特定的時間格式。花括號是必需的
\e 一個 ASCII 轉義字符 (033)
\h 主機名,第一個 `.' 之前的部分
\H 主機名
\j shell 當前管理的作業數量
\l shell 的終端設備名的基本部分
\n 新行符
\r 回車
\s shell 的名稱, $0 的基本部分 (最後一個斜槓後面的部分)
\t 當前時間,採用 24小時制的 HH:MM:SS 格式
\T 當前時間,採用 12小時制的 HH:MM:SS 格式
\@ 當前時間,採用 12小時制上午/下午 (am/pm) 格式
\A 當前時間,採用 24小時制上午/下午格式
\u 當前用戶的用戶名 the username of the current user
\v bash 的版本 (例如,2.00)
\V bash 的發行編號,版本號加補丁級別 (例如,2.00.0)
\w 當前工作目錄
\W 當前工作目錄的基本部分
! 此命令的歷史編號
# 此命令的命令編號
\$ 如果有效 UID 是 0,就是 #, 其他情況下是 $
\nnn 對應八進制數 nnn 的字符
\ 一個反斜槓
[ 一個不可打印字符序列的開始,可以用於在提示符中嵌入終端控制序列
] 一個不可打印字符序列的結束
變量值的處理
3.變量置換 變量的值(即內容)刪除和替換:
======“內容”的刪除========
#給變量url賦上www.sina.com.cn這個值。
[root@client ~]# url=www.sina.com.cn
[root@client ~]# echo $url 或 echo ${url} 標準查看(獲取變量的值)
www.sina.com.cn
[root@client ~]# echo ${#url} 獲取變量值的長度(即變量值的字符數)
15
12/81
#以下是用#號刪除匹配到的關鍵字左側的內容。
[root@client ~]# echo ${url#.} 從前向後匹配,最短匹配(刪除操作) 想想先來後到這個詞
sina.com.cn 理解:刪除左邊第一個點和左側的所有內容
[root@client ~]# echo ${url##
.} 從前向後匹配,最長匹配 貪婪匹配(找到最後一個.)
cn 理解:刪除最右側第一個點和這個點左側的所有內容
#以下是用%號刪除匹配到的關鍵字右側的內容。
[root@client ~]# url=www.sina.com.cn
[root@client ~]# echo ${url}
www.sina.com.cn
[root@client ~]# echo ${url%.} 從後向前匹配,最短匹配
www.sina.com 理解:刪除右邊第一個點和右側的所有內容
[root@client ~]# echo ${url%%.
} 從後向前匹配,最長匹配 貪婪匹配(找到最前面一個.)
www 理解:刪除左邊第一個點和這個點右側的所有內容
練習:執行url=http://www.baidu.com:8080/music/index.html,然後完成以下操作
1.輸出變量url的值。 答:echo $url
2.輸出變量url的值的長度(即字符數)是多少。 答: echo ${#url}
3.僅輸出變量url值中的http關鍵詞。 答: echo ${url%%:}
4.僅輸出變量url值中的index.html關鍵詞。 答: echo ${url##
/}
5.僅輸出變量url值中的域名。 答: echo ${url%:} | awk -F/ '{print $NF}'
6.僅輸出變量url值中的端口號。 答: echo ${url##
:} | awk -F/ '{print $1}'
附加練習:
僅輸出變量url值中的域名: echo $url | awk -F: '{print $2}' |sed 's@/@@'
練習:編寫一個/sh/input.sh腳本,要求提示用戶輸入一個完整的網址(如http://www.163.com:80/
index.php),然後分別用echo輸出用戶輸入的這個網址,顯示"協議名稱是:" ,"主頁是:","域名是:","端
口號是:"。
vim /sh/input.sh 基本內容如下
#!/bin/bash
read -p '輸入一個完整的網址(如http://www.163.com:80/index.php):' url
echo "您輸入的完整網址是: $url"
echo "協議名稱是: ${url%%:
}"
echo "主頁是: ${url##/}"
echo "域名是: $(echo $url | awk -F [:/] '{print $4}') "
echo "端口號是: $(echo $url | awk -F [:/] '{print $5}') "
#域名和端口號的信息可以採用如下代碼實現:
#d_name=$(echo $url | awk -F [:/] '{print $4}')
#port=$(echo $url | awk -F [:/] '{print $5}')
#echo "域名是: ${d_name} "
#echo "端口號是: $port "
附加思考:
請在學習完if、test、while、正則表達式之後,對/sh/input.sh腳本做優化,優化內容是判斷用戶輸入的
網址格式是否正確,如果正確就輸出相關的信息,否則提示用戶重新輸入。
========變量的替換==============
[root@client tmp]# url=www.sina.com.cn.nh
[root@client tmp]# echo ${url/sina/baidu}
www.baidu.com.cn
13/81
[root@client tmp]# echo ${url}
www.sina.com.cn
[root@client tmp]# echo ${url/n/N} 匹配一個替換
www.siNa.com.cn
[root@client tmp]# echo ${url//n/N} 貪婪匹配(整行替換)
www.siNa.com.cN.hN
注意:以上對變量值的內容做刪除、替換之後,變量的原始值是不發生改變。
例:執行如下操作。熟悉變量值的內容刪除、替換等操作。
url=www.sina.com.cn.nh
a=${url//n/N}
b=${url##
.}
c=${url%%.*}
echo $a
echo $b
echo $c
echo $url
=======變量的替代============
要點說明:以下是分別用-、+、=、:等符號來對變量的原始值做判斷後進行修改或不修改處理。
${變量名-新的變量值}
變量沒有被賦值:會顯示“新的變量值”
變量有被賦值(包括空值):顯示原值,不顯示新值
[root@client tmp]# unset var1 取消/刪除var1這個變量
[root@client tmp]# unset var2
[root@client tmp]# unset var3
[root@client tmp]# var2=111
[root@client tmp]# var3=
如果變量沒有被賦值,則顯示aaaa
[root@client tmp]# echo ${var1-aaaa}
aaaa
附加測試:echo $var1 發現原值不變
如果變量值有賦值,則不顯示222,但是顯示變量的原值
[root@client tmp]# echo ${var2-222}
111
如果變量值有賦值,值爲空,則不顯示333,但是顯示變量的原值(即空值)
[root@client tmp]# echo ${var3-333}
${變量名:-新的變量值}
變量沒有被賦值(包括空值):都會顯示“新的變量值”
變量有被賦值:不會被替代
[root@client tmp]# unset var1 var2 var3
[root@client tmp]# var2=111
[root@client tmp]# var3=
如果變量沒有被賦值,則顯示aaaa
[root@client tmp]# echo ${var1:-aaaa}
14/81
aaaa
附加測試:echo $var1 發現原值不變
如果變量有賦值,值爲空,則顯示aaaa
[root@client tmp]# echo ${var2:-aaaa}
111
如果變量有賦值,就不顯示aaaa
[root@client tmp]# echo ${var3:-aaaa}
aaaa
${變量名+新的變量值}
[root@client tmp]# unset var1 var2 var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果變量沒有被賦值,就不顯示新的值
[root@client tmp]# echo ${var1+222}
如果變量有賦值,就顯示新的值
[root@client tmp]# echo ${var2+222}
222
如果變量有賦值,值爲空,則顯示新的值
[root@client tmp]# echo ${var3+222}
222
${變量名:+新的變量值}
[root@client tmp]# unset var1 unset var2 var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果變量沒有被賦值,就不顯示新的值
[root@client tmp]# echo ${var1:+222}
如果變量有賦值,就顯示新的值
[root@client tmp]# echo ${var2:+222}
222
如果變量有賦值,值爲空,則不顯示新的值
[root@client tmp]# echo ${var3:+222}
${變量名=新的變量值}
[root@client tmp]# unset var1 var2 var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果變量沒有被賦值,就顯示新的值,並且會將新值賦給這個變量。
[root@client tmp]# echo ${var1=123}
123
如果變量有賦值,則不顯示新的值
15/81
[root@client tmp]# echo ${var2=123}
aaaa
如果變量有賦值,值爲空,則不顯示新的值
[root@client tmp]# echo ${var3=123}
${變量名:=新的變量值}
[root@client tmp]# unset var1 var2 var3
[root@client tmp]# var2=aaaa
[root@client tmp]# var3=
如果變量沒有被賦值,就顯示新的值,並且會將新值賦給這個變量。(必知)
[root@client tmp]# echo ${var1:=123}
123
附加測試:echo $var1 發現變量var1有了新值
如果變量有賦值,則不顯示新的值
[root@client tmp]# echo ${var2:=123}
aaaa
附加測試:echo $var2 發現原值不變
如果變量有賦值,值爲空,就顯示新的值,並且會將新值賦給這個變量。(必知)
[root@client tmp]# echo ${var3:=123}
123
${變量名:num1}
${變量名:num1:num2}
實例
練習:編寫一個/sh/input.sh腳本,要求提示用戶輸入一個完整的網址(如http://www.163.com:80/
index.php),然後分別用echo輸出用戶輸入的這個網址,顯示"協議名稱是:" ,"主頁是:","域名是:","端
口號是:"。
vim /sh/input.sh 基本內容如下
#!/bin/bash
read -p '輸入一個完整的網址(如http://www.163.com:80/index.php):' url
echo "您輸入的完整網址是: $url"
echo "協議名稱是: ${url%%:}"
echo "主頁是: ${url##
/}"
echo "域名是: $(echo $url | awk -F [:/] '{print $4}') "
echo "端口號是: $(echo $url | awk -F [:/] '{print $5}') "
#域名和端口號的信息可以採用如下代碼實現:
#d_name=$(echo $url | awk -F [:/] '{print $4}')
16/81
#port=$(echo $url | awk -F [:/] '{print $5}')
#echo "域名是: ${d_name} "
#echo "端口號是: $port "
例:編寫一個/sh/var.sh腳本。要求提示用戶輸入一個IP地址,做判斷測試(如果用戶未輸入ip),就提示
默認IP是192.168.11.5,否則顯示默認IP是用戶輸入的這個IP值。
vim /sh/var.sh
#!/bin/bash
read -p 'please input ip address:' IP
echo "默認IP是:${IP:=192.168.11.5}"
腳本常見案例(個人整理)
例如:用if的結構1做如下測試。
x=abc;y=abc;z=123
if [ $x = $y ];then
echo yes
fi
.輸入一個數字判斷是奇數還是偶數
#!/bin/bash
#
read -p "輸入一個整數:" num
if [ $(($num % 2)) -eq 0 ]
then
echo "$num是偶數"
else
echo "$num是奇數"
fi
例如:判斷系統中是否存在root用戶,如果存在就提示yes。
用命令的邏輯執行來實現,方法如下:
id root && echo yes
用if語句來實現,寫法如下:
id root
if [ $? -eq 0 ];then
echo yes
fi
例如:判斷系統中是否存在/zk目錄,如果存在就刪除此目錄且顯示過程,否則創建此目錄且顯示過程
方法一:用命令的邏輯執行方法來實現的寫法。
[ -d /zk ] && rm -rfv /zk || mkdir -pv /zk
方法二:用if語句實現的寫法。
17/81
if [ -d /zk ];then
rm -rfv /zk
else
mkdir -pv /zk
fi
例如:判斷系統中是否存在zk用戶,如果存在就用userdel -r zk刪除此用戶,否則創建zk用戶。
方法一:用命令的邏輯執行方法來實現的寫法。
id zk && userdel -r zk || useradd zk
方法二:用if語句實現的寫法。
if id zk;then
userdel -r zk
else
useradd zk
fi
例:編寫一個名稱爲/sh/mk.sh的腳本,要求批量創建/test/a1~/test/a5這些目錄,同時顯示目錄創建的執
行過程。
第1步,編寫腳本文件。
vim /sh/mk.sh 腳本內容如下
#!/bin/bash
#description: this is a mkdir script.
for i in {1..5}
do
mkdir -pv /test/a$i
done
例:編寫一個名稱爲/sh/user.sh的腳本,要求批量創建用戶u1~u5,並且在創建用戶之後查用戶的id號,並
且給每個用戶設置初始登錄密碼爲007。
第1步,編寫腳本文件。
vim /sh/user.sh 腳本內容如下
#!/bin/bash
#description: this is a useradd script.
for i in {1..5}
do
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
done
第3步,對入門級的腳本進行如下優化。
1.在useradd創建用戶之前,判斷此用戶是否存在,如果存在就提示user exsits,否則創建此用戶並設置初
始登錄密碼爲007.
cp -av /sh/user.sh /sh/user-new.sh
vim /sh/user-new.sh 腳本內容如下
#!/bin/bash
#description: this is a useradd script.
for i in {1..5}
do
if (id u$i);then
echo "u$i user exsits."
else
18/81
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
fi
done
練習:在命令行中執行以下操作,實現輸出10以內的正整數。
i=1
while [ $i -le 10 ]
do
echo $i
let i++ 或 $[i++] 或 $((i++))
sleep 1s 等待1秒(停頓1秒)
done

例:編寫一個名稱爲/sh/while_user.sh的腳本,要求用while循環語句,批量創建用戶w1~w5,並且在創建
用戶之後查用戶的id號,並且給每個用戶設置初始登錄密碼爲007。
第1步,編寫腳本文件。
vim /sh/while_user.sh
i=1
while [ $i -le 5 ]
do
useradd w$i && echo "w$i user added." || echo "w$i user exsits."
id w$i
echo 007 | passwd --stdin w$i
let i++
sleep 1s
done
思考:編寫一個名稱爲/sh/del_users.sh的腳本,要求用while循環語句,批量查詢用戶w1~w5的id信息,然
後用userdel -r刪除這些用戶。
第1步,編寫腳本文件。
vim /sh/del_user.sh
i=1
while [ $i -le 5 ]
do
id w$i
userdel -r w$i && echo "w$i user removed." || echo "w$i user not exsits."
let i++
sleep 1s
done
例如:寫一個名稱爲/sh/cai.sh的腳本,要求提示用戶輸入數字,判斷數字大小是否爲520,如果是就提示
yes;如果大於520,就提示bigger;否則提示little。
第1步,編寫/sh/cai.sh腳本文件。
mkdir -pv /sh
vim /sh/cai.sh
#!/bin/bash
#description:this is crossword games.
read -p 'Please input your number:' x
if [ $x -eq 123 ];then
echo 'you are right.'
elif [ $x -gt 123 ];then
echo 'you are bigger'
19/81
else
echo 'you are little.'
fi

while死循環(無限循環):
while :
do
cmd_list循環體
done
例:執行如下while死循環語句,實現每隔2秒輸出echo命令的中的文本內容。[按ctrl+c強制終止死循環]
while :
do
echo 'I love you!'
sleep 2s
done
例:寫一個名稱爲/sh/cai.sh的腳本,要求用while循環控制語句,當用戶猜的數字錯了就連續重複猜(即提示
用戶"'Please input your number"),提示用戶輸入數字,判斷數字大小是否爲520,如果是就提示yes;
如果大於520,就提示bigger;否則提示little。
第1步,編寫/sh/cai-2.sh腳本文件。
mkdir -pv /sh
vim /sh/cai-2.sh
#!/bin/bash
#description:this is crossword games.
x=0
while [ $x -ne 520 ]
do
read -p 'Please input your number:' x
if [ $x -eq 520 ];then
echo 'you are right.'
break(猜對了退出死循環)
elif [ $x -gt 520 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
done
until循環體退出循環
例:在命令行中執行如下操作,實現用until循環來輸出1~10這些數。
i=1
until [ $i -gt 10 ]
do
echo $i
let i++
done
將while語句的猜字遊戲腳本/sh/cai-2.sh進行改寫,用until語句來實現。
第1步,編寫/sh/cai-3.sh腳本文件。
mkdir -pv /sh
vim /sh/cai-3.sh
#!/bin/bash
#description:this is crossword games.
x=0
20/81
until [ $x -eq 520 ]
do
read -p 'Please input your number:' x
if [ $x -eq 520 ];then
echo 'you are right.'
elif [ $x -gt 520 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
done
循環實例:
1.用for輸出1~100的求和結果。
2.用for語句輸出等腰直角三角形。
3.用for語句輸出九九乘法口訣表。
例1:編寫一個名稱爲/sh/100jia.sh的腳本,要用for進行循環控制,實現輸出1+2+...+100的計算結果。
#!/bin/bash
sum=0
for ((i=0;i<=100;i++))
do
sum=$[i+sum]
done
echo $sum
例2:編寫一個名稱爲/sh/3ja.sh的腳本,用for進行循環控制,實現在屏幕上顯示一個5行由號組成的等腰
直角三角形。

**




解題思路:外層for循環控制三角形中星號的行數,內層for循環控制三角形中星號的列數。
#!/bin/bash
for ((i=1;i<=5;i++))
do
for ((j=1;j<=i;j++))
do
echo -n ""
done
echo " "
done
倒立的三角形
#!/bin/bash
for ((i=1;i<=5;i++))
do
for ((j=5;j>=i;j--))
do
echo -n "
"
done
echo
done
循環分析:for循環中每次i、j變量的取值分析。
21/81
第一次循環:
i=1 j=1
換行
第二次循環:
i=2 j=1
i=2 j=2 換行
第二次循環:
i=3 j=1
i=3 j=2
i=3 j=3
換行
第四、五次循環依次類推。
例3:編寫一個名稱爲/sh/99.sh的腳本,用for進行循環控制,實現在屏幕上顯示'九九乘法表口訣'。
1X1=1
1X2=2 2X2=4
1X3=3 2X3=6 3X3=9
……
1X9=9 2X9=18 …… 9X9=81
#!/bin/bash
for ((i=1;i<=9;i++))
do
for ((j=1;j<=i;j++))
do
echo -ne "${j}X${i}=$[ij]\t"
done
echo
done
case語句
例:編寫一個名稱爲/sh/menu.sh的腳本,要求顯示一個主菜單界面,提示用戶輸入功能選項,回車確認後
執行指定選項的命令操作。
第1步,根據項目需求,編寫出腳本內容。
vim /sh/menu.sh 入門級腳本內容如下:
echo '---------------------
1/a.Install NFS Service
2/b.Install Vsftpd Service
3/c.Install Samba Service
4/d.Install DNS Service
22/81
5/e.Install Apache Service
6/f.Install PXE Service
7/g.Install DHCP Service
0/
.Exit Shell Script
---------------------'
read -p 'please input your choice:' opt
case $opt in
1|a)
echo 'Install NFS Service'
. /sh/nfs-new.sh
;;
2|b)
echo 'Install Vsftpd Service'
. /sh/ftp-new.sh
;;
0|)
echo 'Exit Shell Script'
#exit 0
;;
esac
第2步,給腳本添加x可執行權限,測試腳本的運行。
chmod -v +x /sh/menu.sh
. /sh/menu.sh
23/81
5.交互式腳本
需求:提示用戶輸入功能選項,選項1爲執行clear、date、創建jack用戶、設置jack密碼功能;選項2爲執
行clear、刪除jack用戶;如果輸入其他字符則提示“未輸入正確的功能選項,程序退出”,且自動退出腳
本。
vi case1.sh 代碼內容如下
#!/bin/bash
read -p "請輸入功能選項數字代號,如1、2...:" choice
case $choice in
1)
clear
date
useradd jack
echo jack | passwd --stdin jack
;;
2)
clear
id jack && userdel -r jack || echo "jack用戶不存在"
;;
)
echo "未輸入正確的功能選項,程序退出"
exit 1
esac
6.腳本中交互式實現
判斷用戶輸入的字符串,
如果用戶輸入的字符串爲start,就在/tmp下創建一個start文件;
如果用戶輸入的爲stop,那麼就刪除/tmp/start文件;
如果用戶輸入的爲restart,那麼就先刪除/tmp/start文件,然後創建一個start1文件;
如果用戶輸入其他的字符串,就輸出一個幫助信息:腳本名 Usage:{start|stop|restart}
read -p "請輸入字符串:" strings
case $strings in
start)
touch /tmp/start
;;
stop)
rm -rf /tmp/start
;;
restart)
if [ -e /tmp/start ]
then
rm -rf /tmp/start
else
touch /tmp/start1
fi
;;

echo "$0 Usage:{start|stop|restart}"
esac
1.超市賣水果
24/81
你輸入蘋果,顯示 蘋果 5元每斤
你輸入香蕉 ,顯示 香蕉 3元每斤
你輸入橘子,顯示 橘子 3元每斤
如果你輸入的不是蘋果 香蕉 橘子 就提示只能查詢 蘋果 香蕉 橘子
case語句#!/bin/bash 可以把紅色的分別換成0,1,2或者apple|0),banana|1),orange|2)
read -p "輸入要查詢價格的水果名:" aa
case $aa in
apple)
echo "apple 5元每斤";;
banana)
echo "banana 3元每斤";;
orange)
echo "orange 3元每斤";;
)
echo "Usage :{apple|banana|orange}"
esac
for語句#!/bin/bash
num=(apple banana orange )
declare -a num
read -p "please input fruits:" aa
if [ $aa == ${num[0]} ];then
echo "$aa 5元一斤“
elif [ $aa == ${num[1]} ];then
echo "$aa 5元一斤"
elif [ $aa == ${num[2]} ];then
echo "$aa 2元一斤"
else
echo "Usage:{apple|banana|orange}"
fi
最簡單的×××,但是紅球有可能重複
vim /sh/cp.sh 腳本內容如下
#!/bin/bash
for i in {1..6}
do
red[$i]=$[$RANDOM%33+1]
echo -ne "${red[$i]}\t"
done
echo
echo "$[$RANDOM%16+1]"
25/81
初級腳本優化項目案例
編寫腳本的思路:
1.根據目標需求分析需要用到哪些操作命令。
2.將操作的命令寫入到shell腳本文件中。不考慮邏輯判斷。(入門級)
3.運行和測試入門級的腳本。
4.對入門級的腳本進行優化,即添加條件判斷if、循環(while、until、for)等邏輯控制語句。(高級腳本)
5.運行和測試高級的腳本。
做一個menu菜單
vim /sh/menu.sh 入門級腳本內容如下:
#!/bin/bash
echo '---------------------
1/a.Install NFS Service
2/b.Install Vsftpd Service
3/c.Install Samba Service
4/d.Install DNS Service
5/e.Install Apache Service
6/f.Install PXE Service
7/g.Install DHCP Service
0/.Exit Shell Script
---------------------'
_NFS(){
soft='nfs-utils rpcbind'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_Vsftpd(){
soft='vsftpd lftp ftp'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_Samba(){ soft='samba samba-comment samba-client'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_Httpd(){ soft='Httpd'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_DHCP(){ soft='dhcpd'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_PXE(){ soft='vsftpd dhcpd tftp-server '
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
_firewalld(){
systemctl stop firewalld
getenforce
}
_yum(){ [ -d /iso ] && echo '/iso is exists' || mkdir -pv /iso
lsblk | grep iso && echo 'iso is mounted.' || mount /dev/cdrom /iso
cd /etc/yum.repos.d
[ -d bak ] && echo 'bak directory exsits.' || mkdir -pv bak
mv -fv
.repo bak
echo '[centos7.6]
26/81
name=centos 7.6 linux
baseurl=file:///iso
enabled=1
gpgcheck=0
' >/etc/yum.repos.d/iso.repo
mount /dev/sr0 /iso
yum clean all
yum repolist
}
_addusers(){ i=wl
id $i && echo 'user is exists' || useradd $i
}
_DNS(){ soft='bind bind-utils'
rpm -q $soft && echo "$soft exists" || yum -y install $soft
}
read -p '輸入功能選項的數字編號:' i
case $i in
1)
_NFS
;;
2)
_Vsftpd
;;
3)
_Samba
;;
4)
_Httpd
;;
5)
_DHCP
;;
6)_PXE
;;
7)_firewalld
;;
8)_yum
;;
9)_addusers
;;
10)_DNS
;;
*)
echo 'input error shell.exit'
;;
esac

例:編寫一個名稱爲/sh/user.sh的腳本,要求批量創建用戶u1~u5,並且在創建用戶之後查用戶的id號,並
且給每個用戶設置初始登錄密碼爲007。
第1步,編寫腳本文件。
vim /sh/user.sh 腳本內容如下
#!/bin/bash
27/81
#description: this is a useradd script.
for i in {1..5}
do
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
done
對入門級的腳本進行如下優化。
1.在useradd創建用戶之前,判斷此用戶是否存在,如果存在就提示user exsits,否則創建此用戶並設置初
始登錄密碼爲007.
cp -av /sh/user.sh /sh/user-new.sh
vim /sh/user-new.sh 腳本內容如下
#!/bin/bash
#description: this is a useradd script.
for i in {1..5}
do
if (id u$i);then
echo "u$i user exsits."
else
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
fi
done
需求:編寫一個名稱爲/sh/nfs.sh的腳本程序,要求實現查詢NFS軟件是否已安裝(nfs-utils、rpcbind),全
自動安裝(nfs-utils、rpcbind)文件共享服務,自動啓動服務,自動以可讀可寫方式共享/share目錄,自動本
地測試查看nfs共享資源。
首先,編寫入門級的腳本。
第1步,編寫nfs.sh腳本文件。
vim /sh/02.sh
#!/bin/bash
rpm -q nfs-utils rpcbind
yum install -y nfs-utils rpcbind
systemctl restart nfs rpcbind
systemctl enable nfs rpcbind
mkdir -pv /share
chmod -v o+rwx /share
echo '/share (rw,no_root_squash)' > /etc/exports
exportfs -rav
showmount -e 127.0.0.1
優化後的腳本內容如下:
cp -av /sh/nfs.sh /sh/nfs-new.sh
vim /sh/nfs-new.sh
#!/bin/bash
rpm -q nfs-utils rpcbind > /dev/null && echo 'soft exsits' || yum install -y nfs-utils rpcbind
systemctl status nfs | grep dead && systemctl restart nfs rpcbind || echo 'service running'
read -p 'Input your share dir path (e.g. /etc):' dir_path
[ -d $dir_path ] && echo 'dir exsits' || (mkdir -pv $dir_path;chmod -v o+rwx $dir_path)
grep -q "$dir_path" /etc/exports && echo 'share exsits' || echo "$dir_path
(rw)" >> /etc/
exports
exportfs -rav
showmount -e 127.0.0.1
第4步,測試新腳本的運行。
. /sh/nfs-new.sh
28/81

需求:編寫一個名稱爲/sh/ftp.sh的腳本程序,要求實現查詢vsftpd軟件是否已安裝,全自動安裝vsftpd文
件共享服務,自動啓動服務,自動創建/var/ftp/dvd目錄,將光盤(/dev/cdrom或/dev/sr0)掛載到/var/ftp/
dvd目錄中,用lftp做訪問vsftpd共享的內測(本地測試127.0.0.1)。
第1步,編寫ftp.sh腳本文件。
vim /sh/ftp.sh
#!/bin/bash
rpm -q vsftpd lftp ftp
yum install -y vsftpd lftp ftp
systemctl restart vsftpd
systemctl enable vsftpd
mkdir -pv /var/ftp/dvd
mount -v /dev/cdrom /var/ftp/dvd
mount | grep ftp
lftp 127.0.0.1 -e 'ls dvd;ls;bye'
第3步,對入門級的腳本ftp.sh做如下優化:
1.判斷軟件是否已安裝,如果已安裝就提示soft exsits,否則安裝軟件。
2.判斷服務是否已啓動,如果未啓動就重啓服務,否則提示service running。
3.提示用戶輸入共享用戶賬號。
4.判斷輸入的用戶賬號是否存在,如果存在就提示user exsits,否則創建此用戶且給用戶設置登錄密碼爲
01。
5.用lftp命令採用此用戶來訪問共享,列出共享文件名列表。
cp -av /sh/ftp.sh /sh/ftp-new.sh
vim /sh/ftp-new.sh 優化後的腳本內容如下:
#!/bin/bash
rpm -q vsftpd lftp ftp > /dev/null && echo 'soft exsits' ||yum install -y vsftpd lftp ftp
systemctl status vsftpd | grep -q dead && systemctl restart vsftpd || echo 'service running'
systemctl enable vsftpd
mkdir -pv /var/ftp/dvd
mount -v /dev/cdrom /var/ftp/dvd
mount | grep ftp
read -p 'Input your account name:' user_name
id $user_name &> /dev/null && echo 'user exsits.' || (useradd $user_name;echo 01 |
passwd --stdin $user_name)
lftp 127.0.0.1 -u ${user_name},01 -e 'ls -a;bye'
第4步,測試新腳本的運行。
. /sh/ftp-new.sh

需求:編寫一個名稱爲/sh/smb.sh的腳本程序,要求實現查詢samba軟件是否已安裝,全自動安裝samba
文件共享服務,自動啓動smb服務,創建bk這個samba用戶,bk的samba登陸密碼爲007,自動用samba以
smbrw爲共享名稱並且以可讀可寫方式共享/smb目錄。做內測(即本地測試127.0.0.1)自動查看samba共享
資源。
第1步,編寫smb.sh腳本文件。
vim /sh/smb.sh
#!/bin/bash
rpm -q samba samba-client samba-common
yum install -y samba samba-client samba-common
systemctl restart smb
systemctl enable smb
29/81
useradd bk
pdbedit bk -a
pdbedit -L
mkdir -pv /smb
echo '[smbrw]
comment=smbrw dir share
path=/smb
writeable=yes
browseable=yes
public=yes
' >> /etc/samba/smb.conf
systemctl reload smb
smbclient -L 127.0.0.1

需求:編寫一個名稱爲/sh/apache.sh的腳本程序,要求實現查詢httpd軟件是否已安裝,全自動安裝
httpd、curl、elinks文件共享服務,自動啓動httpd服務,/baidu/www目錄,主頁爲/baidu/www/
index.html,自動用基於端口的虛擬主機技術用81端口發佈/baidu/www目錄的網站,虛擬主機配置文件
名爲/etc/httpd/conf.d/baidu.conf。做網站的內測(即本地測試127.0.0.1)訪問。
第1步,編寫apache.sh腳本文件。
vim /sh/apache.sh
#!/bin/bash
rpm -q httpd httpd-manual
yum install -y httpd httpd-manual curl elinks
systemctl restart httpd
systemctl enable httpd
mkdir -pv /baidu/www
echo 'www.baidu.com' > /baidu/www/index.html
echo 'Listen 81
<VirtualHost :81>
ServerAdmin [email protected]
ServerName www.baidu.com
DocumentRoot /baidu/www
ErrorLog /var/log/httpd/www.baidu.com-err.log
CustomLog /var/log/httpd/www.baidu.com-access.log common
</VirtualHost>
<Directory /baidu/www>
AllowOverride None
require all granted
</Directory>
' > /etc/httpd/conf.d/baidu.conf
systemctl reload httpd
lsof -i:81
curl 127.0.0.1:81
---yum 配置
需求:編寫一個名稱爲/sh/yum.sh的腳本,要求自動將/dev/cdrom掛載到/iso目錄中,移動/etc/
yum.repos.d/
.repo到/etc/yum.repos.d/bak目錄中,自動創建yum源配置文件/etc/yum.repos.d/
iso.repo,其中iso.repo文件中的baseurl路徑指向/iso目錄,自動測試yum源和倉庫的可用性(yum clean
all;yum repolist)。
腳本編寫的思路:
1.根據需求分析要用到哪些命令。
2.將命令寫到腳本文件中,得到第1版的入門級腳本文件。
3.測試入門級腳本的運行。
30/81
4.優化入門級腳本:在腳本中添加if邏輯控制語句,讓腳本更具通用性,得到高級腳本。
5.測試高級腳本的運行。
vim /sh/yum.sh
#!/bin/bash
mkdir -pv /iso
mount /dev/cdrom /iso
cd /etc/yum.repos.d
mkdir -pv bak
mv -v .repo bak
echo '[centos7.6]
name=centos 7.6 linux
baseurl=file:///iso
enabled=1
gpgcheck=0
' > /etc/yum.repos.d/iso.repo
yum clean all
yum repolist
4.優化入門級腳本:在腳本中添加if邏輯控制語句,讓腳本更具通用性,得到高級腳本。
cp -av /sh/yum.sh /sh/yum-new.sh
vim /sh/yum-new.sh
#!/bin/bash
[ -d /iso ] && echo '/iso directory exsits.' || mkdir -pv /iso
lsblk | grep iso && echo 'iso is mounted.' || mount /dev/cdrom /iso
cd /etc/yum.repos.d
[ -d bak ] && echo 'bak directory exsits.' || mkdir -pv bak
mv -fv
.repo bak
echo '[centos7.6]
name=centos 7.6 linux
baseurl=file:///iso
enabled=1
gpgcheck=0
' > /etc/yum.repos.d/iso.repo
yum clean all
yum repolist
DNS域名解析自動部署腳本文件
#!/bin/bash
rpm -q bind bind-utils
yum -y install bind bind-utils
systemctl restart named
systemctl enable named
sed -i 's/127.0.0.1/any/' /etc/named.conf
sed -i 's/localhost/any/' /etc/named.conf
systemctl restart named
echo 'zone "qf.com" IN {
type master;
file "qf.com.zx";
allow-update { none; };
};
zone "5.168.192.in-addr.arpa" IN {
type master;
file "192.168.5.x";
allow-update { none; };
};' >/etc/named.rfc1912.zones
named-checkconf
cp -av /var/named/named.localhost /var/named/qf.com.zx
31/81
cp -av /var/named/named.loopback /var/named/192.168.5.x
echo '$TTL 1D
@ IN SOA qf.com. rname.invalid. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @
A 127.0.0.1
AAAA ::1
NS qf.com.
dns A 192.168.11.11
www A 1.1.1.1
ftp A 1.1.1.2
http A 1.1.1.3
web CNAME www.qf.com.' >/var/named/qf.com.zx
echo '$TTL 1D
@ IN SOA dns.qf.com. rname.invalid. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @
A 127.0.0.1
AAAA ::1
PTR localhost.
NS dns.qf.com.
dns A 192.168.11.11
1 PTR www.qf.com.
2 PTR http.qf.com.
3 PTR ftp.qf.com.' >/var/named/192.168.5.x
systemctl restart named
nslookup www.qf.com 192.168.11.11
nslookup http.qf.com 192.168.11.11
nslookup ftp.qf.com 192.168.11.11
nslookup 192.168.5.1 192.168.11.11
nslookup 192.168.5.3 192.168.11.11
nslookup 192.168.5.2 192.168.11.11
32/81
優化DNS腳本
#!/bin/bash
rpm -q bind bind-utils && echo 'soft is exists' || yum -y install bind bind-utils
systemctl status named | grep dead && (systemctl restart named && systemctl enable named) ||
echo 'service is running'
[ -d /etc/named.conf ] && sed -i 's/127.0.0.1/any/' /etc/named.conf
[ -d /etc/named.conf ] && sed -i 's/localhost/any/' /etc/named.conf
systemctl restart named
[ -d /etc/named.rfc.1912.zones ] && echo 'zone "qf.com" IN {
type master;
file "qf.com.zx";
allow-update { none; };
};' >/etc/named.rfc.1912.zones
cd /var/named
[ -d named.localhost ] && mkdir -pv qf.com.zx
[ -d qf.com.zx ] && echo '$TTL 1D
@ IN SOA qf.com. rname.invalid. (
33/81
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
NS @
A 127.0.0.1
AAAA ::1
NS qf.com.
dns A 192.168.11.11
www A 1.1.1.1
ftp A 1.1.1.2
http A 1.1.1.3
web CNAME www.qf.com.' >/var/named/qf.com.zx
systemctl restart named
nslookup www.qf.com 192.168.11.11
nslookup http.qf.com 192.168.11.11
nslookup ftp.qf.com 192.168.11.11
34/81
作業
1.打印聖誕樹
*










1 #!/bin/bash
2 #
3 for ((i=1;i<=4;i++))
4 do
5 for ((j=4;j>=i;j--))
6 do
7 echo -n " "
8 done
9 for ((k=1;k<=2i-1;k++))
10 do
11 echo -n "
"
12 done
13 echo
14 done
15
16 for ((a=1;a<=3;a++))
17 do
18 for ((b=3;b>=a;b--))
19 do
20 echo -n " "
21 done
22 for ((c=1;c<=2a+1;c++))
23 do
24 echo -n "
"
25 done
26 echo
27 done
28
29 for ((f=1;f<=3;f++))
30 do
31 for ((d=1;d<=3;d++))
32 do
33 echo -n " "
34 done
35 for e in {1..3}
36 do
37 echo -n "*"
38 done
39 echo
40 done
35/81

*












1 #!/bin/bash
2 for ((a=1;a<=4;a++))
3 do
4 for b in {1,2}
5 do
6 echo -n " "
7 done
8 for ((c=4;c>=a;c--))
9 do
10 echo -n " "
11 done
12 for ((d=1;d<=a;d++))
13 do
14 echo -n ""
15 done
16 for ((e=2;e<=a;e++))
17 do
18 echo -n "
"
19 done
20 echo
21 done
22
23 for ((f=1;f<=5;f++))
24 do
25 for ((g=5;g>=f;g--))
26 do
27 echo -n " "
28 done
29 for ((h=1;h<=f;h++))
30 do
31 echo -n ""
32 done
33 for i in 1
34 do
35 echo -n "
"
36 done
37 for ((j=1;j<=f;j++))
38 do
39 echo -n ""
40 done
41 echo
42 done
43
44 for ((k=1;k<=3;k++))
36/81
45 do
46 for l in {1..5}
47 do
48 echo -n " "
49 done
50 for m in {1..3}
51 do
52 echo -n "
"
53 done
54 echo
55 done
1 #!/bin/bash
2 #
3 for ((i=1;i<=4;i++))
4 do
5 for ((j=6;j>=i;j--))
6 do
7 echo -n " "
8 done
9 for ((k=1;k<=2i-1;k++))
10 do
11 echo -n "
"
12 done
13 echo
14 done
15
16 for ((a=1;a<=5;a++))
17 do
18 for ((b=5;b>=a;b--))
19 do
20 echo -n " "
21 done
22 for ((c=1;c<=2a+1;c++))
23 do
24 echo -n "
"
25 done
26 echo
27 done
28
29 for ((f=1;f<=3;f++))
30 do
31 for ((d=1;d<=5;d++))
32 do
33 echo -n " "
34 done
35 for e in {1..3}
36 do
37 echo -n "*"
38 done
39 echo
40 done

2.計算器不輸入退出就一直等待輸入數字進行計算
1 #!/bin/bash
2 #
37/81
3 while read -p "請輸入計算的內容:" num
4 do
5 if [[ -z $num || $num == exit ]]
6 then
7 exit
8 else
9 a=$(($num))
10 echo $a
11 fi
12 done
1 #!/bin/bash
2 #
3 while read -p "請輸入計算的內容:" num
4 do
5 num=${num:=exit}
6 if [[ $num == exit ]]
7 then
8 exit
9 else
10 a=$(($num))
11 echo $a
12 fi
13 done
3.寫一個腳本,顯示如下菜單給用戶: while
cpu)print cpu information;
disk) print disk information;
mem)print memory information;
quit)quit;
Pleas enter your option:
根據用戶輸入的顯示相應的信息,如果用戶輸入的不是以上幾種就顯示幫助信息,幫助信息爲“Pleas
enter your option:<cpu|disk|mem|quit>” 該腳本中用戶的選擇不區分大小寫

  1. 編寫腳本,計算1+2+3+4...100的和 while until
    1 a=0
    2 i=0
    3 while [ $i -le 100 ]
    4 do
    5 a=$(($a+$i))
    6 let i++
    7 done
    8 echo $a

    1 a=0
    2 i=0
    3 until [ $i -gt 100 ]
    4 do
    5 a=$(($a+$i))
    6 let i++
    7 done
    8 echo $a

38/81
1.編寫腳本,如果:
根分區剩餘空間小於20%
向用戶root發送警告郵件,郵件的內容包含使用率相關信息
#!/bin/bash
#
gsyl=df -h | head -2 |tail -1 | tr -s " " | cut -d " " -f 5 | cut -d "%" -f 1
re=$((100-$gsyl))
if [ $re -lt 20 ]
then
echo "警告:根分區剩餘空間爲$re%" > /tmp/disk.txt
mail -s "警告信息" [email protected] < "/tmp/disk.txt"
fi
2.輸入一個數字判斷是奇數還是偶數
#!/bin/bash
#
read -p "輸入一個整數:" num
if [ $(($num % 2)) -eq 0 ]
then
echo "$num是偶數"
else
echo "$num是奇數"
fi
3.編寫腳本,計算1+2+3+4...100的和
1 #!/bin/bash
2 #
3 num=0
4 for i in {1..100}
5 do
6 num=$(($num+$i))
7 done
8 echo $num
4.輸入兩個數,求和、差、商、積、餘。必須使用$1 $2
1 #!/bin/bash
2 #
3 echo "兩個數的和是:echo $(($1+$2))"
4 echo "兩個數的差是:echo $(($1-$2))"
5 echo "兩個數的商是:echo $(($1/$2))"
6 echo "兩個數的積是:echo $(($1*$2))"
7 echo "兩個數的餘是:echo $(($1%$2))"
5.打印下列圖形


39/81




1 #!/bin/bash
2 for i in {1..4}
3 do
4 for j in {1..5}
5 do
6 echo -n ""
7 done
8 echo " "
9 done
1 #!/bin/bash
2 for ((i=1;i<=4;i++))
3 do
4 for ((j=1;j<=5;j++))
5 do
6 echo -n "
"
7 done
8 echo " "
9 done
1 read -p "輸入行數:" line
2 read -p "輸入多少個:" xing
3 for ((i=1;i<=$line;i++))
4 do
5 for ((j=1;j<=$xing;j++))
6 do
7 echo -n "
"
8 done
9 echo " "
10 done
6.
*
**






1 for ((i=1;i<=7;i++))
2 do
3 for ((j=1;j<=i;j++))
4 do
5 echo -n ""
6 done
7 echo " "
8 done
1 read -p "輸入行數:" line
2 for ((i=1;i<=$line;i++))
40/81
3 do
4 for ((j=1;j<=i;j++))
5 do
6 echo -n "
"
7 done
8 echo " "
9 done





  1. 1 #!/bin/bash
    2 for ((i=1;i<=4;i++))
    3 do
    4 for ((r=4;r>=i;r--))
    5 do
    6 echo -n "a"
    7 done
    8 for ((f=1;f<=i;f++))
    9 do
    10 echo -n ""
    11 done
    12 for m in seq 2 $i
    13 do
    14 echo -n "
    "
    15 done
    16
    17 echo
    18 done
    1 #!/bin/bash
    2 for ((i=1;i<=4;i++))
    3 do
    4 for ((j=4;j>=i;j--))
    5 do
    6 echo -n " "
    7 done
    8 for ((k=1;k<=2i-1;k++))
    9 do
    10 echo -n "
    "
    11 done
    12 echo
    13 done
    41/81
    1 #!/bin/bash
    2 read -p "輸入行數:" num
    3 for ((i=1;i<=$num;i++))
    4 do
    5 for ((j=$num;j>=i;j--))
    6 do
    7 echo -n " "
    8 done
    9 for ((k=1;k<=2i-1;k++))
    10 do
    11 echo -n "
    "
    12 done
    13 echo
    14 done
    7./test目錄下有100個文件
    統一給這些文件改名,格式爲:a.bak
    1 #!/bin/bash
    2 for i in ls /test
    3 do
    4 mv /test/$i /test/$i.bak
    5 done
    8./test目錄下有a.bak aa.bak C.b.bak等以.bak結尾的文件,將這些文件有.bak改名爲.txt
    1 for i in ls /test/*.bak
    2 do
    3 mv $i ${i%.*}.txt
    4 done

9.輸入J計算1..100內所有奇數相加之和,輸入O計算1..100內所有偶數相加之和
1 read -p "請輸入J或者O:" num
2 a=0
3 num=$(echo $num | tr "a-z" "A-Z" )
4 if [ "$num" == "J" ]
5 then
6 for i in seq 1 2 100
7 do
8 a=$(($a+$i))
9 done
10 echo $a
11 elif [ "$num" == "O" ]
12 then
13 for i in seq 2 2 100
14 do
15 a=$(($a+$i))
16 done
17 echo $a
18 else
19 echo "Usage:<J|O>"
20 fi

1 read -p "請輸入J或者O:" num
2 a=0
3 case $num in
4 J |j)
42/81
5 for i in seq 1 2 100
6 do
7 a=$(($a+$i))
8 done
9 echo $a
10 ;;
11 O |o)
12 for i in seq 2 2 100
13 do
14 a=$(($a+$i))
15 done
16 echo $a
17 ;;
18 )
19 echo "Usage:<J|O>"
10.寫一個腳本,使用case和函數現實,能夠對/etc/目錄進行打包,打包後存儲到/backup目錄下並命名爲
etc年-月-日.bak的格式
顯示如下菜單給用戶:
xz) xz compress
gzip) gzip compress
bzip2) bzip2 compress
根據用戶指定的壓縮工具使用tar進行打包壓縮,輸入錯誤就提示給用戶一個幫助信息,幫助信息爲“腳本
名 Usage:<xz|gzip|bzip2>”
1 #!/bin/bash
2 #
3 echo "壓縮方式有以下三種:"
4 echo -e "\txz)xz compress"
5 echo -e "\tgzip) gzip compress"
6 echo -e "\tbzip2) bzip2 compress"
7
8 name=etc
date +%F.bak.tar
9 xz() {
10 tar cJf /backup/$name.xz /etc &>/dev/null
11 echo "/etc目錄使用xz方式歸檔壓縮成功"
12 }
13
14 gzip() {
15 tar czf /backup/$name.gz /etc &>/dev/null
16 echo "/etc目錄使用gzip方式歸檔壓縮成功"
17 }
18
19 bzip2() {
20 tar cjf /backup/$name.bz2 /etc &>/dev/null
21 echo "/etc目錄使用bzip2方式歸檔壓縮成功"
22 }
23
24 if [ -e /backup ]
25 then
26 if [ ! -d /backup ]
27 then
28 mv /backup /backup.bak
29 mkdir /backup
30 fi
43/81
31 else
32 mkdir /backup
33 fi
34
35 read -p "請輸入壓縮的方式:" ys
36 case $ys in
37 xz)
38 xz
39 ;;
40 gzip)
41 gzip
42 ;;
43 bzip2)
44 bzip2
45 ;;
46
)
47 echo "$0 Usage:<xz|gzip|bzip2>"
48 esac
11.寫一個腳本,顯示如下菜單給用戶:
cpu)print cpu information;
disk) print disk information;
mem)print memory information;
quit)quit;
Pleas enter your option:
根據用戶輸入的顯示相應的信息,如果用戶輸入的不是以上幾種就顯示幫助信息,幫助信息爲“Pleas
enter your option:<cpu|disk|mem|quit>”
1 #!/bin/bash
2 echo "可以查詢的系統信息如下"
3 echo -e "\tcpu)print cpu information;"
4 echo -e "\tdisk) print disk information;"
5 echo -e "\tmem)print memory information;"
6 echo -e "\tquit)quit;"
7
8 read -p "Pleas enter your option:" ss
9 case $ss in
10 cpu)
11 cat /proc/cpuinfo
12 ;;
13 disk)
14 df -h
15 ;;
16 mem)
17 cat /proc/meminfo
18 ;;
19 quit)
20 echo "byebye"
21 ;;
22 )
23 echo "Pleas enter your option:<cpu|disk|mem| quit>"
24 esac
1 #!/bin/bash
2 echo "可以查詢的系統信息如下"
3 echo -e "\tcpu)print cpu information;"
44/81
4 echo -e "\tdisk) print disk information;"
5 echo -e "\tmem)print memory information;"
6 echo -e "\tquit)quit;"
7
8 for ((i=1;i>0;i++))
9 do
10 read -p "Pleas enter your option:" ss
11 ss=echo $ss | tr "A-Z" "a-z" (將大寫改爲小寫)
12 case $ss in
13 cpu)
14 cat /proc/cpuinfo
15 ;;
16 disk)
17 df -h
18 ;;
19 mem)
20 cat /proc/meminfo
21 ;;
22 quit)
23 exit 0
24 ;;
25
)
26 echo "Pleas enter your option:<cpu|disk|mem| quit>"
27 esac
28 done
shell腳本
shell學習目標
1.shell的特性
2.shell變量
3.shell條件測試
4.shell數值運算
5.流程、循環
6.正則表達式
7.sed
8.awk

cat ~/.vimrc

45/81
set nu
set ts=4
set ic
set ci
set si
set sw=4

shell腳本(script):
shell腳本文件:是一種linux操作命令的集合文件。用戶運行腳本文件時就會自動執行文件中的命令。

入門級(初級)腳本:腳本文件中僅包含一些操作命令,無任何邏輯判斷語句。這種腳本只會按從上到下的
順序來執行命令,如果某行命令錯誤會自動跳過。
高級腳本:在入門級腳本的基礎上加入條件判斷if、循環(for、while、until)等邏輯控制語句,讓腳本更具
有通用性和可移植性。
如何提高自己的腳本編寫水平:經常到網上去看一些別人寫的腳本,從中取經。

計算機語言分類:
解釋型語言:語法沒有很嚴格的要求,也稱爲弱語言(語法要求弱)。通常有shell腳本、html網頁語言、
python語言、java script、VBscript、PHP、bat批處理(Windows腳本)等。腳本程序用notepad記事本、
vi/vim、notepad++等純文本文件編輯軟件來編寫即可。
編譯型的語言:語法要求很嚴格,也稱爲強語言。通常有C、C++、C#、Visual Basic、java、delphi等。編
譯型的語言編寫的源程序代碼需要通過編譯成計算機能夠識別的二進制文件才能夠運行。例如系統中的ls、
date、lsblk等命令都是用c語言編寫,然後編譯成命令文件,所以我們才能直接運行這個命令。這種程序的
運行效率高。
shell腳本的運行的過程:調用腳本文件中的命令--〉shell命令解釋器--〉kernel內核--〉hardware
硬件
高級語言的程序運行過程:二進制程序文件--〉kernel內核--〉hardware硬件
實例:編寫一個入門級的腳本文件01.sh,要實現的功能是執行clear
echo QQ:12700696、cd、ls、pwd、sleep 5s、date、lsblk命令。給01.sh添加x可執行權限,運行
01.sh腳本程序。
第1步,編寫01.sh腳本文件。
mkdir /sh
vim /sh/01.sh 文件內容如下
#!/bin/bash
#date:2019-02-18
#Author By : jim
#Decription: this is my first shell script.
clear
echo QQ:12700696
cd
ls
pwd
sleep 5s
date
lsblk
46/81
第2步,添加可執行權限,運行腳本。
chmod -v +x /sh/01.sh
. /sh/01.sh 或 source /sh/01.sh 或 /sh/01.sh 或 sh /sh/01.sh 或 bash /sh/01.sh
運行腳本並顯示腳本的執行過程:sh -x /sh/01.sh
技巧:
shell腳本學習的幫助文檔:man bash
練習:執行如下操作,來學習bash幫助文檔的使用。
man bash 分別執行如下操作,分別查看這些關鍵字代碼的內容幫助
/if
/while
/until
/test
/&&
test
shell的條件測試
格式1:test 條件表達式
格式2:[ 條件表達式 ]
格式3:[[ 條件表達式 ]] 支持正則表達式 && ||
給x變量賦值爲1314520:x=1314520
顯示變量的值:echo $x
變量:變量是用來存儲某個具體的值的,值可以是數值、任意字符。程序中用變量可以讓程序變得更靈
活。
查上一條命令結果的狀態碼:echo $?
說明:$?是系統的預定義變量,是用來存上一條命令的狀態碼的變量。
狀態碼: 成功爲0 失敗爲非0
47/81
練習:執行如下操作,瞭解命令結果的狀態碼的值。
date
echo $?
xxxxx
echo $?
ls /kkkk
echo $?
date stx
echo $?
條件判斷的組合: -a -o -n
&& 邏輯與
-a
條件表達式1 && 條件表達式2
條件表達式1 -a 條件表達式2
|| 邏輯或
-o
條件表達式1 || 條件表達式2
條件表達式1 -o 條件表達式2

! 非,取反
! 條件表達式
-n 條件表達式
==文件測試===
根據文件類型判斷
-e 判斷文件是存在
例:
[root@client tmp]# test -e /tmp
[root@client tmp]# echo $? 存在 狀態返回值爲0
0
[root@client tmp]# test -e /tmpdahs 不存在 狀態返回值爲1
[root@client tmp]# echo $?
1
-e 判斷文件名是存在
-d 判斷文件是存在且是爲目錄文件
-f 判斷文件是存在且是爲普通文件
-p 判斷文件是存在且是爲管道文件
-b 判斷文件是存在且是爲塊設備文件
-c 判斷文件是存在且是爲字符設備文件
-L 判斷文件是存在且是爲軟鏈接文件
-S 判斷文件是存在且是爲套接字文件
根據文件權限判斷
-r 判斷文件是存在且是有“可讀權限”
-w 判斷文件是存在且是有“可寫權限”
48/81
-x 判斷文件是存在且是有“可執行權限”

[root@client tmp]# test -r a.a.pdf 有讀權限 狀態返回值爲0
[root@client tmp]# echo $?
0
[root@client tmp]# test -x a.a.pdf 無執行權限 狀態返回值非0
[root@client tmp]# echo $?
1
文件內容非空白的判斷
-s 判斷文件是存在且文件內容非空白
[root@client tmp]# test -s /etc/passwd
[root@client tmp]# echo $? 非空,有內容 狀態返回值爲0
0
[root@client tmp]# test -s a.pdf 爲空 狀態返回值非0
[root@client tmp]# echo $?
1
==數值比較===
-gt 大於
-lt 小於
-eq 等於
-ge 大於等於
-le 小於等於
-ne 不等
[root@client tmp]# test 5 -gt 3 5大於3 結果爲真 狀態返回碼爲0
[root@client tmp]# echo $?
0
[root@client tmp]# test 3 -gt 3 3大於3 結果爲假 狀態返回碼爲非0
[root@client tmp]# echo $?
1
[root@client tmp]# A=5
[root@client tmp]# B=3
[root@client tmp]# test $A -gt $B
[root@client tmp]# echo $?
0
[root@client tmp]# test $B -gt $A
[root@client tmp]# echo $?
1
==字符串比較== 字符串一定要用引號引起來
== 等值比較
= 等值比較
[root@client tmp]# A=hello
[root@client tmp]# test $A == hello 結果爲真 返回值0
[root@client tmp]# echo $?
0
[root@client tmp]# test $A == hell0 結果爲假 返回值非0
[root@client tmp]# echo $?
1
49/81
!= 不等值比較
[root@client tmp]# A=hello
[root@client tmp]# test $A != hello 結果爲假 返回值非0
[root@client tmp]# echo $?
1
[root@client tmp]# test $A != hell0 結果爲真 返回值0
[root@client tmp]# echo $?
0
=~ 判斷左側字符串或者變量是否符合右側的模式
-z 判斷字符串是空
[root@client tmp]# unset A
[root@client tmp]# unset B
[root@client tmp]# A=8
[root@client tmp]# test -z $A 結果爲假 返回值非0
[root@client tmp]# echo $?
1
[root@client tmp]# test -z $B 結果爲真 返回值0
[root@client tmp]# echo $?
0

命令的邏輯執行
命令1 && 命令2 當命令1執行成功時會執行命令2
命令1 || 命令2 當命令1執行失敗時會執行命令2
例:
[ -d /etc ] && echo 目錄已存在 || echo 目錄不存在
[ -d /etck ] && echo 目錄已存在 || echo 目錄不存在
if語句
if條件語句:
3種結構:
if結構1:單條件,單分支。如果滿足if後面的條件1(即條件的結果狀態碼爲真[即爲0]),就執行then後面的
語句。
if 條件1;then
command命令1
command命令2
fi
if語句的簡寫如下(命令的邏輯與執行):
命令1 && 命令2 等同於 if 條件1;then 命令列表;fi
50/81
例如:用if的結構1做如下測試。
x=abc;y=abc;z=123
if [ $x = $y ];then
echo yes
fi
if語句的簡寫如下:
[ $x = $y ] && echo yes
例如:判斷系統中是否存在root用戶,如果存在就提示yes。
用命令的邏輯執行來實現,方法如下:
id root && echo yes
用if語句來實現,寫法如下:
id root
if [ $? -eq 0 ];then
echo yes
fi
if結構2:單條件,雙分支。如果滿足if後面的條件1(即條件的結果狀態碼爲真[即爲0]),就執行then後面的
語句,否則執行else後面的語句。
if 條件1;then
command命令1
command命令2
else
command命令3
command命令4
fi
if雙分支的簡寫:
命令1 && 命令2 || 命令3
解釋:命令1執行成功(狀態碼爲0),就執行命令2,否則執行命令3.
例如:用if的結構2做如下測試。
x=abc;y=abc;z=123
if [ $x = $y ];then
echo yes
else
echo no
fi
if語句的簡寫如下:
[ $x = $y ] && echo yes || echo no
例如:判斷系統中是否存在/zk目錄,如果存在就刪除此目錄且顯示過程,否則創建此目錄且顯示過程
方法一:用命令的邏輯執行方法來實現的寫法。
[ -d /zk ] && rm -rfv /zk || mkdir -pv /zk
方法二:用if語句實現的寫法。
if [ -d /zk ];then
rm -rfv /zk
else
mkdir -pv /zk
fi
51/81
例如:判斷系統中是否存在zk用戶,如果存在就用userdel -r zk刪除此用戶,否則創建zk用戶。
方法一:用命令的邏輯執行方法來實現的寫法。
id zk && userdel -r zk || useradd zk
方法二:用if語句實現的寫法。
if id zk;then
userdel -r zk
else
useradd zk
fi
if結構3:多條件,雙分支。如果滿足if後面的條件1(即條件的結果狀態碼爲真[即爲0]),就執行then後面的
語句;否則測試elif後的條件2,滿足條件2就執行elif的then後面的語句;否則執行else後面的語句。
if 條件1;then
command命令1
command命令2
elif 條件2;then
command命令3
command命令4
else
command命令5
command命令6
fi
例如:用if的結構3做如下測試。做猜數字遊戲。
x=123
if [ $x -eq 123 ];then
echo 'you are right.'
elif [ $x -gt 123 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
例如:寫一個名稱爲/sh/cai.sh的腳本,要求提示用戶輸入數字,判斷數字大小是否爲520,如果是就提示
yes;如果大於520,就提示bigger;否則提示little。
第1步,編寫/sh/cai.sh腳本文件。
mkdir -pv /sh
vim /sh/cai.sh
#!/bin/bash
#description:this is crossword games.
read -p 'Please input your number:' x
if [ $x -eq 123 ];then
echo 'you are right.'
elif [ $x -gt 123 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
第2步,添加x可執行權限,測試腳本的運行。
chmod -v +x /sh/cai.sh
. /sh/cai.sh
52/81
shell test及案例
bash shell的幫助手冊:man bash
-gt大於 -ge大於或等於 -eq等於
-lt小於 -le小於或等於 -ne不等於
test 條件 語句 或 [ 條件 ]
功能:用來判斷文件、權限、值(數值是否相等、是否爲空)。
幫助手冊:man test
test練習:
項目一:字符串的長度、值的判斷測試。
練習:判斷字符串長度爲0則爲真(true,狀態碼爲0)
[root@node11 ~]# x=''
[root@node11 ~]# test -z $x
[root@node11 ~]# echo $?
0
練習:判斷字符串長度不爲0則爲真(true,狀態碼爲0)
[root@node11 ~]# x=1234
[root@node11 ~]# test -n $x
[root@node11 ~]# echo $?
0
練習:判斷字符串內容相等爲真(true,狀態碼爲0)
[root@node11 ~]# test abc = abc
[root@node11 ~]# echo $?
0
[root@node11 ~]# test abc = abcde
[root@node11 ~]# echo $?
1
練習:判斷字符串內容不相等爲真(true,狀態碼爲0)
[root@node11 ~]# test abc != abcde
[root@node11 ~]# echo $?
0
項目二:整數值的大小(相等eq、不相等ne、大於gt、小於lt、大於或等於ge、小於或等於le)判斷測試。
練習:執行如下操作,熟悉整數值的大小判斷測試。
x=1314
y=520
z=520
test $x -eq $y
echo $?
test $z -eq $y
echo $?
test $x -ne $y
53/81
echo $?
test $x -gt $y
echo $?
test $x -lt $y
echo $?
test $z -lt $x 520 < 1314
echo $?
test $x -ge $y 1314 >= 520
echo $?
test $z -ge $y 520 >= 520
echo $?
test $y -le $x 520 <= 1314
echo $?
test $y -le $z 520 <= 520
echo $?
項目三:文件類型(目錄d、普通文件-、字符設備c、塊設備b、軟鏈接l、管道p、套接字s)、文件大小(大小
爲0、不爲0)、文件的新舊、權限(ugo、rwx、facl、3種s權限等)的判斷測試。
[ -d /etc ]
echo $?
[ -f /etc/hosts ]
echo $?
[ -c /dev/tty ]
echo $?
[ -b /dev/sda ]
echo $?
[ -L /etc/rc.local ]
echo $?
find / -type p 在根目錄及其子目錄中查找類型爲管道的文件
[ -p /run/dmeventd-client ]
echo $?
find / -type s
[ -S /run/systemd/notify ]
echo $?
文件權限:判斷當前用戶對文件是否有可讀、可寫、可執行權限。-r、 -w、 -x
useradd ak
su - ak
pwd
touch a1
chmod -v 0 a1
[ -r a1 ] ; echo $?
chmod -v u+r a1
[ -r a1 ] ; echo $?
[ -w a1 ] ; echo $?
[ -x a1 ] ; echo $?
touch a2
[ -t 1 ] ; echo $? 文件描述符(FD,文件在內存中的數字代號)已在終端打開了
[ -t 168 ] ; echo $?
54/81
exit
複合條件判斷測試:邏輯非、邏輯與、邏輯或
[ ! abc = abcde ] ; echo $? 邏輯非
[ abc = abc -a 123 -eq 123 ] ; echo $? 邏輯與,同時滿足兩個條件就爲真(狀態碼爲0)
[ abc = abcd -o 123 -eq 123 ] ; echo $? 邏輯或,滿足其中一個條件就爲真(狀態碼爲0)

引號
單引號:單引號中的所有字符均作爲普通字符處理(即原樣輸出),即無法調用變量的值。
雙引號:雙引號中會自動識別特殊字符,即自動識別調用變量的值,如$、\n換行符、\t tab鍵、\r回車符
等特殊字符。
例:執行如下操作,理解單引號、雙引號的區別。
x=123abc 分別看以下命令輸出的結果有什麼不同
echo $x
echo '$x'
echo "$x"
echo -e '${x}_\n_welcome\tlinux'
echo -e "${x}
\n_welcome\t_linux"
說明:echo 的-e 選項是允許識別\n換行符、\t tab鍵、\r回車符特殊字符。

說明:${x}通常等同於$x,那麼什麼時候需要將變量名用{}大括號括起來呢?
答:當變量名後面緊貼着其他字符時,爲了避免歧義,就需要將變量名用{}大括號括起來。
例:執行如下操作,分別看輸出結果有何不同。以此來理解變量名爲何需要用{}大括號括起來。
x=123abc
xy=456
echo $x
echo $xy
echo $xy_haha 跟下一條命令對比結果
echo ${xy}haha 跟上一條命令對比結果
echo $x
$xy 跟下一條命令對比結果
echo ${x}_$xy 跟上一條命令對比結果
echo ${x}y
循環語句
for語句
55/81
for語句:
功能:在滿足條件的情況下,重複執行某些命令操作。
for語句結構:
for i in 值1 值2 ... 值n
do
命令列表
done
例:編寫一個名稱爲/sh/mk.sh的腳本,要求批量創建/test/a1~/test/a5這些目錄,同時顯示目錄創建的執
行過程。
第1步,編寫腳本文件。
vim /sh/mk.sh 腳本內容如下
#!/bin/bash
#description: this is a mkdir script.
for i in {1..5}
do
mkdir -pv /test/a$i
done
第2步,給腳本添加x可執行權限,測試腳本的運行。
chmod -v +x /sh/mk.sh
. /sh/mk.sh
例:編寫一個名稱爲/sh/user.sh的腳本,要求批量創建用戶u1~u5,並且在創建用戶之後查用戶的id號,並
且給每個用戶設置初始登錄密碼爲007。
第1步,編寫腳本文件。
vim /sh/user.sh 腳本內容如下
#!/bin/bash
#description: this is a useradd script.
for i in {1..5}
do
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
done
第2步,給腳本添加x可執行權限,測試腳本的運行。
chmod -v +x /sh/user.sh
. /sh/user.sh
第3步,對入門級的腳本進行如下優化。
1.在useradd創建用戶之前,判斷此用戶是否存在,如果存在就提示user exsits,否則創建此用戶並設置初
始登錄密碼爲007.
cp -av /sh/user.sh /sh/user-new.sh
vim /sh/user-new.sh 腳本內容如下
#!/bin/bash
#description: this is a useradd script.
for i in {1..5}
do
if (id u$i);then
echo "u$i user exsits."
else
56/81
useradd u$i
id u$i
echo 007 | passwd --stdin u$i
fi
done
第4步,測試新腳本的運行。
. /sh/user-new.sh
while語句
while功能:whatis while,得到的官方解釋“在條件滿足時重複的執行腳本中while的do和done之間的循
環體命令”。
簡單解釋:當滿足條件時,就進入循環。
while語法:
while 條件測試
do
cmd_list循環體
done
=======當條件測試成立(條件測試爲真),執行循環體
符合條件將一直循環
直到不符合條件(條件測試爲假)停止循環
練習:在命令行中執行以下操作,實現輸出10以內的正整數。
i=1
while [ $i -le 10 ]
do
echo $i
let i++ 或 $[i++] 或 $((i++))
sleep 1s 等待1秒(停頓1秒)
done

例:編寫一個名稱爲/sh/while_user.sh的腳本,要求用while循環語句,批量創建用戶w1~w5,並且在創建
用戶之後查用戶的id號,並且給每個用戶設置初始登錄密碼爲007。
第1步,編寫腳本文件。
vim /sh/while_user.sh
i=1
while [ $i -le 5 ]
do
useradd w$i && echo "w$i user added." || echo "w$i user exsits."
id w$i
echo 007 | passwd --stdin w$i
let i++
sleep 1s
done
第2步,給腳本添加x可執行權限,測試腳本的運行。
chmod -v +x /sh/while_user.sh
. /sh/while_user.sh
57/81
思考:編寫一個名稱爲/sh/del_users.sh的腳本,要求用while循環語句,批量查詢用戶w1~w5的id信息,然
後用userdel -r刪除這些用戶。
第1步,編寫腳本文件。
vim /sh/del_user.sh
i=1
while [ $i -le 5 ]
do
id w$i
userdel -r w$i && echo "w$i user removed." || echo "w$i user not exsits."
let i++
sleep 1s
done
第2步,給腳本添加x可執行權限,測試腳本的運行。
chmod -v +x /sh/del_user.sh
. /sh/del_user.sh

while死循環(無限循環):
while :
do
cmd_list循環體
done
例:執行如下while死循環語句,實現每隔2秒輸出echo命令的中的文本內容。[按ctrl+c強制終止死循環]
while :
do
echo 'I love you!'
sleep 2s
done

例:寫一個名稱爲/sh/cai.sh的腳本,要求用while循環控制語句,當用戶猜的數字錯了就連續重複猜(即提示
用戶"'Please input your number"),提示用戶輸入數字,判斷數字大小是否爲520,如果是就提示yes;
如果大於520,就提示bigger;否則提示little。
第1步,編寫/sh/cai-2.sh腳本文件。
mkdir -pv /sh
vim /sh/cai-2.sh
#!/bin/bash
#description:this is crossword games.
x=0
while [ $x -ne 520 ]
do
read -p 'Please input your number:' x
if [ $x -eq 520 ];then
echo 'you are right.'
elif [ $x -gt 520 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
done
第2步,添加x可執行權限,測試腳本的運行。
58/81
chmod -v +x /sh/cai-2.sh
. /sh/cai-2.sh
until
until功能:直到條件滿足時,就停止循環。
語法:
until 條件測試
do
循環體
done
=======當條件測試成立(條件測試爲假),執行循環體
不符合條件將一直循環
直到符合條件(條件測試爲真)停止循環
例:在命令行中執行如下操作,實現用until循環來輸出1~10這些數。
i=1
until [ $i -gt 10 ]
do
echo $i
let i++
done
思考:將while語句的猜字遊戲腳本/sh/cai-2.sh進行改寫,用until語句來實現。
第1步,編寫/sh/cai-3.sh腳本文件。
mkdir -pv /sh
vim /sh/cai-3.sh
#!/bin/bash
#description:this is crossword games.
x=0
until [ $x -eq 520 ]
do
read -p 'Please input your number:' x
if [ $x -eq 520 ];then
echo 'you are right.'
elif [ $x -gt 520 ];then
echo 'you are bigger'
else
echo 'you are little.'
fi
done
第2步,添加x可執行權限,測試腳本的運行。
chmod -v +x /sh/cai-3.sh
. /sh/cai-3.sh
59/81
循環實例
循環實例:
1.用for輸出1~100的求和結果。
2.用for語句輸出等腰直角三角形。
3.用for語句輸出九九乘法口訣表。
4.用for語句實現批量創建用戶、查用戶id號、設置用戶初始密碼。
例1:編寫一個名稱爲/sh/100jia.sh的腳本,要用for進行循環控制,實現輸出1+2+...+100的計算結果。
echo '#!/bin/bash
sum=0
for ((i=0;i<=100;i++))
do
sum=$[i+sum]
done
echo $sum
' > /sh/100jia.sh
chmod -v +x /sh/100jia.sh
. /sh/100jia.sh
例3:編寫一個名稱爲/sh/3ja.sh的腳本,用for進行循環控制,實現在屏幕上顯示一個5行由號組成的等腰
直角三角形。

**




解題思路:外層for循環控制三角形中星號的行數,內層for循環控制三角形中星號的列數。
echo '#!/bin/bash
for ((i=1;i<=5;i++))
do
for ((j=5;j>=i;j--))
do
echo -n ""
done
echo
done
' > /sh/3ja.sh
chmod -v +x /sh/3ja.sh
. /sh/3ja.sh
循環分析:for循環中每次i、j變量的取值分析。
第一次循環:
60/81
i=1 j=1
換行
第二次循環:
i=2 j=1
i=2 j=2 **換行
第二次循環:
i=3 j=1
i=3 j=2
i=3 j=3 **換行
第四、五次循環依次類推。
例4:編寫一個名稱爲/sh/3jb.sh的腳本,用for進行循環控制,實現在屏幕上顯示一個5行由
號組成的等腰
直角三角形。




*

echo '#!/bin/bash
for ((i=1;i<=5;i++))
do
for ((j=5;j>=i;j--))
do
echo -n ""
done
echo
done
' > /sh/3jb.sh
chmod -v +x /sh/3jb.sh
. /sh/3jb.sh
例4:編寫一個名稱爲/sh/99.sh的腳本,用for進行循環控制,實現在屏幕上顯示'九九乘法表口訣'。
1X1=1
1X2=2 2X2=4
1X3=3 2X3=6 3X3=9
……
61/81
1X9=9 2X9=18 …… 9X9=81
echo '#!/bin/bash
for ((i=1;i<=9;i++))
do
for ((j=1;j<=i;j++))
do
echo -ne "${j}X${i}=$[i
j]\t"
done
echo
done
' > /sh/99.sh
chmod -v +x /sh/99.sh
. /sh/99.sh
case語句
case功能:根據變量的取值不同,執行不同的命令操作。
case語句結構:
read -p 'please input your choice:' 變量名
case $變量名 in
值1)
命令1
命令2
;;
值2)
命令3
命令4
;;
)
命令5
命令6
;;
esac
例:編寫一個名稱爲/sh/menu.sh的腳本,要求顯示一個主菜單界面,提示用戶輸入功能選項,回車確認後
執行指定選項的命令操作。
第1步,根據項目需求,編寫出腳本內容。
vim /sh/menu.sh 入門級腳本內容如下:
echo '---------------------
62/81
1/a.Install NFS Service
2/b.Install Vsftpd Service
3/c.Install Samba Service
4/d.Install DNS Service
5/e.Install Apache Service
6/f.Install PXE Service
7/g.Install DHCP Service
0/
.Exit Shell Script
---------------------'
read -p 'please input your choice:' opt
case $opt in
1|a)
echo 'Install NFS Service'
. /sh/nfs-new.sh
;;
2|b)
echo 'Install Vsftpd Service'
. /sh/ftp-new.sh
;;
0|)
echo 'Exit Shell Script'
#exit 0
;;
esac
第2步,給腳本添加x可執行權限,測試腳本的運行。
chmod -v +x /sh/menu.sh
. /sh/menu.sh
63/81
模式匹配case
功能:根據用戶輸入的功能選項,執行對應功能選項的任務。
case的語法結構
case 變量 in
模式1)
命令序列1
;;
模式2)
命令序列2
;;
模式3)
命令序列3
;;

無匹配後的命令序列
esac
5.交互式腳本
需求:提示用戶輸入功能選項,選項1爲執行clear、date、創建jack用戶、設置jack密碼功能;選項2爲執
行clear、刪除jack用戶;如果輸入其他字符則提示“未輸入正確的功能選項,程序退出”,且自動退出腳
本。
64/81
vi case1.sh 代碼內容如下
#!/bin/bash
read -p "請輸入功能選項數字代號,如1、2...:" choice
case $choice in
1)
clear
date
useradd jack
echo jack | passwd --stdin jack
;;
2)
clear
id jack && userdel -r jack || echo "jack用戶不存在"
;;
)
echo "未輸入正確的功能選項,程序退出"
exit 1
esac
6.腳本中交互式實現
判斷用戶輸入的字符串,
如果用戶輸入的字符串爲start,就在/tmp下創建一個start文件;
如果用戶輸入的爲stop,那麼就刪除/tmp/start文件;
如果用戶輸入的爲restart,那麼就先刪除/tmp/start文件,然後創建一個start1文件;
如果用戶輸入其他的字符串,就輸出一個幫助信息:腳本名 Usage:{start|stop|restart}
read -p "請輸入字符串:" strings
case $strings in
start)
touch /tmp/start
;;
stop)
rm -rf /tmp/start
;;
restart)
if [ -e /tmp/start ]
then
rm -rf /tmp/start
else
touch /tmp/start1
fi
;;

echo "$0 Usage:{start|stop|restart}"
esac
1.超市賣水果
你輸入蘋果,顯示 蘋果 5元每斤
你輸入香蕉 ,顯示 香蕉 3元每斤
你輸入橘子,顯示 橘子 3元每斤
如果你輸入的不是蘋果 香蕉 橘子 就提示只能查詢 蘋果 香蕉 橘子
#!/bin/bash 可以把紅色的分別換成0,1,2或者apple|0),banana|1),orange|2)
read -p "輸入要查詢價格的水果名:" aa
65/81
case $aa in
apple)
echo "apple 5元每斤";;
banana)
echo "banana 3元每斤";;
orange)
echo "orange 3元每斤";;
)
echo "Usage :{apple|banana|orange}"
esac
11.寫一個腳本,顯示如下菜單給用戶:
cpu)print cpu information;
disk) print disk information;
mem)print memory information;
quit)quit;
Pleas enter your option:
根據用戶輸入的顯示相應的信息,如果用戶輸入的不是以上幾種就顯示幫助信息,幫助信息爲“Pleas
enter your option:<cpu|disk|mem|quit>”
1 #!/bin/bash
2 echo "可以查詢的系統信息如下"
3 echo -e "\tcpu)print cpu information;"
4 echo -e "\tdisk) print disk information;"
5 echo -e "\tmem)print memory information;"
6 echo -e "\tquit)quit;"
7
8 read -p "Pleas enter your option:" ss
9 case $ss in
10 cpu)
11 cat /proc/cpuinfo
12 ;;
13 disk)
14 df -h
15 ;;
16 mem)
17 cat /proc/meminfo
18 ;;
19 quit)
20 echo "byebye"
21 ;;
22
)
23 echo "Pleas enter your option:<cpu|disk|mem| quit>"
24 esac
66/81
技術回顧
test 檢測、判斷命令
test作用:檢測文件類型和比較值。
檢測文件類型:
-e FILE 文件名存在就爲真
-f FILE 文件名存在且爲普通文件就爲真
-d FILE 文件名存在且爲目錄就爲真
-b FILE 文件名存在且爲block塊設備文件就爲真
-S FILE 文件名存在且爲Socket套接字文件就爲真
-L FILE 文件名存在且爲symbolic link 符號鏈接(即快捷方式)文件就爲真
-c FILE 文件名存在且爲char字符設備文件就爲真
-p FILE 文件名存在且爲pipe管道文件就爲真
檢測文件權限:
-r FILE 當前用戶對此文件可讀就爲真
-w FILE 當前用戶對此文件可寫就爲真
-x FILE 當前用戶對此文件可執行就爲真
文件新舊檢測:
FILE1 -ef FILE2 文件1和文件2有相同的設備和inode索引號就爲真
FILE1 -nt FILE2 文件1的mtime新於(newer than)文件2就爲真
FILE1 -ot FILE2 文件1的mtime舊於(older than)文件2就爲真
邏輯與、或、非:
! EXPRESSION 非,EXPRESSION表達式的值(狀態碼)取反,狀態碼0的取反值爲1
EXPRESSION1 -a EXPRESSION2 邏輯與,-a左右兩邊表達式的值都爲真就爲真
EXPRESSION1 -o EXPRESSION2 邏輯或,-o左右兩邊表達式的值一個爲真就爲真
字符串檢測:
string1 = string2 字符串內容相同就爲真(狀態碼爲0)
string1 != string2 字符串內容不相同就爲真(狀態碼爲0)
-z string1 字符串長度爲0就爲真(狀態碼爲0)
-n string1 字符串長度不爲0就爲真(狀態碼爲0)
整數檢測:
int1 -eq int2 相等(equal)
int1 -ne int2 不相等(no equal)
int1 -gt int2 大於(greater than)
int1 -ge int2 大於或等於(greater or equal than)
int1 -lt int2 小於(less than)
int1 -le int2 小於或等於(less or equal than)

if語句:
結構1:if單分支
if 條件;then
cmd_list
67/81
fi
結構2:if雙分支
if 條件;then
cmd_list1
else
cmd_list2
fi
結構3:if多分支
if 條件1;then
cmd_list1
elif 條件2;then
cmd_list2
else
cmd_list3
fi

for循環語句:
for結構1:shell腳本專用的語法結構
for i in value1 value2 value3
do
cmd_list
echo $i
done
例:l爲矩形的長,其值固定爲2,i爲矩形的寬,其值爲2~6,用for循環來計算矩形的面積s,輸出s的值。
方法一:用$[公式]來實現計算。
l=2
for i in 2 3 4 5 6; do s=$[li]; echo $s; done
方法一:用$((公式))來實現計算。
l=2
for i in 2 3 4 5 6; do s=$((l
i)); echo $s; done

for結構2:C語言和shell腳本通用的語法結構
for ((i=0;i<=6;i++)) 說明:i++是i=i+1的簡寫,i=i+2可寫成i+=2
do
cmd_list
echo $i
done
函數
函數

完成特定功能的代碼段(塊)
68/81
在shell中定義函數可以使用代碼模塊化,便於複用(即重複使用)代碼
函數必須先定義纔可以使用
一、定義函數
方法一:
函數名() {
函數要實現的功能代碼
}
方法二:
function 函數名 {
函數要實現的功能代碼
}
a=789
[root@node11 ~]# function a {

echo $a
}
a
例:查看functions、network服務的控制腳本文件內容,其中就有函數。
cat -n /etc/rc.d/init.d/functions | more
cat -n /etc/rc.d/init.d/network | more
二、函數的調用
函數名
1.函數外的參數能被函數調用
#!/bin/bash
a=123
num_1() {
echo $a
}
num_1
2.函數內的參數也能被函數調用
#!/bin/bash
num_2() {
a=456
}
num_2
echo $a
3.使用local來隔離變量,
使參數只能在函數內調用
vim /sh/f.sh
#!/bin/bash
a=love
num_3() {
local a=789
echo "in num_3"
echo $a
69/81
}
num_3
echo "out of num_3"
echo $a
[root@today tmp]# bash /sh/f.sh
in num_3
789
out of num_3
love

項目案例:以下是centos 6系統的服務管理(start啓動、stop停止、restart重啓、reload平滑重啓、status
狀態)腳本的基本框架參考代碼。
#!/bin/bash
#
start() {
touch /tmp/start
}
stop() {
rm -rf /tmp/start
}
read -p "請輸入字符串:" strings
if [ $strings == "start" ]
then
start
elif [ $strings == "stop" ]
then
stop
elif [ $strings == "restart" ]
then
stop
start
else
echo "$0 Usage:{start|stop|restart}"
fi
作業
練習:編寫一個名稱爲/sh/admin.sh的腳本,要求綜合實現如下功能:
1.clear清屏,顯示'admin menu'功能菜單。admin menu菜單內容如下:
-----admin menu-----

  1. install NFS
  2. install Vsftpd
  3. Install Samba
  4. Install httpd
  5. Install DHCP
    70/81
  6. Install PXE
  7. Stop Firewalld and Selinux
  8. Configuration Local Yum
  9. add Users
  10. Install DNS

    2.提示用戶"輸入功能選項的數字編號"。
    3.用case語句取判斷用戶輸入的功能選項,來執行功能選項所對應的操作命令。
    4.需要將admin menu菜單中的每個功能定義成函數,在case語句中調用不同的函數。
    vim /sh/admin.sh 腳本內容如下
    #!/bin/bash
    echo '-----admin menu-----
    1.install NFS
    2.install Vsftpd
    3.install Samba
    4.install Httpd
    5.install DHCP
    6.install PXE
    7.Stop Firewalls and Selinux
    8.Configuration Local Yum
    9.add Users
    10.Instsall DNS
    -----------------------'
    _NFS(){
    soft='nfs-utils rpcbind'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _Vsftpd(){
    soft='vsftpd lftp ftp'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _Samba(){ soft='samba samba-comment samba-client'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _Httpd(){ soft='Httpd'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _DHCP(){ soft='dhcpd'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _PXE(){ soft='vsftpd dhcpd tftp-server '
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    _firewalld(){
    systemctl stop firewalld
    getenforce
    }
    _yum(){ [ -d /iso ] && echo '/iso is exists' || mkdir -pv /iso
    lsblk | grep iso && echo 'iso is mounted.' || mount /dev/cdrom /iso
    cd /etc/yum.repos.d
    [ -d bak ] && echo 'bak directory exsits.' || mkdir -pv bak
    71/81
    mv -fv .repo bak
    echo '[centos7.6]
    name=centos 7.6 linux
    baseurl=file:///iso
    enabled=1
    gpgcheck=0
    ' >/etc/yum.repos.d/iso.repo
    yum clean all
    yum repolist
    }
    _addusers(){ i=wl
    id $i && echo 'user is exists' || useradd $i
    }
    _DNS(){ soft='bind bind-utils'
    rpm -q $soft && echo "$soft exists" || yum -y install $soft
    }
    read -p '輸入功能選項的數字編號:' i
    case $i in
    1)
    _NFS
    ;;
    2)
    _Vsftpd
    ;;
    3)
    _Samba
    ;;
    4)
    _Httpd
    ;;
    5)
    _DHCP
    ;;
    6)_PXE
    ;;
    7)_firewalld
    ;;
    8)_yum
    ;;
    9)_addusers
    ;;
    10)_DNS
    ;;
    )
    echo 'input error shell.exit'
    ;;
    esac
    算術運算
    72/81
    1.整數運算
    方法一:expr

    expr 1 + 2

    3
    [root@client tmp]# A=156
    [root@client tmp]# B=456
    [root@client tmp]# expr $A + $B
    612
    +

    *
    /
    % 取模(取餘數),取除法運算後的餘數。例:expr 7 % 2
    方法二:$(()) + - / %
    [root@client tmp]# echo $((6
    9))
    54
    [root@client tmp]# echo $(((9-6)9))
    27
    [root@client tmp]# echo $((31%2))
    1
    [root@client tmp]# sum=$((6
    9));echo $sum
    54
    方法三:$[] + - * / %
    [root@client tmp]# echo $[456+789]
    1245
    方法四:let
    let
    [root@client tmp]# let num2=9+25 ;echo $num2
    34
    說明:let命令中,要想輸出表達式的計算結果,必須把表達的結果賦值給一個變量,然後用echo 輸出這
    個變量的值。
    Linux計算器:

    bc //交互式操作

    9/2
    4
    scale=2 //指定精度,精度就是小數點後保留幾位小數
    9/2
    4.50
    ctrl d 退出
    非交互式操作
    [root@client tmp]# echo "0.36+356" | bc
    356.36
    [root@client tmp]# echo "scale=6;10/3" |bc
    3.333333
    進制之間的轉換
    73/81
    [root@client tmp]# echo "ibase=2;11111111" | bc //將二進制數轉成十進制數
    255
    [root@client tmp]# echo "ibase=10;obase=16;11" | bc //將十進制數轉成16進制數
    B
    說明:十六進制數由0~9、A~F這十六個元素組成。
    [root@client tmp]# echo "ibase=10;obase=2;255" | bc /將十進制數轉成二進制數
    11111111
    附錄:2的冪
    2的冪: 10 9 8 7 6 5 4 3 2 1 0
    十進制: 1024 512 256 128 64 32 16 8 4 2 1

數組
數值:
賦值100個變量,這樣要起100個變量名,數組的話使用1個名稱就可以了,後跟100個值,在訪
問值的時候要使用下標的方式

聲明:
declare -a 數組名 聲明變量爲數組類型
declare -i 變量名 聲明變量爲整數數字類型
[root@client tmp]# num=6+5
[root@client tmp]# echo $num
6+5
[root@client tmp]# declare -i num=6+5
[root@client tmp]# echo $num
11

declare -x 變量名 聲明變量爲環境變量 用法和export一樣
declare -r 變量名 聲明變量爲readonly類型,只讀類型,變量的內容不可改

declare -a array

declare -a array1

定義數組: 變量值稱爲數組的元數
方法一:一次賦一個值
數組名[下標]=值

array[0]=apple

array[1]=orange

array[2]=banana

方法二:一次賦多個值
數組名=(值1 值2 值3 ...)

array1=(tom jim jack)

查看數組
74/81

declare -a |grep arr

declare -a array='([0]="apple" [1]="orange" [2]="banana")'
declare -a array1='([0]="tom" [1]="jim" [2]="jack")'

訪問數組元數:

echo ${array[0]} 訪問數組中的第一個元數

apple

echo ${array[*]} 訪問數組中的所有元數 數組的遍歷

echo ${array[@]}

echo ${#array[@]} 統計數組元數的個數

echo ${#array[*]}

echo ${!array[@]} 獲取數組元數的索引

0 1 2

echo ${array[@]:1} 從數組下標1開始

orange banana

echo ${array[@]:1:2} 從數組下標1開始,訪問2個元數

orange banana

declare -a | grep name

declare -a name='([0]="user1" [1]="user2" [2]="user3" [3]="user4" [4]="user5" [5]="user6")'
[root@client ~]# echo ${name[@]}
user1 user2 user3 user4 user5 user6

user2 user3 user4 user5 user6

user4 user5 user6

user3 user4 user5
取消數組
#unset 數組名

echo ${name[@]}

user1 user2 user3 user4 user5 user6

for i in ${name[@]};do echo $i ;done

user1
user2
user3
user4
user5
user6
1.超市賣水果
你輸入蘋果,顯示 蘋果 5元每斤
你輸入香蕉 ,顯示 香蕉 3元每斤
你輸入橘子,顯示 橘子 3元每斤
如果你輸入的不是蘋果 香蕉 橘子 就提示只能查詢 蘋果 香蕉 橘子
vim /sh/fruit.sh 腳本內容如下:
#!/bin/bash
declare -a num
num=(apple banana orange)
read -p "輸入要查詢價格的水果名:" aa
if [ $aa == ${num[0]} ] ; then
75/81
echo "$aa 5元一斤"
elif [ $aa == ${num[1]} ] ; then
echo "$aa 3元一斤"
elif [ $aa == ${num[2]} ] ; then
echo "$aa 3元一斤"
else
echo "Usage :{apple|banana|orange}"
fi
case語句
#!/bin/bash
declare -a num
num=(apple banana orange)
read -p "input your fruits:" aa
case $aa in
0)
echo "apple 5元一斤"
;;
1)
echo "banana 3元一斤"
;;
2)
echo "orange 2元一斤"
;;
*)
echo "usage:{apple|banana|orange}"
;;
esac
~
例子:雙色球×××
red紅球: 33選6
blue藍球: 16選1

echo $RANDOM 輸出一個隨機數

echo $[$RANDOM%33+1]

echo $[$RANDOM%16+1]

最簡單的×××,但是紅球有可能重複
vim /sh/cp.sh 腳本內容如下
#!/bin/bash
for i in {1..6}
do
red[$i]=$[$RANDOM%33+1]
echo -ne "${red[$i]}\t"
done
echo
echo "$[$RANDOM%16+1]"
如何去除紅球的重複?
i=1
while [ $i -le 6 ]
do
redtmp=$[$RANDOM%33+1]
flag="yes"
for j in ${red[*]}
76/81
do
if [ $j -eq $redtmp ]
then
flag="no"
break
fi
done
if [ $flag = "yes" ]
then
red[$i]=$redtmp
let i++
fi
done
for i in {1..6}
do
echo -n "${red[i]} "
done
echo
echo "$[$RANDOM%16+1]"

正則表達式
正則表達式(正確的規則表達式):是用來做關鍵字匹配的。它是一種字符模式,是在匹配文本時,使用一
些特殊的符號,匹配用戶想要的東西
正則表達式、通配符的區別:應用場合不同
通配符:是用在查找文件名時或?或[關鍵字]來匹配文件名中不確定的字符。ls /dev/tty[135]?
正則表達式:是用在查看文件內容時^、$、+、
、?、[]、.等符號來匹配文件內容中不確定的字符。
字符模式:
普通字符:沒有特殊含義的字符 a b c
元字符:具有特殊含義的字符 ^ $ . []
shell元字符:
通配符 由shell來解析,Shell將解析爲任意多個字符
正則表達式元字符:
前導符 由各種執行模式匹配操作的程序來解析,比如vim(查找和替換)、
grep、egrep、sed、awk

何時用?
能夠使用正則表達式的命令:vim(查找和替換)、grep、sed、awk
匹配數字:^[0-9]+$ 例:echo -e '123\n456\n7s9' | egrep '^[0-9]+$' 輸出結果:123 456
匹配Mail:[a-z0-9]+@[a-z0-9]+.[a-z]+ 數字和字母@數字和字母.com [email protected]
例:echo -e '[email protected]\[email protected]\n58.com' | egrep '[a-z0-9]+@[a-z0-9]+.[a-z]+'
匹配ip地址:[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3} 例:1.2.3.4
77/81
[0-9]
[0-9][0-9]
[0-9][0-9][0-9]
例: echo -e '192.168.11.11\n172.16.5.3\na.b.c.d\n127.0.0.1' | egrep '[0-9]{1,3}.[0-9]{1,3}.
[0-9]{1,3}.[0-9]{1,3}'

例:編寫一個名稱爲/sh/zhz.sh的腳本,要求提示用戶輸入一個數字,判斷用戶輸入的是否是數字,如果是
就提示'yes',否則提示'no'。
vim /sh/zhz.sh
#!/bin/bash
read -p 'input a number:' x
echo $x | egrep -q '^[0-9]+$'
if [ $? -eq 0 ];then
echo 'yes'
else
echo 'no'
fi

[root@client ~]# grep "abc" /etc/passwd --color
abrt:x:173:173::/etc/abrt:/sbin/nologin
[root@client ~]# grep "roo
" /etc/passwd --color
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
rtkit:x:499:497:RealtimeKit:/proc:/sbin/nologin
基本正則表達式元字符
元字符 功能 例子 匹配結果
字符的匹配 . 匹配任意單個字符 /l.ve/ 匹配love、live...
[] 匹配一組字符中的任意一個 /l[Oo]ve/ 匹配love、lOve
[x-z] 表示匹配一段範圍中的任意一個 /l[a-c]ve/ 匹配lave、lbve、lcve
"^[a-Z0-9]+" 大小寫字母或數字
[0-9] 數字
[a-z] 小寫字母
[A-Z] 大寫字母
[0-9a-z] 小寫字母或數字
[^] 表示取反 /[^a-c]ove/ 匹配除了aove、bove、
cove以外的字符
次數的匹配
前導符(即號左邊的字符) 匹配號左邊的字符0個或多個 /lve/ 匹配
ve、lve、llve、lllllllllve...
x{m} 匹配x出現m次。 x是字符或字符串,m是一個數字 /a{3}/ 匹配到aaa
x{m,} 匹配x出現至少m次 /a{2,}/ 匹配到aa、aaa、aaaa...
x{m,n} 匹配x出現m次到n次 /a{2,4}/ 匹配到aa、aaa、aaaa
x{0,n} 匹配x出現最多n次 /a{0,3}/ 匹配到a、aa、aaa
位置的定位 ^ 行首定位符 /^root/ 匹配以root開頭的行
$ 行尾定位符 /bash$/ 匹配以bash結尾的行
\< 詞首定位符 /\<love/ 匹配到lovely、lover等.例:echo -e 'lovely
\nalove\nlover' | grep '\<love'
\> 詞尾定位符 /love\>/ 匹配到inlove等 .例:echo -e 'klove\inalove
\nlover' | grep 'love\>'
\b /love\b/
78/81
\ 用來轉義(將字符在普通意義和特殊意義之間轉換)元字符 /2.5/ 匹
配2.5
分組
(..) 將括號內的內容作爲一個單位來看(並且在內存中會用1~n記錄這些值),內容
可以是字串也可以是一個模式 (love)\1er 匹配loveloveer
# 引用前面第#個“(”和與之對應的“)”中的模式所匹配到的內容,#至少爲1
(ab)(ac)(dd) abacddacddab
(ab)(ac)(dd).
\2\3\1 abacddjjjacddab

:1,$ s/(192.168.1).20/\1.50/g 將.20替換成.50
:3,9 s/(.*)/#\1/ 匹配任意一個字符開頭加上#
:%s/172.16.1.1/172.16.1.5/ 將172.16.1.1替換成172.16.1.5
:% s/(172.16.1.)1/\15/ 172.16.1.
:% s/(172.)(16.)(1.)1/\1\2\35/g 172.16.1.1 172.16.1.5

正則表達式的組合:
.* :任意字符任意次 匹配0到多個任意字符
^$:匹配空白行
擴展正則表達式元字符
元字符 功能 例子 匹配結果
? 表示0個或1個它前面的字符 a?d ad d aad

  • 表示1個或多個它前面的字符 a+d ad d aad aaad...
    | 或者 a|b a b aa
    ()
    (..)(..)\1\2
    x{m} 前置字符x出現了m次
    x{m,}
    x{m,n}
    x{0,n}
    \d 匹配0~9數字(digital) ????????
    POSIX字符集
    表達式 功能 示例 例子 等同於
    [:alnum:] 字母和數字 [[:alnum:]]+ [a-Z0~9]
    [:alpha:] 字母(包括大小寫字母) [[:alpha:]]{4}
    [:lower:] 小寫字母
    [:upper:] 大寫字母
    [:digit:] 數字 [[:digit:]]?
    [:blank:] 空格和製表符 [[:blank:]]
    [:punct:] 標點符號
    [:space:] 包括換行符,回車等所有空白
    grep 基本正則表達式
    grep -E 或 egrep 支持擴展表達式
    例:
    ip a | egrep '[[:alpha:]]'
    echo -e 'aaa\naaaaaa\naaaa\nccc\ncccc' | egrep '[[:alpha:]]{4}'
    79/81
    grep執行狀態的返回值三種
    0 :該文件中搜索到匹配行
    1 :該文件中沒有搜索到匹配行
    2 :搜索文件不存在
    思考練習:
    1.如果輸入小寫字母,提示輸入的是小寫字母
    如果輸入大寫字母,提示輸入的是大寫字母
    如果輸入的是數字,提示輸入的是數字
    如果輸入的是其他內容,提示只能輸入字母數字空白
    vim /sh/char.sh 參考內容如下
    #!/bin/bash
    read -p 'input your char:' x
    if echo "$x" | egrep -wq '[[:lower:]]
    ' ;then
    echo 'lower word.'
    elif echo "$x" | egrep -wq '[[:upper:]]' ;then
    echo 'upper word.'
    elif echo "$x" | egrep -wq '[[:digit:]]
    ' ;then
    echo 'number word.'
    else
    echo 'only input word 、 number、blank.'
    fi
    2.使用ifconfig命令查找ip地址,使用正則表達式只顯示ip地址
    1~254.1~254.1~254.1~254
    1-9
    10-99
    100-199
    200-249
    250-254

    grep "\<[1-9]\>|\<[1-9][0-9]\>|\<1[0-9][0-9]\>|\<2[0-4][0-9]\>|25[0-4]" --color /tmp/

    num1.txt

    grep "\<[1-9][0-9]{0,1}\>|\<1[0-9]{2}\>|\<2[0-4][0-9]\>|25[0-4]" --color /tmp/

    num1.txt

作業

  1. 把每個數字用()括起來
    :%s/([0-9])/(\1)/g
    :%s/([[:digit:]])/(\1)/g
    80/81
  2. 匹配ip每個十進制數的範圍是1~255

    grep -E "\<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-4])\>" /tmp/aa.txt

  3. for ping測試指定網段的主機
    網段由用戶輸入,例如用戶輸入192.168.1,則ping 192.168.1.1~192.168.1.20
    ping通的主機將主機的ip地址保存在/tmp/host_up.txt UP:/tmp/host_up.txt
    ping不通的主機將主機的ip地址保存在/tmp/host_down.txt Down:/tmp/host_down.txt
    vim /sh/ping.sh
    #!/bin/bash
    #

    /tmp/host_up.txt
    /tmp/host_down.txt
    read -p "請輸入一個網段:" wd
    for ((i=1;i<=20;i++))
    do
    ( ping -c 2 -W 1 "$wd".$i > /dev/null
    if [ $? -eq 0 ];then
    echo "${wd}.${i} up" | tee -a /tmp/host_up.txt
    else
    echo "${wd}.${i} down"| tee -a /tmp/host_down.txt
    fi
    )&
    done
    4.匹配用戶名是三個字符的用戶
    :^[^:][^:][^:]\>

    grep "^[^:][^:][^:]>\" /tmp/test

5.刪除每行的倒數第二個字符
:%s/(.)(.)$/\2/
6.搜索包含2個o的行
o+.*o+
7.顯示/boot/grub/grub.conf中至少一個空白字符開頭的行

grep "^[[:space:]]{1,}" /boot/grub/grub.conf

grep "^[[:space:]]+" /boot/grub/grub.conf

8.顯示/etc/rc.d/rc.sysinit文件中,以#開頭,後面跟至少一個空白字符,而後又有至少一個非空白字符的

grep "^#[[:space:]]{1,}[^[:space:]]{1,}" /etc/rc.d/rc.sysinit

grep "^#[[:space:]]+[^[:space:]]+" /etc/rc.d/rc.sysinit

egrep "^#[[:space:]]+[^[:space:]]+" /etc/rc.d/rc.sysinit

81/81

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章