腳本書寫規範、shell腳本的執行方式、Shell中的變數說明、變數子串、shell中的數學運算 ...
1.1 前言
1.1.1 為什麼學Shell
Shell腳本語言是實現Linux/UNIX系統管理及自動化運維所必備的重要工具, Linux/UNIX系統的底層及基礎應用軟體的核心大都涉及Shell腳本的內容。每一個合格 的Linux系統管理員或運維工程師,都需要能夠熟練地編寫Shell腳本語言,並能夠閱 讀系統及各類軟體附帶的Shell腳本內容。只有這樣才能提升運維人員的工作效率,適 應曰益複雜的工作環境,減少不必要的重覆工作,從而為個人的職場發展奠定較好的基礎
1.1.2 什麼是shell
Shell是一個命令解釋器,它在操作系統的最外層,負責直接與用戶對話,把用戶的輸入解釋給操作系統,並處理各種各樣的操作系統的輸出結果,輸出屏幕返回給用戶。
這種對話方式可以是:
交互的方式:從鍵盤輸入命令,通過/bin/bash的解析,可以立即得到Shell的回應
[root@clsn ~]# ls anaconda-ks.cfg [root@clsn ~]# echo ls |bash anaconda-ks.cfg
非交互的方式: 腳本
1.1.3 什麼是Shell腳本
命令、變數和流程式控制制語句等有機的結合起來
shell腳本擅長處理純文本類型的數據,而linux中,幾乎所有的配置文件,日誌,都是純文本類型文件
1.1.4 腳本語言的種類
一、編譯型語言
定義:指用專用的編譯器,針對特定的操作平臺(操作系統)將某種高級語言源代碼一次性翻譯成可被硬體平臺直接運行的二進位機器碼(具有操作數,指令、及相應的格式),這個過程叫做編譯(./configure make makeinstall );編譯好的可執行性文件(.exe),可在相對應的平臺上運行(移植性差,但運行效率高)。。
典型的編譯型語言有, C語言、C++等。
另外,Java語言是一門很特殊的語言,Java程式需要進行編譯步驟,但並不會生成特定平臺的二進位機器碼,它編譯後生成的是一種與平臺無關的位元組碼文件(*.class)(移植性好的原因),這種位元組碼自然不能被平臺直接執行,運行時需要由解釋器解釋成相應平臺的二進位機器碼文件;大多數人認為Java是一種編譯型語言,但我們說Java即是編譯型語言,也是解釋型語言也並沒有錯。
二、解釋型語言
定義:指用專門解釋器對源程式逐行解釋成特定平臺的機器碼並立即執行的語言;相當於把編譯型語言的編譯鏈接過程混到一起同時完成的。
解釋型語言執行效率較低,且不能脫離解釋器運行,但它的跨平臺型比較容易,只需提供特定解釋器即可。
常見的解釋型語言有, Python(同時是腳本語言)與Ruby等。
三、腳本語言
定義:為了縮短傳統的編寫-編譯-鏈接-運行(edit-compile-link-run)過程而創建的電腦編程語言。
特點:程式代碼即是最終的執行文件,只是這個過程需要解釋器的參與,所以說腳本語言與解釋型語言有很大的聯繫。腳本語言通常是被解釋執行的,而且程式是文本文件。
典型的腳本語言有,JavaScript,Python,shell等。
其他常用的腳本語句種類
PHP是網頁程式,也是腳本語言。是一款更專註於web頁面開發(前端展示)的腳本語言,例如:Dedecms,discuz。PHP程式也可以處理系統日誌,配置文件等,php也可以調用系統命令。
Perl腳本語言。比shell腳本強大很多,語法靈活、複雜,實現方式很多,不易讀,團隊協作困難,但仍不失為很好的腳本語言,存世大量的程式軟體。MHA高可用Perl寫的
Python,不但可以做腳本程式開發,也可以實現web程式以及軟體的開發。近兩年越來越多的公司都會要求會Python。
Shell腳本與php/perl/python語言的區別和優勢?
shell腳本的優勢在於處理操作系統底層的業務 (linux系統內部的應用都是shell腳本完成)因為有大量的linux系統命令為它做支撐。2000多個命令都是shell腳本編程的有力支撐,特別是grep、awk、sed等。例如:一鍵軟體安裝、優化、監控報警腳本,常規的業務應用,shell開發更簡單快速,符合運維的簡單、易用、高效原則.
PHP、Python優勢在於開發運維工具以及web界面的管理工具,web業務的開發等。處理一鍵軟體安裝、優化,報警腳本。常規業務的應用等php/python也是能夠做到的。但是開發效率和複雜比用shell就差很多了。
系統環境說明
[root@clsn scripts]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) [root@clsn scripts]# uname -r 3.10.0-693.el7.x86_64 [root@clsn scripts]# getenforce Disabled [root@clsn scripts]# systemctl status firewalld.service ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled) Active: inactive (dead) Docs: man:firewalld(1)
1.1.5 系統中的shell
查看系統中的命解釋器
[root@clsn ~]# cat /etc/shells /bin/sh /bin/bash /sbin/nologin /usr/bin/sh /usr/bin/bash /usr/sbin/nologin
常用操作系統的預設shell
1.Linux是Bourne Again shell(bash)
2.Solaris和FreeBSD預設的是Bourne shell(sh)
3.AIX下是Korn Shell(ksh)
4.HP-UX預設的是POSIX shell(sh)
[root@clsn ~]# echo $SHELL /bin/bash
bash版本
[root@clsn scripts]# bash -version GNU bash, 版本 4.2.46(2)-release (x86_64-redhat-linux-gnu) Copyright (C) 2011 Free Software Foundation, Inc. 許可證 GPLv3+: GNU GPL 許可證版本3或者更高 <http://gnu.org/licenses/gpl.html> 這是自由軟體,您可以自由地更改和重新發佈。 在法律允許的範圍內沒有擔保.
bash 破殼漏洞
使用 命令 env x='() { :;}; echo be careful' bash -c "echo this is a test" 如果返回結果為一行,則為正常, [root@clsn ~]# env x='() { :;}; echo be careful' bash -c "echo this is a test" this is a test #解決辦法 升級當前的bash版本 yum install update bash
sh與bash 的關係
[root@clsn ~]# ll /bin/sh lrwxrwxrwx. 1 root root 4 11月 13 11:15 /bin/sh -> bash
/bin與 /user/bin 的關係
[root@clsn ~]# ll /bin -d lrwxrwxrwx. 1 root root 7 11月 13 11:15 /bin -> usr/bin
1.2 腳本書寫規範
1.2.1 腳本統一存放目錄
[root@clsn ~]# mkdir -p /server/scripts/ [root@clsn ~]# cd /server/scripts/
1.2.2 選擇解釋器
註意格式 ↓
其中開頭的"#!"字元又稱為幻數,在執行bash腳本的時候,內核會根據"#!"後的解釋器來確定該用那個程式解釋這個腳本中的內容。
[root@clsn scripts]# head -1 /etc/init.d/* ==> /etc/init.d/functions <== # -*-Shell-script-*- ==> /etc/init.d/netconsole <== #!/bin/bash ==> /etc/init.d/network <== #! /bin/bash
1.2.3 編輯腳本使用vim
使用 .vimrc 文件,能夠快速的生成開頭的註釋信息
[root@clsn scripts]# cat ~/.vimrc autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()" func SetTitle() if expand("%:e") == 'sh' call setline(1,"#!/bin/bash") call setline(2, "##############################################################") call setline(3, "# File Name: ".expand("%")) call setline(4, "# Version: V1.0") call setline(5, "# Author: clsn") call setline(6, "# Organization: http://blog.znix.top") call setline(7, "# Created Time : ".strftime("%F %T")) call setline(8, "# Description:") call setline(9, "##############################################################") call setline(10, "") endif endfunc
使用後的效果
[root@clsn scripts]# cat scripts_test.sh #!/bin/bash ############################################################## # File Name: scripts_test.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-04 11:39:57 # Description: First scripts file ##############################################################
在Shell腳本中,跟在#後面的內容表示註釋。註釋部分不會被執行,僅給人看。註釋可以自成一行,也可以跟在命令後面,與命令同行。要養成寫註釋的習慣,方便自己與他人。
最好不用中文註釋,因為在不同字元集的系統會出現亂碼。(字元集為zh_CN.UTF-8,為中文)。
1.2.4 文件名規範
名字要有意義,並且結尾以 .sh 結束
1.2.5 開發的規範和習慣小結
1) 放在統一的目錄
2) 腳本以.sh為擴展名
3) 開頭指定腳本解釋器。
4) 開頭加版本版權等信息,可配置~/.vimrc文件自動添加。
5) 腳本不要用中文註釋,儘量用英文註釋。
6) 代碼書寫優秀習慣
a、成對的內容一次性寫出來,防止遺漏,如[ ]、' '、" "等
b、[ ]兩端要有空格,先輸入[ ],退格,輸入2個空格,再退格寫。
c、流程式控制制語句一次書寫完,再添加內容。(if 條件 ; then 內容;fi)ddd
d、通過縮進讓代碼易讀。
f、腳本中的引號都是英文狀態下的引號,其他字元也是英文狀態。
1.3 shell腳本的執行
1.3.1 執行腳本的辦法
sh/bash scripts.sh chown +x ./scripts.sh && ./scripts.sh source scripts.sh . (空格) scripts.sh cat oldboyedu.sh |bash # 效率較低
source 與 . (點) 的作用
soucre命令
[root@clsn ~]# help source |head -2 source: source 文件名 [參數] 在當前 shell 中執行一個文件中的命令。
. (點)
[root@clsn scripts]# help . |head -2 .: . 文件名 [參數] 在當前 shell 中執行一個文件中的命令。
1.3.2 sh 於 source的區別
[root@clsn scripts]# sh clsn_test.sh Hello World! [root@clsn scripts]# echo $clsn # sh 新建一個Shell視窗(新建一個進程)執行一個文件中的命令。 [root@clsn scripts]# source clsn_test.sh Hello World! [root@clsn scripts]# echo $clsn Hello World!
面試題:
問sh test.sh後echo $user返回的結果__空_ ?
[root@oldboy scripts]# cat test.sh #!/bin/bash user=`whoami`
1.4 Shell的變數
1.4.1 什麼是變數
變數可以分為兩類:環境變數(全局變數)和普通變數(局部變數)
環境變數也可稱為全局變數,可以在創建他們的Shell及其派生出來的任意子進程shell中使用,環境變數又可分為自定義環境變數和Bash內置的環境變數
普通變數也可稱為局部變數,只能在創建他們的Shell函數或Shell腳本中使用。普通變數一般是由開發者用戶開發腳本程式時創建的。
特殊變數
1.4.2 環境變數
使用 env/declare/set/export -p 命令查看系統中的環境變數,這三個命令的的輸出方式稍有不同。
[root@clsn scripts]# env XDG_SESSION_ID=1 HOSTNAME=clsn TERM=linux SHELL=/bin/bash HISTSIZE=1000 SSH_CLIENT=10.0.0.1 5537 22 SSH_TTY=/dev/pts/0 USER=root ~~~
輸出一個系統中的 環境變數
[root@clsn ~]# echo $LANG zh_CN.UTF-8
1.4.3 普通變數
本地變數在用戶當前的Shell生存期的腳本中使用。例如,本地變數OLDBOY取值為bingbing,這個值在用戶當前Shell生存期中有意義。如果在Shell中啟動另一個進程或退出,本地變數值將無效
定義普通變數實踐
[root@clsn ~]# a=1 [root@clsn ~]# b='2' [root@clsn ~]# c="3" [root@clsn ~]# echo "$a" 1 [root@clsn ~]# echo "$b" 2 [root@clsn ~]# echo "${c}"
提示:$變數名錶示輸出變數,可以用$c和${c}兩種用法
小結:連續普通字元串內容賦值給變數,不管用什麼引號或者不用引號,它的內容是什麼,列印變數就輸出什麼
1.4.4 export命令
[root@clsn ~]# help export export: export [-fn] [名稱[=值] ...] 或 export -p 為 shell 變數設定導出屬性。 標記每個 NAME 名稱為自動導出到後續命令執行的環境。如果提供了 VALUE 則導出前將 VALUE 作為賦值。
export命令的說明
當前shell視窗及子shell視窗生效
在新開的shell視窗不會生效,生效需要寫入配置文件
# 定義變數
[root@clsn scripts]# CSLN=clsn [root@clsn scripts]# export CSLN1=1
# 當前視窗查看
[root@clsn scripts]# echo $CSLN clsn [root@clsn scripts]# echo $CSLN1 1
# 編寫測試腳本
[root@clsn scripts]# vim quanju.sh #!/bin/bash echo $CSLN echo $CSLN1
# 使用sh執行
[root@clsn scripts]# sh quanju.sh 1
# 使用source 執行
[root@clsn scripts]# source quanju.sh clsn 1
1.4.5 環境變數相關配置文件
/etc/proflie
/etc/bashrc
~/.bashrc
~/.bash_profile
/etc/proflie.d/ # 目錄
四文件讀取順序(CentOS6和7都一樣)
① /etc/profile
② ~/.bash_profile
③ ~/.bashrc
④ /etc/bashrc
文件讀取過程示意圖
驗證四文件讀取順序的方法
sed -i '1a echo "$(date +%T-%s) /etc/profile1" >>/tmp/clsn' /etc/profile sed -i '$a echo "$(date +%T-%s) /etc/profile2" >>/tmp/clsn' /etc/profile sed -i '1a echo "$(date +%T-%s) /etc/bashrc1" >>/tmp/clsn' /etc/bashrc sed -i '$a echo "$(date +%T-%s) /etc/bashrc2" >>/tmp/clsn' /etc/bashrc sed -i '1a echo "$(date +%T-%s) ~/.bashrc1" >>/tmp/clsn' ~/.bashrc sed -i '$a echo "$(date +%T-%s) ~/.bashrc2" >>/tmp/clsn' ~/.bashrc sed -i '1a echo "$(date +%T-%s) ~/.bash_profile1" >>/tmp/clsn' ~/.bash_profile sed -i '$a echo "$(date +%T-%s) ~/.bash_profile2" >>/tmp/clsn' ~/.bash_profile
1.4.6 環境變數的知識小結
ü 變數名通常要大寫。
ü 變數可以在自身的Shell及子Shell中使用。
ü 常用export來定義環境變數。
ü 執行env預設可以顯示所有的環境變數名稱及對應的值。
ü 輸出時用“$變數名”,取消時用“unset變數名”。
ü 書寫crond定時任務時要註意,腳本要用到的環境變數最好先在所執行的Shell腳本中重新定義。
ü 如果希望環境變數永久生效,則可以將其放在用戶環境變數文件或全局環境變數文件里。
1.4.7 變數中引號的使用
只有在變數的值中有空格的時候,會使用引號。
單引號與雙引號的區別在於,是否能夠解析特殊符號。
[root@clsn ~]# name=znix [root@clsn ~]# name2='clsn' [root@clsn ~]# name3="http://blog.znix.top" [root@clsn ~]# echo $name znix [root@clsn ~]# echo $name2 clsn [root@clsn ~]# echo $name3 http://blog.znix.top [root@clsn ~]# name4='cl sn' [root@clsn ~]# echo $name4 cl sn [root@clsn ~]# name5="cl sn" [root@clsn ~]# echo $name5 cl sn [root@clsn ~]# name6='cl sn $PWD' [root@clsn ~]# echo $name6 cl sn $PWD [root@clsn ~]# name6="cl sn $PWD" [root@clsn ~]# echo $name6 cl sn /root
1.4.8 普通變數的要求
1) 內容是純數字、簡單的連續字元(內容中不帶任何空格)時,定義時可以不加任何引號,例如:
a.ClsnAge=22
b.NETWORKING=yes
2) 沒有特殊情況時,字元串一律用雙引號定義賦值,特別是多個字元串中間有空格時,例如:
a.NFSD_MODULE="no load"
b.MyName="Oldboy is a handsome boy."
3) 當變數里的內容需要原樣輸出時,要用單引號(M),這樣的需求極少,例如:
a.OLDBOY_NAME='OLDBOY'
變數使用反引號賦值
[root@clsn scripts]# time=`date` [root@clsn scripts]# echo $time 2017年 12月 05日 星期二 09:02:06 CST [root@clsn scripts]# file=`ls` [root@clsn scripts]# echo $file clsn_test.sh panduan.sh quanju.sh yhk.sh
使用${}
列印變數的時候防止出現“金庸新著”的問題
[root@clsn scripts]# time=`date` [root@clsn scripts]# echo $time_day [root@clsn scripts]# echo ${time}_day 2017年 12月 05日 星期二 09:02:06 CST_day [root@clsn scripts]# echo $time-day 2017年 12月 05日 星期二 09:02:06 CST-day
編寫腳本測試${}
# 使用腳本測試 [root@clsn scripts]# vim bianliang.sh #!/bin/bash ############################################################# # File Name: bianliang.sh # Version: V1.0 # Author: clsn # Organization: http://blog.znix.top # Created Time : 2017-12-05 09:10:29 # Description: ############################################################# time=`date` echo $timeday echo ${time}day [root@clsn scripts]# sh bianliang.sh 2017年 12月 05日 星期二 09:11:19 CSTday
1.4.9 定義變數名技巧
1. 變數名只能為字母、數字或下劃線,只能以字母或下劃線開頭。
2. 變數名的定義要有一定的規範,並且要見名知意。
示例:
ClsnAge=22 #<==每個單詞的首字母大寫的寫法
clsn_age=22 #<==單詞之間用"_"的寫法
clsnAgeSex=man #<==駝峰語法:首個單詞的首字母小寫,其餘單詞首字母大寫
CLSNAGE=22 #<==單詞全大寫的寫法
3. 一般的變數定義、賦值常用雙引號;簡單連續的字元串可以不加引號;希望原樣輸出時使用單引號。
4. 希望變數的內容是命令的解析結果時,要用反引號'',或者用$()把命令括起來再賦值。
1.5 特殊變數
1.5.1 位置變數
常用的特殊位置參數說明