簡單來講Shell其實就是一個命令解釋器,而它的做用就是解釋並執行用戶輸入的命令及程序。用戶每輸入一條命令,Shell就解釋執行一次。這種方式很容易讓你們想起在Windows環境中使用的command命令,咱們在cmd窗口輸入一條命令,按下Enter鍵,則執行相應的命令和結果。
Shell位於操做系統的最外層,對外提供與用戶交互式的對話並返回相應的執行結果,對內則是將用戶輸入的命令解釋給操做系統。Shell在操做系統中所處的位置以下圖所示:
linux
Shell在英文中的意思就是外殼、貝殼等,從圖中也能夠看出,Shell就像殼同樣包住了系統的核心(Kernel)shell
Shell命令與Command命令對比
編程
在理解了Shell以後,咱們再來看看Shell腳本。當命令或程序語句不是在命令行中執行時,而是經過程序文件來執行時,該程序就稱之爲Shell腳本,我依然拿Windows來作比例。當咱們須要執行比較少的命令時,咱們能夠一個一個命令的進行手動輸入,若是須要執行成百上千的命令時,你會怎麼辦?聰明的你確定會脫口而出,用批處理(擴展名通常爲bat或cmd)。其實Shell腳本就相似於批處理,經過在腳本中定義變量、執行命令、調用函數和邏輯判斷、循環等造成一個有機的總體,便造成一個功能強大、自動化程度較高的腳本。vim
@echo off set date=%date:~0,4%-%date:~5,2%-%date:~8,2% echo "當前時間爲:"%date% cd /d "D:\" mkdir SystemInfo cd /d "SystemInfo" systeminfo>systeminfo%date%.txt start systeminfo%date%.txt pause
# !/bin/bash currentName=`whoami` echo $currentName if [ "$currentName" = "root" ] then echo "Current Login User is root" else echo "Current Login User is :"$currentName fi
Shell 腳本語言是弱類型語言,即無須定義變量類型便可使用。在UNIX/Linux中主要有兩大類Shell:Bourne Shell和C Shell。bash
Bourne Shell包括Bourne Shell(sh)、Korn Shell(ksh)、Bourne Again Shell(bash)三種類型。微信
Bourne Shell
由AT&T的Steve Bourne開發,是標準的UNIX Shell,不少UNIX系統都配有sh。編程語言
Korn Shell(ksh)
由David Korn開發,是Bournd Shell(sh)的超集合而且添加了csh引入的新功能,是目前不少UNIX系統標配的Shell,這些系統上的/bin/sh每每指向/bin/ksh的符號連接編輯器
Bourne Again Shell(bash)
由GNU項目組開發,主要目標是與POSIX標準操持一致,同時兼容sh。bash從csh和ksh借鑑了不少功能,是各類Linux發行版本默認配置的Shell。Linux系統上的/bin/sh每每是指向/bin/bash的符號連接。但bash和sh仍是有不少不一樣之處,雖然bash擴展了一些命令和參數,但bash並不徹底兼容sh,二者之間有些行爲並不一致。在大多數狀況下區別不太大,有時還可使用bash替代sh。函數
C Shell包括csh和tcsh兩種。csh由Berkeley大學開發,隨之BSD UNIX發佈,它的流程控制語句很像C語言,支持不少Bourne Shell所不支持的功能,如做業控制、別名、系統算術、命令歷史、命令行編輯等。tcsh是csh的加強版,加入了命令補全等功能,在FreeBSD、Mac OS X等系統上代替了csh。
以上介紹的這些Shell中,較爲通用的是標準的Bourne Shell(sh)和C Shell(csh),而其中Bourne Shell(sh)已經被Bourne Again Shell(bash)所取代。可經過如下命令查看CentOS 7.3系統Shell的支持狀況。
[admin@CentOS7 tmp]$ cat /etc/shells /bin/sh #Linux經常使用的Shell,指向/bin/bash /bin/bash #Linux經常使用的Shell,也是默認使用的Shell /sbin/nologin #Linux經常使用的Shell,用於禁止用戶登陸 /usr/bin/sh /usr/bin/bash /usr/sbin/nologin /bin/tcsh /bin/csh
Linux系統中主流的Shell是bash,而bash是由Bourne Shell(sh)發展而來,同時bash還包含了csh和ksh的特點。所以大多數腳本均可以不作修改便可在sh運行,若是使用sh後結果與預期有差別,能夠嘗試用bash代替sh.
在經常使用的操做系統中,Linux中默認的Shell是Bourne Again Shell(bash),Solaris和FreeBSD下默認的是Bourne Shell(sh),AIX下默認的是Korn Shell(ksh)。那麼問題來了,咱們該如何查看所使用系統的Shell?以CentOS爲例查看系統默認的Shell:
[admin@CentOS7 tmp]$ echo $SHELL /bin/bash
[admin@CentOS7 tmp]$ grep root /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin
root用戶結尾的/bin/bash就是用戶登陸後的Shell解釋器。後續文章中重點講解的是Bourne Again Shell(bash)。
在Linux系統中,Shell腳本一般是在編輯器vi/vim中進行編寫。可由UNIX/Linux命令、bash shell命令、程序結構控制語句、註釋等組成,推薦使用vim。
#!/bin/bash 或 #!/bin/sh
注意事項:
一、第一行通常要求小於255個字符。
二、#!/bin/bash不是註釋,在執行腳本時,內核會根據#!後的解釋器肯定使用哪一個解釋器來執行腳本的內容。
三、這一行必須位於每一個腳本頂端的第一行,若是不是第一行則是表明註釋
#!/bin/bash echo "bash test" #!/bin/bash #表明該行是註釋 #!/bin/sh #表明該行是註釋
從上圖能夠看到sh爲bash的軟連接,大多數狀況下,腳本開頭使用#!/bin/bash和#!/bin/sh是沒有區別的。但仍是建議採用#!/bin/bash。
通常狀況下,安裝完Linux系統以後會自動安裝好bash軟件,查看bash版本以下所示:
[admin@CentOS7 etc]$ cat /etc/redhat-release CentOS Linux release 7.3.1611 (Core) #當前系統版本 [admin@CentOS7 etc]$ bash --version GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu) # bash 版本,後續省略自由軟件提示信息
若是想體驗更高版本的bash,升級方法以下所示:
yum -y update bash #在線升級 rpm -qa bash #查看bash安裝包 bash-4.2.46-20.el7_2.x86_64
如下是經常使用腳本開頭的寫法,不一樣語言的腳本在開頭通常都要加上以下標識內容:
#!/bin/sh #!/bin/bash #!/usr/bin/awk #!/bin/sed #!/usr/bin/tcsh #!/usr/bin/perl
CentOS中默認的Shell均爲bash。所以即在腳本中未加#!/bin/bash,它也會使用bash去解釋。若是不但願使用系統默認的Shell解釋器,就須要自行指定解釋器。建議你們一開始就養成好習慣,遵循Shell編程規範,在開頭第一行指定所使用的解釋器
若是在開頭未指定解釋器,要使用對應的解釋器來執行腳本時,可使用以下方法:
Shell腳本: bash test.sh或sh test.sh Python腳本:python test.py
在不少編程語言中,都會支持單行和多行註釋,方便閱讀和維護,在Shell中,使用#對所在行進行註釋,註釋的內容並不會看成命令執行。註釋可單獨一行也能夠緊跟在命令後面。建議在寫腳本添加必要的註釋,方便本身也方便後續維護者或使用者。
註釋中儘可能不要使用中文,腳本中也儘可能不要使用中文。
Shell腳本的執行流程
當腳本運行時,它會先查找系統環境變量ENV,該變量指定了環境文件(加載順序一般是/etc/profile、~/.bash_profile、~/.bashrc、/etc/bashrc等),在加載了上述環境變量文件後,Shell開始執行Shell腳本中的內容。
Shell腳本執行的順序是從上到下,從左到右依次執行每一行的命令及語句。若是Shell中存在腳本嵌套(子腳本)時,就會執行嵌套腳本的內容,完成後再返回父腳本繼續執行父腳本內後續的命令和語句。一般狀況下,執行Shell腳本時,會向系統內核啓動一個新的進程,以便在該進程中執行腳本的命令和子腳本,其流程圖以下所示:
Shell腳本的執行方式
【1】bash script-name或sh script-name
這種方式是當腳本文件自己沒有可執行權限(即文件屬性沒有x佔位符)時常使用的方式或腳本文件沒有指定解釋器時經常使用的方法。
【2】path/script-name或./script-name
這種方式是指在當前路徑下執行腳本,前提是腳本必須有可執行權限,具體方法爲chmod +x script-name。而後經過相對路徑或絕對路徑執行腳本。
【3】source script-name或. script-name
這種方法一般使用source或" . "讀入或加載指定的Shell腳本,如son.sh,而後依次執行指定的Shell腳本文件son.sh中的全部語句。這些語句將在當前父Shell腳本father.sh中運行(其餘幾種模式都會啓動新的進程執行子腳本)。
使用source或" . "能夠將son.sh自身腳本中的變量值或函數等的返回值傳遞到當前父Shell腳本father.sh中使用,這是和其餘兩種方法最大的區別,所以須要特別注意。
【4】sh<script-name或cat script-name | sh
這種方法一樣適用於bash,這種方法並不常見,瞭解知道便可。其原理就是利用了管道技術。
你們能夠看看如下腳本的正確答案是哪個?
參考的答案選項以下所示:
正確答案是無內容輸入。緣由可查看Shell腳本的幾種執行方式。
經過這個示例咱們能夠得出以下結論:
每種語言都有本身的開發規範,雖然不是強制遵照,但有規範的代碼不便方便閱讀、維護、多人協同開發,同時也能減小出現Bug的機率。主要的規範以下所示:
#!/bin/bash 或 #!/bin/sh
#Date:2017-11-29 22:50 #Author:Surpassme #Description:This is sample shell scripts #Version:1.5
【3】Shell腳本中儘可能不要使用中文
雖然說Linux也能兼容中文,但仍是存在切換系統環境後中文出現亂碼的問題。若是非要用中文,可對系統進行字符集調整。如export LANG="zh_CN.UTF-8",並在腳本中從新定義字符集設置和系統保持一致。
【4】Shell腳本儘可能添加擴展名.sh
一、成對的符號儘可能一次性寫全,防止遺漏 二、中括號([])兩端至少要保留一個空格。 三、流程控制語句,應一次性將格式寫完,再添加內容 四、良好的代碼縮進,方便閱讀 五、腳本的各個符號必須爲英文狀態下的符號 六、常規變量的字符串定義時應加雙引號("")而且等號先後均不能有空格,須要強引用(指所見即所得的字符串引用),則使用單引號(''),若是是命令引用,則用反引號(``)
本文同步在微信訂閱號上發佈,如各位小夥伴們喜歡個人文章,也能夠關注個人微信訂閱號:woaitest,或掃描下面的二維碼添加關注: