概述:
本章重點在于講解bash腳本的基礎知識,為今后學習使用bash腳本打下基礎
一、bash基礎特性
程序:指令+數據
指令:由程序文件提供
數據:IO設備、文件、管道、變量
程序:算法+數據結構
變量:變量名+指向的內存空間
變量賦值:name=value
變量類型:存儲格式(變量存儲數據的數據類型)、表示數據范圍、參與的運算
編程語言:
強類型變量:變量類型不可變,是什么類型就是什么類型;例如C語言
弱類型變量:
bash把所有變量統統視作字符型
bash正常情況下不支持浮點型數據,除非借助其他工具
bash中的變量無需事先聲明:相當于把聲明和賦值過程同時實現
聲明:說明數據類型,定義變量名
變量替換(引用):把變量名出現的位置替換為其所指向的內存空間中數據
變量引用:${var_name},$var_name
變量名:變量名只能包含數字、字母和下劃線,而且不能以數字開頭
變量名:見名知義,命名機制遵循某種法則:不能夠使用程序的保留字,例如if,else,then,while等等
bash變量類型:根據作用范圍劃分的
本地變量:作用域范圍僅為當前shell進程
環境變量:作用域為當前shell進程及其子進程
局部變量:作用域僅為某代碼片段(函數上下文)
位置參數變量:向執行腳本的shell進程傳遞的參數
特殊變量:shell內置的有特殊功用的變量;例如$?保存上一個命令執行的狀態結果
0:成功
1-255:失敗
本地變量:只對當前shell進程有效
變量賦值:name=value
name=$user
name=`Command`
name=$(Command)
這里需要注意的是“ 和 $()的意義是不同的。
推薦使用$()
變量引用:${name},$name
""弱引用:變量名會替換為其值
''強引用:變量名不會替換為其值
查看變量:set
撤銷變量:unset name
注意:此處非變量引用,不加$
環境變量:對當前進程及其子進程有效,對父進程無效(除非寫進配置文件,并且重新讀取配置文件)
變量賦值:
(1)export name=value
(2)name=value
export name
(3)declare -x name=value
(4)name=value
declare -x name
變量引用:${name},$name
注意:bash內嵌了許多環境變量(通常為全大寫字符),用于定義bash的工作環境
PATH,HISTFILE,HISTSIZE,HISTFILESIZE,HISTCONTROL,SHELL,HOME,UID,PWD,OLDPWD
查看環境變量:export,declare -x,printenv,env
撤銷環境變量:unset name
只讀變量:不能修改和撤銷
(1)declare -r name
(2)readonly name
只讀變量無法重新賦值,并且不支持撤銷;存活時間為當前shell進程的生命周期,隨shell進程終止而終止
位置變量:見下文第二部分整理
局部變量:對當前shell進程中的某代碼片段有效(通常指函數上下文)
PATH變量定義位置:.bash_profile –> $PATH:$HOME/binPATH=$PATH:$HOME/.local/bin:$HOME/bin –.local/bin centos7普通用戶有的隱藏的目錄,可以放寫隱藏的腳本
寫腳本的時候可以先mkdir /home/bin 在bin目錄下寫腳本,可省去相對路徑。source bash.sh 也可以執行腳本:其執行過程相當于直接在當前shell進程中進行,而不是開一個子進程進行,所有腳本執行完,echo 變量,還可以查看到變量的值。(正常父進程是不能查看子進程的變量的)shadow 默認權限000 但是root用戶屬于超級用戶 可讀可寫,但是如果文件沒有x權限,root也不能執行
算數運算符bash中的算數運算符:+、-、*、/、%、**(平方) 注意:在使用expr的時候“*” 要轉義“\*”實現算數運算: let var=算數表達式 var=$[算數表達式] var=$((算數表達式)) var=$(expr arg1 arg2 arg3) 注意:每個參數之間要用空格隔開
declare -i var =數字
echo ‘算數表達式’| bc
隨機數生成器:echo $[RANDOM%50]:0-49之間的隨機數 echo $[RANDOM%50+1]:1-50之間的隨機數 $RANDOM :1-32767 聚合命令 #!/bin/bash
echo xxx;(echo zzz;exit) ############():代表開個子shell,exit退出子shell非當前shell
echo yyy
退出狀態
0 代表成功, 1-255代表失敗$? 變量保存最近的命令退出狀態
我們也可以指定程序退出的狀態碼,根據狀態碼的數值,來判斷工作狀態,腳本中一旦遇到exit命令,腳本會立即終止,終止,終止退出狀態取決于exit命令后面的數字,如果沒有執行exit,則取腳本最后一條命令的執行狀態結果。
條件測試
測試命令:test [expression]
[ $a = $b ] 判斷 一對[]或兩對[[]] 都可以
[[ $a == $b ]] 兩個等號也可以 [ -f /bin/cat -a -x /bin/cat ] 此時必須使用 一對[] 否則會報錯 數值測試: -gt:大于 -ge:大于等于 -lt:小于 -le:小于等于 -eq:等于 -ne:不等于字符串測試: ==:是否相等 >:大于(比較ascll碼) <:小于 !=:是否不等于 =~:左側字符串是否能夠被右側的PATTERN所匹配,注意: 此表達式一般用于[[ ]]中; -z “string”:判斷字符串是否為空,如果為空則為真 -n “string”:判斷字符串是否為空,如果不為空則為真 注意:用于字符串比較的時候,操作數應該使用引號存在性測試: -a file:文件存在為真,否則為假 -e file:同-a 存在性及類別測試: -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 或者
! EXPRESSION
bash特性之多命令執行:
~]#COMMAND1;COMMAND2;COMMAND3;…
邏輯運算:
運算數:真(true,yes,on,1)
假(false,no,off,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,不同則為1
短路法則:可以提前判斷出結果
~]#COMMAND1 && COMMAND2
COMMAND1為“假”,則COMMAND2不會再執行
否則,COMMAND1為“真”,則COMMAND2必須執行
~]#COMMAND1 || COMMAND2
COMMAND1為“真”,則COMMAND2不會再執行
否則,COMMAND1為“假”,則COMMAND2必須執行
示例:~]#id $username || useradd $username
示例: ~】#id $username ||useradd $username
shell腳本編程:
編程語言的分類:根據運行方式
編譯運行:源代碼–>編譯器(編譯)–>程序文件
解釋運行:源代碼–>運行時啟動解釋器,由解釋器邊解釋邊運行
根據其編程過程中功能的實現是調用庫還是外部的程序文件
shell腳本編程:利用系統上的命令及編程組件進行編程
完整程序:利用庫或編程組件進行編程
編程模型:過程式編程語言,面向對象的編程語言
程序=指令+數據
過程式:以命令為中心來組織代碼,數據是服務于代碼
順序執行
選擇執行
循環執行
代表:C,bash
對象式:以數據為中心來組織代碼,圍繞數據來組織指令
類(class):實例化對象(數據結構),method;
代表:java,C++,Python
shell腳本編程:過程式編程、解釋運行、依賴于外部程序文件運行;
如何寫shell腳本:
常見的解釋器:shellbang
#!/bin/bash
#!/user/bin/python
#!/user/bin/perl
文本編輯器:nano
行編輯器:sed
全屏幕編輯器:nano、vi、vim
shell腳本是什么?
命令的堆積:
但很多命令不具有冪等性,需要用程序邏輯來判斷運行條件是否滿足,,以避免其運行中發生錯誤
運行腳本:
(1)賦予執行權限。并直接運行此程序文件;
chmod +x /PATH/SCRIPT_FILE
/PATH/TO/SCRIPT_FILE
(2)直接運行解釋器,將腳本以命令行參數傳遞給解釋器程序
bash/PATH/TO/SCRIPT_FILE
注意:腳本中的空白行會被解釋器忽略
腳本中,除了shebang,余下所有以#開頭的行,都會被視作注釋行而被忽略;此即為注釋行;
shell腳本的運行是通過運行一個子shell進程實現的
bash的配置文件:
兩類:
profile類:為交互式登錄的shell提供配置
bashrc類:為非交互式登錄的shell進程提供配置
登錄類型:
交互式登錄shell進程:
直接通過某終端輸入賬號和密碼后登陸打開的shell進程
使用su命令:su – USERNAME,或者使用su -l USERNAME執行的登錄切換
非交互式登錄shell進程:
su USERNAME執行的登錄切換
圖像界面下打開的終端
運行腳本(bash子進程)
profile類:
全局:對所有用戶都生效;
/etc/profile
/etc/profile.d/*.sh
用戶個人:僅對當前用戶有效
~/.bash_profile
功用:
1、用于定義環境變量
2、運行命令或腳本
bashrc類:
全局:/etc/bashrc
用戶個人:~/.bashrc
功用:
1、定義本地變量
2、定義命令別名
注意:僅管理員可修改全局配置文件
交互式登錄shell進程:
/etc/profile–>/etc/profile.d/*–>~/.bash_profile–>~/.bashrc–>/etc/bashrc
非交互式登錄shell進程:
~/.bashrc–>/etc/bashrc–>/etc/profile.d/*
命令行中定義的特性,例如變量和別名作用域為當前shell進程的生命周期
配置文件定義的特性,只對隨后新啟動的shell進程有效
讓通過配置文件定義的特性立即生效:
(1)通過命令行重復定義一次
(2)讓shell進程重讀配置文件
~]#source /PAHT/FROM/CONF_FILE
~]#./PATH/FROM/CONF_FILE
問題1:定義對所有用戶都生效的命令別名,例如lftps='lftp 172.16.0.1/pub'?
問題2:讓centos用戶登錄時。提供其已經登錄,并顯示當前系統時間?
bash的特性:hash變量
命令hash:hash命令
變量:
本地變量、環境變量、局部變量、位置參數變量、特殊變量
變量賦值:name=value,export name=value,declare -x name=value
變量引用:$name,${name}
注意:有些時候{}不能省略,例如
myvalue=
撤銷:unset name
bash腳本編程,運行腳本
#!/bin/bash shebang
# 注釋
空白行 忽略不顯示行
bash的配置文件
porfile類:登錄式shell
bashrc類:非登錄式shell
登錄式shell:/etc/profile–>/etc/profile.d/*.sh–>~/.bash_profile–>~/.bashrc–>/etc/bashrc
非登錄式shell:~/.bashrc–>/etc/bashrc–>/etc/profile.d/*.sh
二、總結位置變量:
$1,$2.. ${10},${11}..:對應調用的第1、第2個等參數;用于讓腳本在腳本代碼中通過調用命令行中的傳遞的參數,1和2 等分別代表第一個參數和第二個參數…,shift可以替換參數
特殊變量:$?:判斷執行結果0-255
$0:表示命令本身腳本名稱
$#:傳遞給腳本參數的個數
$*:傳遞給腳本的所有參數(所有參數整體一次性傳遞給腳本)
$@:引用傳遞給腳本的所有參數(每個參數單獨為一個整體一次性傳遞給腳本)
$*與$@的區別:
相同點:都是引用所有參數
不同點:只有在雙引號中體現出來
假設你的腳本運行時你寫了三個參數 分別存儲在$1 $2 $3中
則"$*" 等價于 “$1 $2 $3" —>傳遞了一個參數
而“$@" 等價于 "$1" "$2" "$3" —>傳遞了三個參數
例證:
三、作業:
1、編寫腳本/root/bin/systeminfo.sh,顯示當前主機系統信息,包括主機名,IPv4地址,操作系統版本,內核版本,CPU型號,內存大小,硬盤大小。
解決思路:
分步拆解,將所要的信息用合理的方法先單獨獲取到,再整合到shell script中
主機名:有兩種簡單的獲取方式
hostname #hostname命令(推薦)
echo $HOSTNAME #利用hostname命令所調用的環境變量
uname -n #利用uname命令直接獲?。ɑ旧习ê芏嘞到y信息)
IPv4地址:利用ifconfig命令、擴展正則表達式、head命令獲取
ifconfig |egrep -o "((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])"|head -1
此種方法看上去雖然很亂和繁瑣,但是此公式的實用性很廣,在Centos6與7中,ifconfig中獲取的ip信息格式有些許不同,這就會造成我們從一個版本到另一個版本時,要調整表達式,而用上述表達式則可以盡量避免此種情況
操作系統版本:
cat /etc/redhat-release #適用于6、7版本(推薦適用性廣、直接獲取到我們需要的,沒有其它)
lsb_release #適用于6
cat /etc/issue #適用于6
內核版本:
uname -r
CPU型號:
lscpu |head -n 13|tail -n +13|cut -d: -f2|tr -s " "
內存大?。?/p>
free -h |head -2|tail -1|tr -s " "|cut -d" " -f2
硬盤大?。?/p>
lsblk -d|egrep "^sd.*"|tr -s " "|cut -d" " -f1,4
注意:在不同版本中和不同的語言環境下,命令行不一定通用,例如CPU型號,我的centos7安裝了中文環境,在不調整語言環境和命令行的情況下是與centos6英文版,不通用,所以大家要多多注意
根據上面的信息逐一獲取方法我們可以編寫以下內容作為/root/bin/systeminfo.sh腳本
vim /root/bin/systeminfo.sh
注意:在運行之前需要給腳本添加執行權限哦
chmod +x /root/bin/systeminfo.sh
這樣就可以直接運行腳本文件了
直接運行
絕對路徑:/root/bin/systeminfo.sh
相對路徑:./systeminfo.sh
不賦予執行權限就只能再打開一個bash子進程解析運行此腳本了,但是注意結果能得到,但是在我們以后用配置腳本的話,則不見用用此方法,因為子進程運行的變量是不能影響父進程的
間接運行:
bash /root/bin/systeminfo.sh
以下每題都是默認賦予執行權限我就不說了
2、編寫腳本/root/bin/backup.sh,可實現每日將/etc/目錄備份到/root/etcYYYY-mm-dd中
3、編寫腳本/root/bin/disk.sh,顯示當前硬盤分區中空間利用率最大的值
4、編寫腳本/root/bin/links.sh,顯示正連接本主機的每個遠程主機的IPv4地址和連接數,并按連接數從大到小排序
5、寫一個腳本/root/bin/sumid.sh,計算/etc/passwd文件中的第10個用戶和第20用戶的ID之和
6、寫一個腳本/root/bin/sumspace.sh,傳遞兩個文件路徑作為參數給腳本,計算這兩個文件中所有空白行之和
7、寫一個腳本/root/bin/sumfile.sh,統計/etc, /var, /usr目錄中共有多少個一級子目錄和文件
8、寫一個腳本/root/bin/argsnum.sh,接受一個文件路徑作為參數;如果參數個數小于1,則提示用戶“至少應該給一個參數”,并立即退出;如果參數個數不小于1,則顯示第一個參數所指向的文件中的空白行數
9、寫一個腳本/root/bin/hostping.sh,接受一個主機的IPv4地址做為參數,先判斷是否合格IP,否,提示IP格式不合法并退出,是,測試是否可連通。如果能ping通,則提示用戶“該IP地址可訪問”;如果不可ping通,則提示用戶“該IP地址不可訪問”
10、chmod -rw /tmp/file1,編寫腳本/root/bin/per.sh,判斷當前用戶對/tmp/file1文件是否不可讀且不可寫
11、編寫腳本/root/bin/nologin.sh和login.sh,實現禁止和充許普通用戶登錄系統。
12、計算1+2+3+…+100的值
echo {1..10}|tr " " "+"|bc
echo $((`echo {1..10}|tr " " "+"`))
13、計算從腳本第一參數A開始,到第二個參數B的所有數字的總和,判斷B是否大于A,否提示錯誤并退出,是則計算之
原創文章,作者:NameLess,如若轉載,請注明出處:http://www.www58058.com/36670
總結的很詳細,希望以后的作業能按時完成