Linux13:shell腳本基本命令


shell腳本基本命令

輸出命令echo

輸出命令echo,基本模式就是echo [選項] [輸出內容]輸出內容如果包含空格,則必須將內容用雙引號括起來。選項-e可以使輸出語句支持反斜線轉義。

加入退格后就不會顯示退格符左邊的一個字符。ascii碼表中有對應的八進制和十六進制表示法,所以可以表示對應的字符。

顯示環境變量的值:echo ${PATH}echo $PATH,如果一個變量沒有被設定,那么就什么都不返回。

顏色輸出如將abcd用紅色打印:echo -e "\e[1;31m abcd \e[0m"其中\e[1的意思是開啟顏色輸出,而\e[0m是結束顏色輸出,31m代表紅色,abcd是輸出內容,其他顏色如下:

第一個腳本與腳本執行方式

新建一個腳本hello.sh:

#!/bin/bash
#the first program

echo "hello world"
exit 0

其中第一行是聲明,不是注釋,不能省略,這是在指定使用哪個shell,如果沒有這行有的程序可能無法執行。

第二行#開頭的是注釋,第四行是命令。

最后一行在設置回傳值,在執行完該腳本后,執行echo $?就能查看這個值,可以通過這個自定義錯誤信息。

在腳本中有需要時要重新定義一下PATH環境變量,以便直接使用一些外部命令而不是寫絕對路徑:

PATH=/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/module/jdk1.8.0_144/bin:/opt/module/hadoop-2.7.2/bin:/opt/module/hadoop-2.7.2/sbin:/root/bin
export PATH

執行shell腳本要先賦予其可rx權限:chomd 755 hello.sh然后再執行./hello.sh這里也可以用絕對路徑執行。或者用bash命令執行(這種執行方法只要對腳本有r權限就可以執行):bash hello.sh,此時屏幕上就會打印hello world,sh hello.sh也一樣。也可以將文件放入PATH指定的路徑中,直接執行文件名就能運行了。(直接執行一串指令:sh -c "指令1;指令2"

上述幾種腳本執行方式都屬於直接執行,這些執行方式本質上會使用一個新的bash環境來運行指令,這個子shell不會繼承父shell的普通變量,只能繼承環境變量,而子shell中定義的變量也不會在父shell中查到,在腳本運行完畢后,子shell中所有的數據都會移除。

另外一種腳本執行方式是source指令,該指令后跟腳本路徑就能執行,source執行腳本時不會開啟子shell,所以各指令的運行結果都會在原shell中生效,腳本中定義了變量,運行完畢后依然可以查到,所以該命令常常用在修改配置文件后。

寫腳本要養成一些良好的習慣,在開頭記錄一些關鍵的注釋:功能、版本信息、作者及聯絡方式、歷史記錄。重要的代碼也需要注釋。

條件判斷

判斷文件類型:

基本判斷格式有兩種:test -e /root/install.log[ -e /root/install.log ]注意后者方括號內兩邊都必須有空格(這樣處理主要是為了規避正則表達式)。這種判斷語句直接執行不會顯示正確還是錯誤,需要執行$?來查看該條命令執行結果。或者可以使用[ -e /root/install.log ] && echo "yes" || echo "no"根據打印結果來查看是否執行正確。

判斷文件權限:

這種方式只能判斷有沒有這種權限,而不會區分具體是屬主、屬組或者other擁有這種權限,想要細分權限需要自定義腳本提取ll命令的打印結果。

兩個文件比較:

兩個整數之間進行比較:

字符串或變量的判斷:

如果先執行name=sc再執行[ -z "$name" ] && echo "yes" || echo "no"則會輸出no,因為此時變量name不為空。如果將$name替換為$不存在的變量,那么結果就為yes。

如果執行aa=abcbb=abc,然后再執行[ "$aa" == "$bb" ]結果就為真,[ "$aa" == abc ]結果也為真,但是[ "$aa" == "bb" ]結果為假。

在條件判斷式方括號中有一些需要經常遵循的原則:

1、每個組件之間都要用空格隔開(為了防止兩邊沒有空格格式錯誤)

2、變量都要用雙引號括起來,常量用單引號或雙引號括起來

第二點原則其實和命令中的量用雙引號括起來的原因是一樣的,一旦出現空格就會發生一些錯誤,如執行:

[ a b=="$c" ],其實不是a b整體和c比較,而是b在和c比較,這個命令會直接報錯,應該這樣執行:

[ "a b"=="$c" ]

(在bash的判斷中使用一個等號和使用兩個結構是一樣的,但是推薦用兩個等號)

多重條件判斷:

if語句

單分支if條件語句:

if [ 條件判斷式 ];then
程序
fi

if [ 條件判斷式 ]
then
程序
fi

注意if中的條件判斷式方括號兩邊還是要有空格。

在if語句中,方括號和方括號之間也可以加邏輯運算符&&和||,下面兩行是等價的:

[ 判斷1 -o 判斷2 ]
[ 判斷1 ] || [ 判斷2 ]

雙分支if條件語句:

if [ 條件判斷式 ]
then
條件成立時,執行的程序
else
條件不成立時,執行的另一個程序
fi

多分支if條件語句:

if [ 條件判斷式1 ] 
	then 
		當條件判斷式1成立時,執行程序1 
elif [ 條件判斷式2 ] 
	then 
		當條件判斷式2成立時,執行程序2 
else 
	當所有條件都不成立時,最后執行此程序
fi

例1:判斷分區使用率

#!/bin/bash
#統計根分區使用率
rate=$(df -h | grep "/dev/sda3" | awk '{print $5}' | cut -d "%" -f1)
#把根分區使用率作為變量值賦予變量rate
if [ $rate -ge 80 ]
	then
		echo "Warning! /dev/sda3 is full!!"
fi

這個腳本是基於查看分區情況命令df -h的,從輸出內容中提取對應分區的對應列,然后去掉%,將值賦值給rate,然后用if語句判斷rate的值是否大於80,如果大於就打印警告信息,實際應用中這里應該給管理員發送郵件。

例2:備份mysql數據庫

#!/bin/bash
#備份mysql數據庫。
ntpdate asia.pool.ntp.org &>/dev/null
#同步系統時間
date=$(date +%y%m%d)
#把當前系統時間按照“年月日”格式賦予變量date
size=$(du -sh /var/lib/mysql)
#統計mysql數據庫的大小,並把大小賦予size變量
if [ -d /tmp/dbbak ]
	then
		echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
		echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
		cd /tmp/dbbak
		tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
		rm -rf /tmp/dbbak/dbinfo.txt
else
	mkdir /tmp/dbbak
	echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
	echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
	cd /tmp/dbbak
	tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
	rm -rf /tmp/dbbak/dbinfo.txt
fi

首先用if語句判斷日志目錄/tmp/dbbak是否存在,如果不存在就新建該目錄。

將date和size變量都輸出到dbinfo.txt文件中,然后將數據庫/var/lib/mysql和dbinfo.txt都打包到mysql-lib-$date.tar.gz文件中,這個文件的命名有一部分調用了date的值,這是為了保持壓縮文件文件名的唯一性,在打包過程中將命令執行過程中的打印內容全部輸出到/dev/null中,相當於刪除,&>表示無論語句執行正確與否都將打印內容重定向。打包完成后刪掉dbinfo.txt文件。

如果想獲取前兩天的日期:

date2=$(date --date='2 days ago' +%Y%m%d)

文件名也可以單獨拿出來拼接,這樣可讀性更強:

filename=${filename2}${date2}

例3:判斷apache是否啟動

#!/bin/bash
port=$(nmap -sT 192.168.1.156 | grep tcp | grep http | awk '{print $2}')
#使用nmap命令掃描服務器,並截取apache服務的狀態,賦予變量port
if [ "$port" == "open" ]
	then
		echo “$(date) httpd is ok!” >> /tmp/autostart-acc.log
else
	/etc/rc.d/init.d/httpd start &>/dev/null
	echo "$(date) restart httpd !!" >> /tmp/autostart-err.log
fi

nmap命令是判斷進程執行的重要命令,提取此命令的打印結果,得到占用狀態:

然后根據狀態進行if判斷,如果已經啟動就將已啟動輸出到日志,如果沒有啟動就開啟該服務,然后將已啟動命令輸出到日志。

例4:判斷用戶輸入的文件類型

#!/bin/bash
#判斷用戶輸入的是什么文件
read -p "Please input a filename: " file
#接收鍵盤的輸入,並賦予變量file
if [ -z "$file" ]
#判斷file變量是否為空
	then
		echo "Error,please input a filename"
		exit 1
elif [ ! -e "$file" ]
#判斷file的值是否存在
	then
		echo "Your input is not a file!"
		exit 2
elif [ -f "$file" ]
#判斷file的值是否為普通文件
	then
		echo "$file is a regulare file!"
elif [ -d "$file" ]
#判斷file的值是否為目錄文件
	then
		echo "$file is a directory!"
else
		echo "$file is an other file!"
fi

先用read命令接受鍵盤輸入,然后將輸入賦值給file,用if判斷file的類型,這里用exit來跳出多條件if語句,否則如果文件名為空的話還會繼續執行下一個條件。

case語句

case語句和多分支if語句類似,不同之處在於case語句判斷的條件關系只有一個。使用格式:

case $變量名 in
	"值1")
		如果變量的值等於值1,則執行程序1
		;;
	"值2")
		如果變量的值等於值2,則執行程序2
		;;
	*)
		如果變量的值都不是以上的值,則執行此程序
		;;
