Shell編程-03-Shell腳本初步入門

什么是Shell

? ? 簡單來說Shell其實就是一個命令解釋器,而它的作用就是解釋并執(zhí)行用戶輸入的命令及程序。用戶每輸入一條命令,Shell就解釋執(zhí)行一次。這種方式很容易讓大家想起在Windows環(huán)境中使用的command命令,我們在cmd窗口輸入一條命令,按下Enter鍵,則執(zhí)行相應(yīng)的命令和結(jié)果。
? ? Shell位于操作系統(tǒng)的最外層,對外提供與用戶交互式的對話并返回相應(yīng)的執(zhí)行結(jié)果,對內(nèi)則是將用戶輸入的命令解釋給操作系統(tǒng)。Shell在操作系統(tǒng)中所處的位置如下圖所示:

3-1 Shell在操作系統(tǒng)的位置.jpg

Shell在英文中的意思就是外殼、貝殼等,從圖中也可以看出,Shell就像殼一樣包住了系統(tǒng)的核心(Kernel)

Shell命令與Command命令對比


3-2 Shell命令與Command命令_c2i.jpg

什么是Shell腳本

? ? 在理解了Shell之后,我們再來看看Shell腳本。當命令或程序語句不是在命令行中執(zhí)行時,而是通過程序文件來執(zhí)行時,該程序就稱之為Shell腳本,我依然拿Windows來做比例。當我們需要執(zhí)行比較少的命令時,我們可以一個一個命令的進行手動輸入,如果需要執(zhí)行成百上千的命令時,你會怎么辦?聰明的你肯定會脫口而出,用批處理(擴展名一般為bat或cmd)。其實Shell腳本就類似于批處理,通過在腳本中定義變量、執(zhí)行命令、調(diào)用函數(shù)和邏輯判斷、循環(huán)等形成一個有機的整體,便形成一個功能強大、自動化程度較高的腳本。

  • 在Windows通過批處理獲取系統(tǒng)信息保存為txt文件,而后自動打開該文件,代碼如下:
@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
  • Shell腳本判斷當前登錄用戶是否為root
# !/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腳本語言的種類

? ? Shell 腳本語言是弱類型語言,即無須定義變量類型即可使用。在UNIX/Linux中主要有兩大類Shell:Bourne ShellC Shell

Bourne Shell

? ? Bourne Shell包括Bourne Shell(sh)、Korn Shell(ksh)、Bourne Again Shell(bash)三種類型。

  • Bourne Shell
    ? 由AT&T的Steve Bourne開發(fā),是標準的UNIX Shell,很多UNIX系統(tǒng)都配有sh。

  • Korn Shell(ksh)
    ? 由David Korn開發(fā),是Bournd Shell(sh)的超集合并且添加了csh引入的新功能,是目前很多UNIX系統(tǒng)標配的Shell,這些系統(tǒng)上的/bin/sh往往指向/bin/ksh的符號鏈接

  • Bourne Again Shell(bash)
    ? 由GNU項目組開發(fā),主要目標是與POSIX標準操持一致,同時兼容sh。bash從csh和ksh借鑒了很多功能,是各種Linux發(fā)行版本默認配置的Shell。Linux系統(tǒng)上的/bin/sh往往是指向/bin/bash的符號鏈接。但bash和sh還是有很多不同之處,雖然bash擴展了一些命令和參數(shù),但bash并不完全兼容sh,兩者之間有些行為并不一致。在大多數(shù)情況下區(qū)別不太大,有時還可以使用bash替代sh。

C Shell

? ? C Shell包括csh和tcsh兩種。csh由Berkeley大學(xué)開發(fā),隨之BSD UNIX發(fā)布,它的流程控制語句很像C語言,支持很多Bourne Shell所不支持的功能,如作業(yè)控制、別名、系統(tǒng)算術(shù)、命令歷史、命令行編輯等。tcsh是csh的增強版,加入了命令補全等功能,在FreeBSD、Mac OS X等系統(tǒng)上代替了csh。
? ? 以上介紹的這些Shell中,較為通用的是標準的Bourne Shell(sh)和C Shell(csh),而其中Bourne Shell(sh)已經(jīng)被Bourne Again Shell(bash)所取代??赏ㄟ^以下命令查看CentOS 7.3系統(tǒng)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系統(tǒng)中主流的Shell是bash,而bash是由Bourne Shell(sh)發(fā)展而來,同時bash還包含了csh和ksh的特色。因此大多數(shù)腳本都可以不做修改即可在sh運行,如果使用sh后結(jié)果與預(yù)期有差異,可以嘗試用bash代替sh.

常用操作系統(tǒng)默認Shell

? ? 在常用的操作系統(tǒng)中,Linux中默認的Shell是Bourne Again Shell(bash),Solaris和FreeBSD下默認的是Bourne Shell(sh),AIX下默認的是Korn Shell(ksh)。那么問題來了,我們該如何查看所使用系統(tǒng)的Shell?以CentOS為例查看系統(tǒng)默認的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用戶結(jié)尾的/bin/bash就是用戶登錄后的Shell解釋器。后續(xù)文章中重點講解的是Bourne Again Shell(bash)。

Shell 腳本的建立和執(zhí)行

Shell腳本的建立

? ? 在Linux系統(tǒng)中,Shell腳本通常是在編輯器vi/vim中進行編寫??捎蒛NIX/Linux命令、bash shell命令、程序結(jié)構(gòu)控制語句、注釋等組成,推薦使用vim。

  • Shell腳本開頭(第一行)
    ? 一個規(guī)范標準的Shell腳本會在第一行指出由哪個解釋器來執(zhí)行腳本中的內(nèi)容,一般如下所示:
#!/bin/bash
或
#!/bin/sh

注意事項:

1、第一行一般要求小于255個字符。
2、#!/bin/bash不是注釋,在執(zhí)行腳本時,內(nèi)核會根據(jù)#!后的解釋器確定使用哪個解釋器來執(zhí)行腳本的內(nèi)容。
3、這一行必須位于每個腳本頂端的第一行,如果不是第一行則是代表注釋

#!/bin/bash
echo "bash test"
#!/bin/bash #代表該行是注釋
#!/bin/sh   #代表該行是注釋
  • bash和sh的區(qū)別
    ? 早期的bash與sh稍有不同,bash包含csh和ksh的特色,但大多數(shù)的腳本都可以直接在sh上運行。


    3-3 bash和sh區(qū)別.jpg

從上圖可以看到sh為bash的軟鏈接,大多數(shù)情況下,腳本開頭使用#!/bin/bash和#!/bin/sh是沒有區(qū)別的。但還是建議采用#!/bin/bash。

? 一般情況下,安裝完Linux系統(tǒng)之后會自動安裝好bash軟件,查看bash版本如下所示:

[admin@CentOS7 etc]$ cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core) #當前系統(tǒng)版本
[admin@CentOS7 etc]$ bash --version
GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu) # bash 版本,后續(xù)省略自由軟件提示信息

如果想體驗更高版本的bash,升級方法如下所示:

yum -y update bash #在線升級
rpm -qa bash  #查看bash安裝包
bash-4.2.46-20.el7_2.x86_64

? 以下是常用腳本開頭的寫法,不同語言的腳本在開頭一般都要加上如下標識內(nèi)容:

#!/bin/sh
#!/bin/bash
#!/usr/bin/awk
#!/bin/sed
#!/usr/bin/tcsh
#!/usr/bin/perl

? ? CentOS中默認的Shell均為bash。因此即在腳本中未加#!/bin/bash,它也會使用bash去解釋。如果不希望使用系統(tǒng)默認的Shell解釋器,就需要自行指定解釋器。建議大家一開始就養(yǎng)成好習(xí)慣,遵循Shell編程規(guī)范,在開頭第一行指定所使用的解釋器
? ? 如果在開頭未指定解釋器,要使用對應(yīng)的解釋器來執(zhí)行腳本時,可以使用如下方法:

Shell腳本: bash test.sh或sh test.sh
Python腳本:python test.py
  • 腳本注釋

? ? 在很多編程語言中,都會支持單行和多行注釋,方便閱讀和維護,在Shell中,使用#對所在行進行注釋,注釋的內(nèi)容并不會當作命令執(zhí)行。注釋可單獨一行也可以緊跟在命令后面。建議在寫腳本添加必要的注釋,方便自己也方便后續(xù)維護者或使用者。

注釋中盡量不要使用中文,腳本中也盡量不要使用中文。

