shell腳本是Linux運維工程師必須掌握的技能之一,shell腳本的使用讓我們更好的操作Linux系統,方便了我們的執行。
一,編程基礎
編程基本概念
編程邏輯處理方式:順序執行,循環執行,選擇執行
程序:指令+ 數據
shell 編程:過程式、解釋執行
shell程序:提供了編程能力,解釋執行
程序編程風格:
過程式:以指令為中心,數據服務于指令
對象式:以數據為中心,指令服務于數據
程序的執行方式
計算機:運行二進制指令;
編程語言的基本結構:
數據存儲:變量、數組
表達式: a + b
語句:if
編程語言:
低級:匯編
高級:
編譯:高級語言–> 編譯器–> 目標代碼 : java,C#
解釋:高級語言–> 解釋器–> 機器代碼 : shell, perl, python
編程程序語言分類
強類型:定義變量時必須指定類型、參與運算必須符合類型要求;調用未聲明變量會產生錯誤
如 java,python
弱類型:無須指定類型,默認均為字符型;參與運算會自動進行隱式類型轉換;變量無須事先定義可直接調用
如:bash 不支持浮點數
二,shell 腳本基礎
shell腳本規范和用途:
shell 腳本是包含一些命令或聲明,并符合一定格式的文本文件
格式要求:首行shebang 機制
shell腳本:#!/bin/bash; 文件名以 .sh 結尾
Python: #!/usr/bin/python; 文件名以 .py 結尾
Perl :#!/usr/bin/perl ; 文件名以 .pl 結尾
shell 腳本的用途有:
自動化常用命令
執行系統管理和故障排除
創建簡單的應用程序
處理文本或文件
創建shell 腳本
第一步:使用文本編輯器來創建文本文件
第一行必須包括shell 聲明序列:#!: #!/bin/bash
添加注釋:注釋以# 開頭
第二步:運行腳本
給予執行權限,在命令行上指定腳本的絕對或相對路徑
直接運行解釋器,將腳本作為解釋器程序的參數運行
腳本調試
bash -n /path/to/some_script
檢測腳本中的語法錯誤
bash -x /path/to/some_script
調試執行
三,腳本變量的基礎
變量(變量的內容是可以更改的,它可以存儲很多類型的數據)
變量:命名的內存空間
數據存儲方式:
字符:
數值:整型,浮點型
變量:變量類型
作用:1 、數據存儲格式;2 、參與的運算;3 、表示的數據范圍
類型:
字符
數值:整型、浮點型
變量命名法則:
1 、不能使程序中的保留字:例如if, for;
2 、只能使用數字、字母及下劃線,且不能以數字開頭
3 、見名知 義
4 、統一命名規則:駝峰命名法(多個單詞命名,分為大,小駝峰,大駝峰是每個單詞的第一個字母大寫,小駝峰是除了第一個單詞小寫其他單詞的第一個字母大寫)
{
sleep 休眠:在腳本中執行 sleep + 時間 可以有時間查看父子進程,sleep默認時間為秒。
定義變量時不能帶空格,必須用雙引號擴起來才可以。
echo默認是一行,加雙引號就可以原原本本顯示出來。
}
四,變量的范圍簡介
根據變量的生效范圍等標準:
本地變量:生效范圍為當前shell 進程;對當前shell 之外的其它shell 進程,包括當前shell 的子shell 進程均無效
變量賦值:name=‘value’
可以使用引用value:
(1) 可以是直接字串; name=“root"
(2) 變量引用:name="$USER"
(3) 命令引用:name=` COMMAND `, name =$(COMMAND)
變量引用:${name}, $name
"" :弱引用,其中的變量引用會被替換為變量值
'' :強引用,其中的變量引用不會被替換為變量值,而保持原字符串
顯示已定義的所有變量:set
刪除變量:unset name
環境變量:生效范圍為當前shell 進程及其子進程局部變量:生效范圍為當前shell 進程中某代碼片斷( 通常指函數)
變量聲明、賦值:
export name=VALUE
declare -x name=VALUE
變量引用:$name, ${name}
顯示所有環境變量:
export
env
printenv
刪除:unset name
bash 有許多內建的環境變量:PATH, SHELL, USRE,UID,HISTSIZE, HOME, PWD, OLDPWD, HISTFILE, PS1
只讀變量:只能聲時,但不能修改和刪除(一般使用在常量身上)
readonly name
declare -r name
(declare -rx name 定義一個即使常量,也是環境變量)
位置變量:$1, $2, … 來表示,用于讓腳本在腳本代碼中調用通過命令行傳遞給它的參數
在腳本代碼中調用通過命令行傳遞給腳本的參數
$1, $2, … :對應第1 、第2 等參數,shift [n] 換位置
$0: 命令本身
$*: 傳遞給腳本的所有參數,全部參數合為一個字符串
$@: 傳遞給腳本的所有參數,每個參數為獨立字符串
$#: 傳遞給腳本的參數的個數
$@ $* 只在被雙引號包起來的時候才會有差異
示例:判斷給出的文件的行數
linecount="$(wc -l $1| cut -d' ' -f1)"
echo "$1 has $linecount lines."
特殊變量:$?, $0, $*, $@, $#
basename + 文件名
basename的語法是:basename[選項][參數]
選項:為有路徑信息的文件名,如/home/test/test.txt
參數:指文件擴展名
五,bash運算
算術運算:help let(bash雖然不支持浮點,但是還是支持加減乘除的)
+, -, *, /, % 取模(取余), ** (乘方)
實現算術運算:
(1) let var= 算術表達式
(2) var=$[ 算術表達式]
(3) var=$(( 算術表達式))
(4) var=$(expr arg1 arg2 arg3 …)
(5) declare –i var = 數值 (需要先申明數值,在進行計算)
(6) echo ‘ 算術表達式’ | bc
乘法符號有些場景中需要轉義 ,如 如*
bash 有內建的隨機數生成器:$RANDOM (1-32767)
echo $[$RANDOM%50] :0-49
(echo $[RANDOM%50+1] :1-50 %50+1 :是0-49整體性的+1,不是單個的49+1)
$?是查看上一個命令的狀態,
expr使用乘號需要把乘號轉義和加空格 如:expr 2 \* 3
賦值
增強型賦值:+=, -=, *=, /=, %=
{
% : 在算術運算中,這個是求模操作符,即兩個數進行除法運算后的余數;
}
let varOPERvalue
例如:let count+=3(自己先加3 后再給自己賦值)
自增,自減:
let var+=1
let var++
let var-=1
let var–
邏輯運算
true 1, false 0,
與:
1 與 1 = 1
1 與 0 = 0
0 與 1 = 0
0 與 0 = 0
或:
1 或 1 = 1
1 或 0 = 1
0 或 1 = 1
0 或 0 = 0
非:!
! 1 = 0
! 0 = 1
短路運算:
短路與:(&&)
第一個為0 ,結果必定為0;
第一個為1 ,第二個必須要參與運算;
cmd1 && cmd2
cmd1 成功,將執行cmd2
cmd1 失敗,將不執行cmd2
短路或 :(||)
第一個為1 ,結果必定為1;
第一個為0 ,第二個必須要參與運算;
cmd1 成功,將不執行cmd2
cmd1 失敗,將執行cmd2
異或:^
異或的兩個值, 相同為假,不同為真
{
短路與 和 普通與 的區別
cmd1 && cmd2
短路與: cmd1 為真時 ,執行 cmd2 ; cmd1為假時 ,不執行 cmd2 直接退出。
普通與: cmd1 不管是真是假,cmd2 都要執行 。
短路或 和 普通或 的區別
cmd1 || cmd2
短路與 : cmd1 為真時,可以不用執行 cmd2 直接退出; cmd1 為假時,執行 cmd2 。
普通與 : cmd1 不管是真是假,cmd2 都要執行。
}
六,bash的退出狀態
進程使用退出狀態來報告成功或失敗
0 代表成功,1 -255 代表失敗
$? 變量保存最近的命令退出狀態(最后一條的命令的狀態)
例如:
$ ping -c1 -W1 hostdown &> /dev/null
$ echo $?
(ping -c1 代表拼一個)(ping -W1 一秒,默認為是五秒,在局域網一般最多需要一秒連接的顯示信息就能返回,在互聯網時間稍長一點)
退出狀態碼
bash 自定義退出狀態碼
exit [n] :自定義退出狀態碼;(在腳本中(exit)執行的是子shell )
注意:腳本中一旦遇到exit 命令,腳本會立即終止;終止退出狀態取決于exit 命令后面的數字
注意:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決于腳本中執行的最后一條命令的狀態碼
七,bash 的測試類型
條件測試
判斷某需求是否滿足,需要由測試機制來實現;
專用的測試表達式需要由測試命令輔助完成測試過程;
評估布爾聲明,以便用在條件性執行中
若真,則返回0
若假,則返回1
測試命令:
test EXPRESSION (test $a = $b 測試$a 和$b 是否相同時 $a 和$b的前后必須要有空格,要是沒有就成了賦值了)
[ EXPRESSION ]
[[ EXPRESSION ]] ([[ $a ]] 測試$a 是否定義過值)
注意:EXPRESSION 前后必須有空白字符
test 命令
長格式的例子:
$ test "$A" == "$B" && echo "Strings are equal"
$ test “$A” -eq “$B” \
&& echo "Integers are equal"
簡寫格式的例子:
$ [ "$A" == "$B" ] && echo "Strings are equal"
$ [ "$A" -eq "$B" ] && echo "Integers are equal"
條件性的執行操作符
根據退出狀態而定,命令可以有條件地運行
&& 代表條件性的AND THEN
|| 代表條件性的OR ELSE
例如:
$ grep -q no_such_user /etc/passwd \|| echo 'No such user'
No such user
$ ping -c1 -W2 station1 &> /dev/null \> && echo
"station1 is up" \> || (echo 'station1 is unreachable'; exit 1)
station1 is up
數值測試:
-gt: 是否大于;
-ge: 是否大于等于;
-eq: 是否等于;
-ne: 是否不等于;
-lt: 是否小于;
-le: 是否小于等于;
字符串測試:
== :是否等于;
>: ascii 碼是否大于ascii碼
<: 是否小于
!=: 是否不等于
=~: 左側字符串是否能夠被右側的PATTERN所匹配(右側是要使用擴展正則表達式)
注意:用于字符串比較時的用到的操作數都應該使用引號
{
-z "STRING" :字符串是否為空,空為真,不空為假
-n "STRING" :字符串是否不空,不空為真,空為假
注意: 此表達式一般用于[[ ]] 中;
}
文件測試
存在性測試
-a FILE :同-e
-e FILE: 文件存在性測試,存在為真,否則為假;
存在性及類別測試
-b FILE :是否存在且為塊設備文件;
-c FILE :是否存在且為字符設備文件;
-d FILE :是否存在且為目錄文件;
-f FILE :是否存在且為普通文件;
-h FILE 或 或 -L FILE :存在且為符號鏈接文件;
-p FILE :是否存在且為命名管道文件;
-S FILE :是否存在且為套接字文件;
文件權限測試:(是以實際的權限為標準,不是看設的權限的。)
-r FILE :是否存在且可讀
-w FILE: 是否存在且可寫
-x FILE: 是否存在且可執行
文件特殊權限測試:
-g FILE :是否存在且擁有sgid 權限;
-u FILE :是否存在且擁有suid 權限;
-k FILE :是否存在且擁有sticky 權限;
文件大小測試:
-s FILE: 是否存 在 且非空;
文件是否打開:
-t fd: fd 表示文件描述符是否已經打開且與某終端相關
-N FILE :文件自上一次被讀取之后是否被修改過
-O FILE :當前有效用戶是否為文件屬主
-G FILE:當前有效用戶是否為文件屬組
雙目測試:
FILE1 -ef FILE2: FILE1 與FILE2 是否指向同一個設備上的相同inode
{
FILE1 -nt FILE2: FILE1 是否新于FILE2;
FILE1 -ot FILE2: FILE1 是否舊于FILE2;
}(比的是文件的修改時間)
組合測試條件
第一種方式:
COMMAND1 && COMMAND2 并且
COMMAND1 || COMMAND2 或者
! COMMAND 非
如:[ -e FILE ] && [ -r FILE ]
第二種方式:
EXPRESSION1 -a EXPRESSION2 并且
EXPRESSION1 -o EXPRESSION2 或者(or)
! EXPRESSION
必須使用測試命令進行;
# [ -z “$HOSTNAME” -o $HOSTNAME "==\"localhost.localdomain" ] && hostname www.magedu.com
# [ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
八,聚集命令
有兩種聚集命令的方法:
復合式:date; who | wc -l (命令會一個接一個地運行)
子shell :(date; who | wc -l ) >>/tmp/trace (所有的輸出都被發送給單個STDOUT 和STDERR)
原創文章,作者:AN0519,如若轉載,請注明出處:http://www.www58058.com/38660