esac

function函數

基本格式:

function fname(){
	程序
}

fname就是函數名,也是調用時要執行的命令名。

注意在bash中調用函數一定要在定義函數之后,否則會報錯。定義好函數后就可以在后續程序中直接調用fname命令,此時就相當於執行代碼塊。調用該命令時也可以跟后續的參數,第一個參數是$1、第二個參數是$2..,在function中$0代表函數名稱,注意在函數內和函數外內建變量的值是不同的。

for循環

for格式1:

for 變量 in 值1 值2 值3
	do
		程序
	done

這種循環的循環次數和in后的值個數相等。in后面可以放:

1、特殊符號,如$(seq 1 100)代表從1-100這中間的一百個值。

2、多行結果,如cut命令執行的結果

users=$(cut -d ':' -f1 /etc/passwd)
for username in ${users}
	do
		id ${username}
	done

for格式2:

for((初始值;循環控制條件;變量變化))
	do
		程序
	done

例1:批量解壓縮腳本

#!/bin/bash

cd /lamp
ls *.tar.gz > ls.log
for i in $(cat ls.log)
	do
		tar -zxf $i &> /dev/null
	done
rm -rf /lamp/ls.log

將文件中的壓縮包都重定向到日志文件中,然后把日志文件的內容放在in后,逐個執行解壓,最后刪除日志文件。