Shell腳本的執(zhí)行

  • Shell腳本的執(zhí)行流程
    ? ? 當腳本運行時,它會先查找系統(tǒng)環(huán)境變量ENV,該變量指定了環(huán)境文件(加載順序通常是/etc/profile、~/.bash_profile、~/.bashrc、/etc/bashrc等),在加載了上述環(huán)境變量文件后,Shell開始執(zhí)行Shell腳本中的內(nèi)容。
    ? ? Shell腳本執(zhí)行的順序是從上到下,從左到右依次執(zhí)行每一行的命令及語句。如果Shell中存在腳本嵌套(子腳本)時,就會執(zhí)行嵌套腳本的內(nèi)容,完成后再返回父腳本繼續(xù)執(zhí)行父腳本內(nèi)后續(xù)的命令和語句。通常情況下,執(zhí)行Shell腳本時,會向系統(tǒng)內(nèi)核啟動一個新的進程,以便在該進程中執(zhí)行腳本的命令和子腳本,其流程圖如下所示:

    3-4 Shell腳本執(zhí)行基本流程圖_c2i.jpg

  • Shell腳本的執(zhí)行方式

【1】bash script-name或sh script-name
? ? 這種方式是當腳本文件本身沒有可執(zhí)行權(quán)限(即文件屬性沒有x占位符)時常使用的方式或腳本文件沒有指定解釋器時常用的方法。

3-5 Shell執(zhí)行方式-1.jpg

【2】path/script-name或./script-name
? ? 這種方式是指在當前路徑下執(zhí)行腳本,前提是腳本必須有可執(zhí)行權(quán)限,具體方法為chmod +x script-name。然后通過相對路徑或絕對路徑執(zhí)行腳本。

3-6 Shell執(zhí)行方式-2.jpg

【3】source script-name或. script-name
? ? 這種方法通常使用source或" . "讀入或加載指定的Shell腳本,如son.sh,然后依次執(zhí)行指定的Shell腳本文件son.sh中的所有語句。這些語句將在當前父Shell腳本father.sh中運行(其他幾種模式都會啟動新的進程執(zhí)行子腳本)。

使用source或" . "可以將son.sh自身腳本中的變量值或函數(shù)等的返回值傳遞到當前父Shell腳本father.sh中使用,這是和其他兩種方法最大的區(qū)別,因此需要特別注意。
3-7 Shell執(zhí)行方式-3_c2i.jpg

**【4】sh<script-name或cat script-name | sh **
? ? 這種方法同樣適用于bash,這種方法并不常見,了解知道即可。其原理就是利用了管道技術(shù)。

3-8 Shell執(zhí)行方式-4.jpg
  • 示例

大家可以看看以下腳本的正確答案是哪一個?

3-9 Shell執(zhí)行示例-1.jpg

參考的答案選項如下所示:

  • [ ] 當前用戶
  • [ ] admin
  • [ ] 無內(nèi)容輸入

正確答案是無內(nèi)容輸入。原因可查看Shell腳本的幾種執(zhí)行方式。

通過這個示例我們可以得出如下結(jié)論:

  • 子Shell腳本會直接繼承父Shell的變量、函數(shù)等,如兒子繼承父親基因。
  • 如果希望父Shell繼承子Shell的變量,就要使用source或" . "
3-10 Shell執(zhí)行示例-2.jpg

腳本規(guī)范

? ? 每種語言都有自己的開發(fā)規(guī)范,雖然不是強制遵守,但有規(guī)范的代碼不便方便閱讀、維護、多人協(xié)同開發(fā),同時也能減少出現(xiàn)Bug的概率。主要的規(guī)范如下所示:

  • 【1】Shell腳本的第一行指定腳本解釋器
#!/bin/bash
或
#!/bin/sh
  • 【2】Shell腳本的開關(guān)添加版本、版權(quán)、作者等
#Date:2017-11-29 22:50
#Author:Surpassme
#Description:This is sample shell scripts
#Version:1.5
  • 【3】Shell腳本中盡量不要使用中文
    ? 雖說Linux也能兼容中文,但還是存在切換系統(tǒng)環(huán)境后中文出現(xiàn)亂碼的問題。如果非要用中文,可對系統(tǒng)進行字符集調(diào)整。如export LANG="zh_CN.UTF-8",并在腳本中重新定義字符集設(shè)置和系統(tǒng)保持一致。

  • 【4】Shell腳本盡量添加擴展名.sh

  • 【5】養(yǎng)成良好的腳本書寫習(xí)慣

1、成對的符號盡量一次性寫全,防止遺漏
2、中括號([])兩端至少要保留一個空格。
3、流程控制語句,應(yīng)一次性將格式寫完,再添加內(nèi)容
4、良好的代碼縮進,方便閱讀
5、腳本的各個符號必須為英文狀態(tài)下的符號
6、常規(guī)變量的字符串定義時應(yīng)加雙引號("")并且等號前后均不能有空格,需要強引用(指所見即所得的字符串引用),則使用單引號(''),如果是命令引用,則用反引號(``)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容