SHELL腳本編程基礎
一、編程基礎
1. 編程基礎
1 Linus:Talk is cheap, show me the code
2 程序
程序:算法+ 數據結構
數據:是程序的核心
數據結構:數據在計算機中的類型和組織方式
算法:處理數據的方式
3. 程序編程風格:
過程式:以指令爲中心,數據服務於指令
對象式:以數據爲中心,指令服務於數據
4. shell程序:提供了編程能力,解釋執行
2. 程序的執行方式
1. 計算機:運行二進制指令
2. 編程語言:人與計算機之間交互的語言
3. 低級編程語言:
機器:二進制的0 和1 的序列,稱爲機器指令。與自然語言差異太大,難懂、難寫
彙編:用一些助記符號替代機器指令,稱爲彙編語言
如:ADD A , B 將寄存器A 的數與寄存器B 的數相加得到的數放到寄存器A 中
彙編語言寫好的程序需要彙編程序轉換成機器指令
彙編語言稍微好理解,即機器指令對應的助記符,助記符更接近自然語言
4. 高級編程語言:
編譯:高級語言-- > 編譯器-- > 機器代碼-- > 執行
C ,C ++
解釋:高級語言-- > 執行-- > 解釋器-- > 機器代碼
shell,python,php,JavaScript,perl
3. 編譯和解釋型語言
4. 編程基本概念
1. 編程邏輯處理方式:
順序執行
循環執行
選擇執行
2. shell編程:過程式、解釋執行
編程語言的基本結構:
各種系統命令的組合
數據存儲:變量、數組
表達式:a + b
語句:if
二、腳本基本格式
1. shell腳本基礎
1. shell腳本:
包含一些命令或聲明,並符合一定格式的文本文件
2. 格式要求:首行shebang機制
#! / bin/ bash
#! / usr/ bin/ python
#! / usr/ bin/ perl
3. shell腳本的用途有:
自動化常用命令
執行系統管理和故障排除
創建簡單的應用程序
處理文本或文件
2. 創建shell腳本
1. 第一步:使用文本編輯器來創建文本文件
第一行必須包括shell聲明序列:#!
示例:#! / bin/ bash
添加註釋
註釋以#開頭
2. 第二步:運行腳本
給予執行權限,在命令行上指定腳本的絕對或相對路徑
直接運行解釋器,將腳本作爲解釋器程序的參數運行
3. 腳本規範
腳本代碼開頭約定
1 、第一行一般爲調用使用的語言
2 、程序名,避免更改文件名爲無法找到正確的文件
3 、版本號
4 、更改後的時間
5 、作者相關信息
6 、該程序的作用,及注意事項
7 、最後是各版本的更新簡要說明
4. 編程基本概念
腳本的基本結構
#! SHEBANG
CONFIGURATION_VARIABLES
FUNCTION_DEFINITIONS
MAIN_CODE
5. shell腳本示例
#! / bin/ bash
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
# Filename: hello. sh
# Revision: 1.1
# Date: 2017 / 06 / 01
# Author: wang
# Email: wang@gmail. com
# Website: www. magedu. com
# Description: This is the first script
# Copyright: 2017 wang
# License: GPL
# -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
echo “hello world”
[ root@centos7 ~]
set ignorecase
set cursorline
set autoindent
autocmd BufNewFile *.sh exec ":call SetTitle()"
func SetTitle( )
if expand( "%:e" ) == 'sh'
call setline( 1,"#!/bin/bash" )
call setline( 2,"#****************
****************************************************" )
call setline( 3,"#Filename: " .expand(( "%" )) )
call setline( 4,"#Revision: 1.0" )
call setline( 5,"#Date: " .strftime( "%Y-%m-%d" ))
call setline( 6,"#Author:zjl " )
call setline( 7,"#Email:[email protected] " )
call setline( 8,"#Website:https://zjl.com" )
call setline( 9,"#Description: Annotated script" )
call setline( 10,"#********************************************************************" )
call setline( 11,"" )
endif
endfunc
autocmd BufNewFile * normal G
6. 腳本調試
1. 檢測腳本中的語法錯誤
bash - n / path/ to/ some_script
2. 調試執行
bash - x / path/ to/ some_script
三、變量
1. 變量
1. 變量:命名的內存空間
2. 變量:變量類型
作用:
1 、數據存儲方式
2 、參與的運算
3 、表示的數據範圍
類型:
字符
數值:整型、浮點型
3. Shell中變量命名法則:
1 、不能使程序中的保留字:例如if , for
2 、只能使用數字、字母及下劃線,且不能以數字開頭
3 、見名知義
4 、統一命名規則:駝峯命名法
4. Shell中命名建議規則:
1 、變量名大寫
2 、局部變量小寫
3 、函數名小寫
4 、用英文名字,並體現出實際作用
5. 靜態編譯語言:使用變量前,先聲明變量類型,之後類型不能改變,在編譯時
檢查,如:java,c
6. 動態編譯語言:不用事先聲明,可隨時改變類型,如bash,Python
7. 強類型語言:不同類型數據操作,必須經過強制轉換才同一類型才能運算,如
java , c# ,python
如:以下python代碼
print ( ‘magedu’+ 10 ) 提示出錯,不會自動轉換類型
print ( ‘magedu’+ str ( 10 ) ) 結果爲magedu10,需要顯示轉換類型
8. 弱類型語言:語言的運行時會隱式做數據類型轉換。無須指定類型,默認均爲
字符型;參與運算會自動進行隱式類型轉換;變量無須事先定義可直接調用
如:bash 不支持浮點數,php,javascript
2. bash中變量的種類
根據變量的生效範圍等標準劃分下面變量類型
局部變量:生效範圍爲當前shell進程;對當前shell之外的其它shell進程,包括當前shell的子shell進程均無效
環境變量:生效範圍爲當前shell進程及其子進程
本地變量:生效範圍爲當前shell進程中某代碼片斷,通常指函數
位置變量:$1 , $2 , ... 來表示,用於讓腳本在腳本代碼中調用通過命令行傳遞給它的參數
特殊變量:$? , $0 , $* , $@, $#, $$
a. 局部變量
1. 變量賦值:name= ‘value’
2. 可以使用引用value
( 1 ) 可以是直接字串:name= “root"
( 2 ) 變量引用:name= "$USER"
( 3 ) 命令引用:name= `COMMAND`
name= $ ( COMMAND )
3. 變量引用:${ name} 或者 $name
" " 弱引用,其中的變量引用會被替換爲變量值
' ' 強引用,其中的變量引用不會被替換爲變量值,而保持原字符串
4. 顯示已定義的所有變量:set
5. 刪除變量:unset name
b. 環境變量
1. 變量聲明、賦值:
export name= VALUE
declare - x name= VALUE
2. 變量引用:
$name, ${ name}
3. 顯示所有環境變量:
env
printenv
export
declare - x
4. 刪除變量:
unset name
5. bash內建的環境變量
PATH
SHELL
USER
UID
HOME
PWD
SHLVL
LANG
MAIL
HOSTNAME
HISTSIZE
_ 下劃線
c. 只讀和位置變量
1. 只讀變量:只能聲明,但不能修改和刪除
聲明只讀變量:
readonly name
declare - r name
查看只讀變量:
readonly - p
2. 位置變量:在腳本代碼中調用通過命令行傳遞給腳本的參數
$1 , $2 , ... 對應第1 、第2 等參數,shift [ n] 換位置
$0 命令本身
$* 傳遞給腳本的所有參數,全部參數合爲一個字符串
$@ 傳遞給腳本的所有參數,每個參數爲獨立字符串
$# 傳遞給腳本的參數的個數
注意:$@ $* 只在被雙引號包起來的時候纔會有差異
set -- 清空所有位置變量
3. 退出狀態
1. 進程使用退出狀態來報告成功或失敗
0 代表成功,1 -255 代表失敗
$? 變量保存最近的命令退出狀態
2. 例如:
ping - c1 - W1 hostdown & > / dev/ null
echo $?
4. 退出狀態碼
bash自定義退出狀態碼
exit [ n] :自定義退出狀態碼
注意:腳本中一旦遇到exit命令,腳本會立即終止;終止退出狀態取決於exit命
令後面的數字
注意:如果未給腳本指定退出狀態碼,整個腳本的退出狀態碼取決於腳本中執
行的最後一條命令的狀態碼
四、運算
1. 算術運算
1. bash中的算術運算: help let
+ , - , * , / , % 取模(取餘), ** (乘方),乘法符號有些場景中需要轉義
實現算術運算:
( 1 ) let var = 算術表達式
( 2 ) var = $[ 算術表達式]
( 3 ) var = $ ( ( 算術表達式) )
( 4 ) var = $ ( expr arg1 arg2 arg3 ... )
( 5 ) declare –i var = 數值
( 6 ) echo ‘算術表達式’ | bc
2. bash有內建的隨機數生成器變量:$RANDOM (0 - 32767 )
示例:生成 0 - 49 之間隨機數
echo $[ $RANDOM % 50 ]
2. 賦值
1. 增強型賦值:
+= , -= , *= , /= , %=
2. let varOPERvalue
例如: let count+= 3
自加3 後自賦值
3. 自增,自減:
let var += 1
let var ++
let var -= 1
let var
3. 邏輯運算
1. true , false
1 , 0
2. 與
1 與 1 = 1
1 與 0 = 0
0 與 1 = 0
0 與 0 = 0
3. 或
1 或 1 = 1
1 或 0 = 1
0 或 1 = 1
0 或 0 = 0
4. 非:!
! 1 = 0 ! true
! 0 = 1 ! false
5. 短路運算
短路與
第一個爲0 ,結果必定爲0
第一個爲1 ,第二個必須要參與運算
短路或
第一個爲1 ,結果必定爲1
第一個爲0 ,第二個必須要參與運算
6. 異或:^
異或的兩個值,相同爲假,不同爲真
五、條件測試
1. 條件測試
1. 判斷某需求是否滿足,需要由測試機制來實現
專用的測試表達式需要由測試命令輔助完成測試過程
2. 評估布爾聲明,以便用在條件性執行中
• 若真,則返回0
• 若假,則返回1
3. 測試命令:
• test EXPRESSION
• [ EXPRESSION ]
• [ [ EXPRESSION ] ]
注意:EXPRESSION 前後必須有空白字符
2. bash的數值測試
- v VAR
變量VAR 是否設置
數值測試:
- gt 是否大於
- ge 是否大於等於
- eq 是否等於
- ne 是否不等於
- lt 是否小於
- le 是否小於等於
3. bash的字符串測試
1. 字符串測試:
= 是否等於
> ascii碼是否大於ascii碼
< 是否小於
!= 是否不等於
= ~ 左側字符串是否能夠被右側的PATTERN 所匹配
注意: 此表達式一般用於[ [ ] ] 中;擴展的正則表達式
- z "STRING “ 字符串是否爲空,空爲真,不空爲假
- n "STRING “ 字符串是否不空,不空爲真,空爲假
2. 注意:用於字符串比較時的用到的操作數都應該使用引號
4. bash的文件測試
1. 存在性測試
- a FILE :同 - e
- e FILE : 文件存在性測試,存在爲真,否則爲假
2. 存在性及類別測試
- b FILE :是否存在且爲塊設備文件
- c FILE :是否存在且爲字符設備文件
- d FILE :是否存在且爲目錄文件
- f FILE :是否存在且爲普通文件
- h FILE 或 - L FILE :存在且爲符號鏈接文件
- p FILE :是否存在且爲命名管道文件
- S FILE :是否存在且爲套接字文件
5. bash的文件權限測試
1. 文件權限測試:
- r FILE :是否存在且可讀
- w FILE : 是否存在且可寫
- x FILE : 是否存在且可執行
2. 文件特殊權限測試:
- u FILE :是否存在且擁有suid權限
- g FILE :是否存在且擁有sgid權限
- k FILE :是否存在且擁有sticky權限
6. bash的文件屬性測試
1. 文件大小測試:
- s FILE : 是否存在且非空
2. 文件是否打開:
- t fd: fd 文件描述符是否在某終端已經打開
- N FILE :文件自從上一次被讀取之後是否被修改過
- O FILE :當前有效用戶是否爲文件屬主
- G FILE :當前有效用戶是否爲文件屬組
3. 雙目測試:
FILE1 - ef FILE2 : FILE1 是否是FILE2 的硬鏈接
FILE1 - nt FILE2 : FILE1 是否新於FILE2 (mtime)
FILE1 - ot FILE2 : FILE1 是否舊於FILE2
7. bash的組合測試條件
1. 第一種方式:
EXPRESSION1 - a EXPRESSION2 並且
EXPRESSION1 - o EXPRESSION2 或者
! EXPRESSION
必須使用測試命令進行,[ [ ] ] 不支持
2. 第二種方式:
COMMAND1 && COMMAND2 並且,短路與,代表條件性的AND THEN
COMMAND1 || COMMAND2 或者,短路或,代表條件性的OR ELSE
! COMMAND 非
如:[ - f “$FILE ” ] && [ [ “$FILE ”= ~ . * \. sh$ ] ]
3. 示例:
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
4. 示例:
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“
[ - f / bin/ cat - a - x / bin/ cat ] && cat / etc/ fstab
[ - z “$HOSTNAME ” - o $HOSTNAME "==" localhost. localdomain" ] \
&& hostname www. magedu. com
## [ $RANDOM % 6 –eq 0 ] && rm –rf
8. 使用read命令來接受輸入
1. 使用read來把輸入值分配給一個或多個shell變量
- p 指定要顯示的提示
- s 靜默輸入,一般用於密碼
- n N 指定輸入的字符長度N
- d ‘字符’ 輸入結束符
- t N TIMEOUT 爲N 秒
read 從標準輸入中讀取值,給每個單詞分配一個變量
所有剩餘單詞都被分配給最後一個變量
read - p “Enter a filename: “ FILE
六、條件判斷if
1. 條件判斷if
1. 選擇執行:
2. 注意:if 語句可嵌套
3. 單分支
if 判斷條件; then
條件爲真的分支代碼
fi
2. 雙分支
if 判斷條件; then
條件爲真的分支代碼
else
條件爲假的分支代碼
fi
3. 多分支
if 判斷條件1 ; then
條件1 爲真的分支代碼
elif 判斷條件2 ; then
條件2 爲真的分支代碼
elif 判斷條件3 ; then
條件3 爲真的分支代碼
else
以上條件都爲假的分支代碼
fi
4. 逐條件進行判斷,第一次遇爲“真”條件時,執行其分支,而後結束整個if 語句
5. 根據命令的退出狀態來執行命令
if ping - c1 - W2 station1 & > / dev/ null ; then
echo 'Station1 is UP'
elif grep "station1" ~ / maintenance. txt & > / dev/ null ; then
echo 'Station1 is undergoing maintenance'
else
echo 'Station1 is unexpectedly DOWN!'
exit 1
fi
七、條件判斷case
1. 條件判斷:case語句
case 變量引用 in
PAT1 )
分支1
; ;
PAT2 )
分支2
; ;
...
* )
默認分支
; ;
esac
case 支持glob風格的通配符:
* : 任意長度任意字符
? : 任意單個字符
[ ] :指定範圍內的任意單個字符
a| b: a或b
八、配置用戶環境
1. bash如何展開命令行
1. 把命令行分成單個命令詞
2. 展開別名
3. 展開大括號的聲明({ } )
4. 展開波浪符聲明(~ )
5. 命令替換$ ( ) 和 `` )
6. 再次把命令行分成命令詞
7. 展開文件通配(* 、? 、[ abc] 等等)
8. 準備I / 0 重導向(< 、> )
9. 運行命令
2. 防止擴展
1. 反斜線(\)會使隨後的字符按原意解釋
echo Your cost: \$5.00
Your cost: $5.00
2. 加引號來防止擴展
• 單引號(’’)防止所有擴展
• 雙引號(”“)也可防止擴展,但是以下情況例外:
$(美元符號) 變量擴展
` ` ( 反引號) 命令替換
\(反斜線) 禁止單個字符擴展
! (歎號) 歷史命令替換
3. bash的配置文件
1. 按生效範圍劃分,存在兩類:
2. 全局配置:
/ etc/ profile
/ etc/ profile. d
4. shell登錄兩種方式
1. 交互式登錄:
( 1 ) 直接通過終端輸入賬號密碼登錄
( 2 ) 使用“su - UserName” 切換的用戶
執行順序:/ etc/ profile -- > / etc/ profile. d
2. 非交互式登錄:
( 1 ) su UserName
( 2 ) 圖形界面下打開的終端
( 3 ) 執行腳本
( 4 ) 任何其它的bash實例
執行順序: / etc/ profile. d
5. Profile類
1. 按功能劃分,存在兩類:
profile類和bashrc類
2. profile類:爲交互式登錄的shell提供配置
全局:/ etc/ profile, / etc/ profile. d
個人:~ / . bash_profile
功用:
( 1 ) 用於定義環境變量
( 2 ) 運行命令或腳本
6. Bashrc類
bashrc類:爲非交互式和交互式登錄的shell提供配置
全局:/ etc/ bashrc
個人:~ / . bashrc
功用:
( 1 ) 定義命令別名和函數
( 2 ) 定義本地變量
7. 編輯配置文件生效
修改profile和bashrc文件後需生效
兩種方法:
1 重新啓動shell進程
2 . 或source
例:
. ~ / . bashrc
8. Bash 退出任務
1. 保存在~ / . bash_logout文件中(用戶)
2. 在退出登錄shell時運行
3. 用於
• 創建自動備份
• 清除臨時文件
9. set 命令
$- 變量
h:hashall,打開這個選項後,Shell 會將命令所在的路徑hash下來,避免每次
都要查詢。通過set + h將h選項關閉
i:interactive- comments,包含這個選項說明當前的 shell 是一個交互式的
shell。所謂的交互式shell, 在腳本中,i選項是關閉的。
m:monitor,打開監控模式,就可以通過Job control來控制進程的停止、繼
續,後臺或者前臺執行等。
B :braceexpand,大括號擴展
H :history,H 選項打開,可以展開歷史列表中的命令,可以通過! 感嘆號來完
成,例如“! ! ”返回上最近的一個歷史命令,“! n”返回第 n 個歷史命令
10. 腳本安全
set 命令
- u 在擴展一個沒有設置的變量時,顯示錯誤信息
等同set –o nounset
- e 如果一個命令返回一個非0退出狀態值 ( 失敗) 就退出
等同set –o errexit