例2:for版1到100求和

#!/bin/bash
s=0
for((i=1;i<=100;i=i+1))
	do
		s=$(($s+$i))
	done
echo s

例3:批量添加用戶

#!/bin/bash

read -p "input username :" -t 30 name
read -p "input the number of users: " -t 30 num
read -p "input the password of users: " -t 30 pass
if[ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ]
	then
		y=$(echo $num | sed 's/[0-9]//g')
			if[ -z "$y" ]
				then
					for((i=1;i<=$num;i=i+1))
						do
							useradd $name$i &> /dev/null
							echo $pass | passwd --stdin $name&i &> /dev/null
						done
			fi
fi

首先用戶輸入用戶名name和要添加的用戶數量num,還有用戶密碼pass,然后判斷這三個變量是否為空,如果不為空那么就判斷num是否為數字,這里用的方法是把num中的數字全部替換為空,然后再檢查是否為空。最后開始循環,循環次數就是num,添加用戶名時為了保持每個用戶名不同設置名字時要加上循環次數,每個用戶名為$name&i,設置密碼也同理。

while和until循環

while循環,條件為假時退出循環。

while [ 條件判斷式 ] 
	do 
		程序 
	done

until循環和while類似,不同之處在於條件為真時退出循環。

until [ 條件判斷式 ]
	do
		程序
	done

例1:while版1到100求和

#!/bin/bash
#從1加到100
i=1
s=0
while [ $i -le 100 ]
#如果變量i的值小於等於100,則執行循環
do
s=$(( $s+$i ))
i=$(( $i+1 ))
done
echo "The sum is: $s"

腳本的debug

測試腳本是否有語法問題:sh -n 腳本路徑,如果沒有問題則不會顯示任何信息。

列出腳本的執行過程:sh -x 腳本路徑,輸出的結果中加號開頭的行是指令的執行過程,沒有加號的代表打印內容。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM