
初步入門1、什么時Shell2、什么是Shell腳本3、Shell腳本在Linux運(yùn)維工作中的地位4、腳本語言的種類4.1、Shell腳本語言的種類4.2、其他常用的腳本語言種類4.3、Shell腳本語言的優(yōu)勢5、常用操作系統(tǒng)默認(rèn)的Shell6、Shell腳本的建立和執(zhí)行6.1、Shell腳本的建立6.2、Shell腳本的執(zhí)行6.3、Shell腳本開發(fā)的基本規(guī)范及習(xí)慣1、什么時ShellShell是一個命令解釋器它的作用是解釋執(zhí)行用戶輸入的命令及程序等用戶每輸入一條命令Shell就解釋執(zhí)行一條。這種從鍵盤一輸入命令就可以立即得到回應(yīng)的對話方式稱為交互的方式。Shell存在于操作系統(tǒng)的最外層負(fù)責(zé)與用戶直接對話把用戶的輸入解釋給操作系統(tǒng)并處理各種各樣的操作系統(tǒng)的輸出結(jié)果然后輸出到屏幕返回給用戶。輸入系統(tǒng)用戶名和密碼并登錄到Linux后的所有操作都是由Shell解釋與執(zhí)行的。下圖針對命令解釋器Shell在操作系統(tǒng)中所處的位置給出了基本圖解。提示Shell的英文是貝殼的意思從圖中可以看出命令解釋器Shell就像貝殼一樣包住了系統(tǒng)核心。2、什么是Shell腳本理解了Shell之后再理解Shell腳本就簡單了。當(dāng)命令或程序語句不在命令行下執(zhí)行而是通過一個程序文件來執(zhí)行時該程序就被稱為Shell腳本。如果在Shell腳本里內(nèi)置了很多條命令、語句及循環(huán)控制然后將這些命令一次性執(zhí)行完畢這種通過文件執(zhí)行腳本的方式稱為非交互的方式。Shell腳本類似于DOS系統(tǒng)下的批處理程序早期擴(kuò)展名一般為“*.bat”??。用戶可以在Shell腳本中敲入一系列的命令及命令語句組合。這些命令、變量和流程控制語句等有機(jī)地結(jié)合起來就形成了一個功能強(qiáng)大的Shell腳本。下面是在Windows下利用bat批處理程序開發(fā)的備份企業(yè)網(wǎng)站及數(shù)據(jù)庫數(shù)據(jù)的腳本范例。在Windows下利用bat批處理程序備份網(wǎng)站及數(shù)據(jù)庫數(shù)據(jù)的腳本。echo off set date%date:0,4%-%date:5,2%-%date:8,2% #定義時間變量。 mysqldump -uroot -poldboy -A -B D:\bak\%date%.sql #備份數(shù)據(jù)庫數(shù)據(jù)。 rar.exe a -k -r -s -m1 D:\bak\%date%.sql.rar D:\bak\%date%.sql #打包備份出來的數(shù)據(jù)庫數(shù)據(jù)。 del D:\bak\.sql #刪除未打包的無用數(shù)據(jù)庫數(shù)據(jù)。 rar.exe a -k -r -s -m1 D:\bak\%date%htdocs.rar D:\work\PHPnow\htdocs #打包站點(diǎn)目錄下的數(shù)據(jù)。清除/var/log下messages日志文件的簡單命令腳本。# 清除日志腳本 版本 1。cd/var/logcat/dev/nullmessagesechoLogs cleaned up.提示/var/log/messages是Linux系統(tǒng)的日志文件很重要。上面所示的腳本其實(shí)是有一些問題的具體如下如果不是root用戶則無法執(zhí)行腳本清理日志并且會提示系統(tǒng)的權(quán)限報(bào)錯信息。沒有任何流程控制語句簡單地說就是只進(jìn)行順序操作沒有成功判斷和邏輯嚴(yán)密性。范例寫一個包含命令、變量和流程控制的語句來清除/var/log下messages日志文件的Shell腳本。# ! /bin/bash# 清除日志腳本 版本 2LOG_DIR/var/logROOT_UID0#$UID為0的用戶即root用戶# 腳本需要使用root用戶權(quán)限來運(yùn)行因此對當(dāng)前用戶進(jìn)行判斷對不合要求的用戶給出友好提示并終止程序運(yùn)行。if[$UID-ne$ROOT_UID]#如果當(dāng)前用戶不是root則不允許執(zhí)行腳本。thenechoMust be root to run this script.#給出提示后退出。exit1#退出腳本。fi# 如果切換到指定目錄不成功則給出提示并終止程序運(yùn)行。cd$LOG_DIR||{echoCannot change to necessary directory.exit1}# 經(jīng)過上述兩個判斷后此處的用戶權(quán)限和路徑應(yīng)該就是對的了只有清空成功才打印成功提示。cat/dev/nullmessages{echoLogs cleaned up.exit0# 退出之前返回0表示成功返回1表示失敗。}echoLogs cleaned up fail.exit1初學(xué)者如果想要快速掌握Shell腳本的編寫方法最有效的思路就是采用電子游戲中過關(guān)的方式比如對于范例腳本可以設(shè)計(jì)成如下幾關(guān)第一關(guān)必須是root才能執(zhí)行腳本否則給出友好提示并終止腳本運(yùn)行。第二關(guān)成功切換目錄cd /var/log?否則給出友好提示并終止腳本運(yùn)行。第三關(guān)清理日志cat /dev/null messages?若清理成功則給出正確提示。第四關(guān)通關(guān)或失敗分別給出相應(yīng)的提示echo輸出?。3、Shell腳本在Linux運(yùn)維工作中的地位Shell腳本語言很適合用于處理純文本類型的數(shù)據(jù)而Linux系統(tǒng)中幾乎所有的配置文件、日志文件如NFS、Rsync、Httpd、Nginx、LVS、MySQL等?以及絕大多數(shù)的啟動文件都是純文本類型的文件。因此學(xué)好Shell腳本語言就可以利用它在Linux系統(tǒng)中發(fā)揮巨大的作用。下圖形象地展示了Shell腳本在運(yùn)維工作中的地位。4、腳本語言的種類4.1、Shell腳本語言的種類Shell腳本語言是弱類型語言無須定義變量的類型即可使用?在Unix/Linux中主要有兩大類Shell一類是Bourne shell另一類是C shell。1. Bourne shellBourne shell又包括Bourne shellsh?、Korn shellksh?、Bourne Again Shellbash三種類型。Bourne shellsh由ATT的Steve Bourne開發(fā)是標(biāo)準(zhǔn)的UNIX Shell很多UNIX系統(tǒng)都配有sh。Korn shellksh由David Korn開發(fā)是Bourneshellsh的超集合并且添加了csh引入的新功能是目前很多UNIX系統(tǒng)標(biāo)準(zhǔn)配置的Shell這些系統(tǒng)上的/bin/sh往往是指向/bin/ksh的符號鏈接。Bourne Again Shellbash由GNU項(xiàng)目組開發(fā)主要目標(biāo)是與POSIX標(biāo)準(zhǔn)保持一致同時兼顧對sh的兼容bash從csh和ksh借鑒了很多功能是各種Linux發(fā)行版默認(rèn)配置的Shell, Linux系統(tǒng)上的/bin/sh往往是指向/bin/bash的符號鏈接。盡管如此bash和sh還是有很多的不同之處一方面bash擴(kuò)展了一些命令和參數(shù)另一方面bash并不完全和sh兼容它們有些行為并不一致但在大多數(shù)企業(yè)運(yùn)維的情況下區(qū)別不大特殊場景可以使用bash替代sh。** 2. C shell**C shell又包括csh、tcsh兩種類型。csh由Berkeley大學(xué)開發(fā)隨BSD UNIX發(fā)布它的流程控制語句很像C語言支持很多Bourne shell所不支持的功能例如作業(yè)控制、別名、系統(tǒng)算術(shù)、命令歷史、命令行編輯等。tcsh是csh的增強(qiáng)版加入了命令補(bǔ)全等功能在FreeBSD、Mac OS X等系統(tǒng)上替代了csh。以上介紹的這些Shell中較為通用的是標(biāo)準(zhǔn)的Bourneshellsh和C shellcsh?。其中Bourne shellsh已經(jīng)被Bourne Again shellbash所取代??赏ㄟ^以下命令查看CentOS 6系統(tǒng)的Shell支持情況。[rootoldboy ]# cat /etc/shells/bin/sh#這是Linux里常用的Shell指向/bin/bash。/bin/bash#這是Linux里常用的Shell也是默認(rèn)使用的Shell。/sbin/nologin#這是Linux里常用的Shell用于禁止用戶登錄。/bin/dash /bin/tcsh /bin/cshLinux系統(tǒng)中的主流Shell是bash, bash是由Bourne Shellsh發(fā)展而來的同時bash還包含了csh和ksh的特色但大多數(shù)腳本都可以不加修改地在sh上運(yùn)行如果使用了sh后發(fā)現(xiàn)結(jié)果和預(yù)期有差異那么可以嘗試用bash替代sh。4.2、其他常用的腳本語言種類1. PHP語言PHP是網(wǎng)頁程序語言也是腳本語言。它是一款更專注于Web頁面開發(fā)前端展示的語言例如wordpress、dedecms、discuz等著名的開源產(chǎn)品都是用PHP語言開發(fā)的。用PHP程序語言也可以處理系統(tǒng)日志、配置文件等還可以調(diào)用Linux系統(tǒng)命令但是很少有人這么用。2. Perl語言Perl腳本語言比Shell腳本語言強(qiáng)大很多在2010年以前很流行它的語法靈活、復(fù)雜在實(shí)現(xiàn)不同的功能時可以用多種不同的方式缺點(diǎn)是不易讀團(tuán)隊(duì)協(xié)作困難但它仍不失為一種很好的腳本語言存世的大量相關(guān)程序軟件3. Python語言Python是近幾年非常流行的語言它不但可以用于腳本程序開發(fā)也可以實(shí)現(xiàn)Web頁面程序開發(fā)例如CMDB管理系統(tǒng)?甚至還可以實(shí)現(xiàn)軟件的開發(fā)例如大名鼎鼎的OpenStack、SaltStack都是Python語言開發(fā)的?、游戲開發(fā)、大數(shù)據(jù)開發(fā)、移動端開發(fā)。4.3、Shell腳本語言的優(yōu)勢Shell腳本語言的優(yōu)勢在于處理偏操作系統(tǒng)底層的業(yè)務(wù)例如Linux系統(tǒng)內(nèi)部的很多應(yīng)用有的是應(yīng)用的一部分都是使用Shell腳本語言開發(fā)的因?yàn)橛?000多個Linux系統(tǒng)命令為它做支撐特別是Linux正則表達(dá)式及三劍客grep、awk、sed等命令。對于一些常見的系統(tǒng)腳本使用Shell開發(fā)會更簡單、更快速例如讓軟件一鍵自動化安裝、優(yōu)化監(jiān)控報(bào)警腳本軟件啟動腳本日志分析腳本等雖然PHP/Python語言也能夠做到這些但是考慮到掌握難度、開發(fā)效率、開發(fā)習(xí)慣等因素它們可能就不如Shell腳本語言流行及有優(yōu)勢了。對于一些常規(guī)的業(yè)務(wù)應(yīng)用使用Shell更符合Linux運(yùn)維簡單、易用、高效的三大基本原則。PHP語言的優(yōu)勢在于小型網(wǎng)站系統(tǒng)的開發(fā)Python語言的優(yōu)勢在于開發(fā)較復(fù)雜的運(yùn)維工具軟件、Web界面的管理工具和Web業(yè)務(wù)的開發(fā)例如CMDB自動化運(yùn)維平臺、跳板機(jī)、批量管理軟件SaltStack、云計(jì)算OpenStack軟件等。我們在開發(fā)一個應(yīng)用時應(yīng)根據(jù)業(yè)務(wù)需求結(jié)合不同語言的優(yōu)勢及自身擅長的語言來選擇揚(yáng)長避短從而達(dá)到高效開發(fā)及易于自身維護(hù)等目的。5、常用操作系統(tǒng)默認(rèn)的Shell在常用的操作系統(tǒng)中Linux下默認(rèn)的Shell是BourneAgain shellbash; Solaris和FreeBSD下默認(rèn)的是Bourne shellsh; AIX下默認(rèn)的是Korn Shellksh?。這里重點(diǎn)講Linux系統(tǒng)環(huán)境下的Bourne Again shellbash?。下面來看一個企業(yè)面試題CentOS Linux系統(tǒng)默認(rèn)的Shell是什么這題的答案就是bash。通過以下兩種方法可以查看CentOS Linux系統(tǒng)默認(rèn)的Shell。方法1[rootoldboy ]# echo $SHELL/bin/bash方法2[rootoldboy ]# grep root /etc/passwdroot:x:0:0:root:/root:/bin/bash提示結(jié)尾的/bin/bash就是用戶登錄后的Shell解釋器。注意本書寫作的環(huán)境為Linux系統(tǒng)具體版本為CentOS 6.x x86_64絕大部分已寫好的腳本程序都不需要經(jīng)過任何修改就可以直接應(yīng)用于其他的Linux系統(tǒng)中。對于一些UNIX系統(tǒng)因?yàn)槟J(rèn)不是bash解釋器所以需要根據(jù)解釋器版本進(jìn)行調(diào)整本書的全部內(nèi)容都是以bash及和bash兼容的sh解釋器為基礎(chǔ)編寫的。6、Shell腳本的建立和執(zhí)行6.1、Shell腳本的建立在Linux系統(tǒng)中Shell腳本bash Shell程序通常是在編輯器vi/vim中編寫的由UNIX/Linux命令、bash Shell命令、程序結(jié)構(gòu)控制語句和注釋等內(nèi)容組成。這里推薦用Linux自帶的功能更強(qiáng)大的vim編輯器來編寫可以事先做一個別名alias vi‘vim’并使其永久生效這樣以后習(xí)慣輸入vi的讀者也就可以直接調(diào)用vim編輯器了設(shè)置方法如下[rootoldboy ]# echo alias vivim /etc/profile[rootoldboy ]# tail -1 /etc/profilealiasvivim[rootoldboy ]# source /etc/profile1腳本開頭第一行一個規(guī)范的Shell腳本在第一行會指出由哪個程序解釋器來執(zhí)行腳本中的內(nèi)容這一行內(nèi)容在Linux bash的編程一般為#! /bin/bash或#! /bin/sh #255個字符以內(nèi)。其中開頭的“#! ”字符又稱為幻數(shù)其實(shí)叫什么都無所謂知道它的作用就好?在執(zhí)行bash腳本的時候內(nèi)核會根據(jù)“#! ”后的解釋器來確定該用哪個程序解釋這個腳本中的內(nèi)容。注意這一行必須位于每個腳本頂端的第一行如果不是第一行則為腳本注釋行例如下面的例子。[oldboyoldboy ]$cattest.sh#! /bin/bashechooldboy start#! /bin/bash #寫到這里就是注釋了。#! /bin/sh #寫到這里就是注釋了。echooldboy end2. bash與sh 的區(qū)別早期的bash與sh稍有不同它還包含了csh和ksh的特色但大多數(shù)腳本都可以不加修改地在sh上運(yùn)行比如[rootoldboy ]# ll /bin/shlrwxrwxrwx.1root root43月1920:54 /bin/sh -bash[rootoldboy ]# ll /bin/bash-rwxr-xr-x1root root94041610月1621:56 /bin/bash提示sh為bash的軟鏈接大多數(shù)情況下腳本的開頭使用“#! /bin/bash”和“#! /bin/sh”是沒有區(qū)別的但更規(guī)范的寫法是在腳本的開頭使用“#!/bin/bash”?。下面的Shell腳本是系統(tǒng)自帶的軟件啟動腳本的開頭部分。[rootoldboy ]# head -1 /etc/init.d/sshd#! /bin/bash[rootoldboy ]# head -1 /etc/init.d/ntpd#! /bin/bash[rootoldboy ]# head -1 /etc/init.d/crond#! /bin/sh提示如果使用/bin/sh執(zhí)行腳本出現(xiàn)異常那么可以再使用/bin/bash試一試但是一般不會發(fā)生此類情況。一般情況下在安裝Linux系統(tǒng)時會自動安裝好bash軟件查看系統(tǒng)的bash版本的命令如下。[rootoldboy ]# cat /etc/redhat-releaseCentOS release6.8(Final)#這里顯示的是作者寫作的Linux的環(huán)境版本。[rootoldboy ]# bash --versionGNU bash, version4.1.2(1)-release(x86_64-redhat-linux-gnu)#這里顯示的是bash的版本。Copyright(C)2009Free Software Foundation, Inc.#下面幾行是自由軟件提示的相關(guān)信息。License GPLv3: GNU GPL version3or later http://gnu.org/licenses/gpl.html This isfreesoftware;you arefreeto change and redistribute it. There is NO WARRANTY, to the extent permitted by law.如果讀者使用的是較老版本的Shell那么建議將其升級到最新版本的Shell特別是企業(yè)使用因?yàn)榻鼉赡昀习姹镜腷ash被暴露出存在較嚴(yán)重的安全漏洞。例如bash軟件曾經(jīng)爆出了嚴(yán)重漏洞破殼漏洞?憑借此漏洞攻擊者可能會接管計(jì)算機(jī)的整個操作系統(tǒng)得以訪問各種系統(tǒng)內(nèi)的機(jī)密信息并對系統(tǒng)進(jìn)行更改等。任何人的計(jì)算機(jī)系統(tǒng)如果使用了bash軟件都需要立即打上補(bǔ)丁。檢測系統(tǒng)是否存在漏洞的方法為[rootoldboy ]# env x() { :; }; echo be careful bash -c echo this is a testthis is atest如果返回如下兩行則表示需要盡快升級bash了不過僅僅是用于學(xué)習(xí)和測試就無所謂了。be careful this is atest升級方法為[rootoldboy ]# yum -y update bash[rootoldboy ]# rpm -qa bashbash-4.1.2-40.el6.x86_64下面是Linux中常用腳本開頭的寫法不同語言的腳本在開頭一般都要加上如下標(biāo)識內(nèi)容1#! /bin/sh2#! /bin/bash3#! /usr/bin/awk4#! /bin/sed5#! /usr/bin/tcl6#! /usr/bin/expect #expect解決交互式的語言開頭解釋器。7#! /usr/bin/perl #perl語言解釋器。8#! /usr/bin/env python #python語言解釋器。CentOS和Red Hat Linux下默認(rèn)的Shell均為bash。因此在寫Shell腳本的時候腳本的開頭即使不加“#!/bin/bash”?它也會交給bash解釋。如果寫腳本不希望使用系統(tǒng)默認(rèn)的Shell解釋那么就必須要指定解釋器了否則腳本文件執(zhí)行后的結(jié)果可能就不是你所要的。建議讀者養(yǎng)成好的編程習(xí)慣不管采用什么腳本最好都加上相應(yīng)的開頭解釋器語言標(biāo)識遵守Shell編程規(guī)范。如果在腳本開頭的第一行不指定解釋器那么就要用對應(yīng)的解釋器來執(zhí)行腳本這樣才能確保腳本正確執(zhí)行。例如如果是Shell腳本就用bash test.sh執(zhí)行test.sh。如果是Python腳本就用python test.py執(zhí)行test.py。如果是expect腳本就用expect test.exp執(zhí)行test.exp。3腳本注釋在Shell腳本中跟在#后面的內(nèi)容表示注釋用來對腳本進(jìn)行注釋說明注釋部分不會被當(dāng)作程序來執(zhí)行僅僅是給開發(fā)者和使用者看的系統(tǒng)解釋器是看不到的更不會執(zhí)行。注釋可自成一行也可以跟在腳本命令的后面與命令在同一行。開發(fā)腳本時如果沒有注釋那么團(tuán)隊(duì)里的其他人就會很難理解腳本對應(yīng)內(nèi)容的用途而且若時間長了自己也會忘記。因此我們要盡量養(yǎng)成為所開發(fā)的Shell腳本書寫關(guān)鍵注釋的習(xí)慣書寫注釋不光是為了方便別人更是為了方便自己避免影響團(tuán)隊(duì)的協(xié)作效率以及給后來接手的人帶來維護(hù)困難。特別提示一下注釋盡量不要用中文在腳本中最好也不要有中文。6.2、Shell腳本的執(zhí)行當(dāng)Shell腳本運(yùn)行時它會先查找系統(tǒng)環(huán)境變量ENV該變量指定了環(huán)境文件加載順序通常是/etc/profile、/.bash_profile、/.bashrc、/etc/bashrc等?在加載了上述環(huán)境變量文件后Shell就開始執(zhí)行Shell腳本中的內(nèi)容?。Shell腳本是從上至下、從左至右依次執(zhí)行每一行的命令及語句的即執(zhí)行完了一個命令后再執(zhí)行下一個如果在Shell腳本中遇到子腳本即腳本嵌套時就會先執(zhí)行子腳本的內(nèi)容完成后再返回父腳本繼續(xù)執(zhí)行父腳本內(nèi)后續(xù)的命令及語句。通常情況下在執(zhí)行Shell腳本時會向系統(tǒng)內(nèi)核請求啟動一個新的進(jìn)程以便在該進(jìn)程中執(zhí)行腳本的命令及子Shell腳本基本流程如下圖所示。特殊技巧設(shè)置Linux的crond任務(wù)時最好能在定時任務(wù)腳本中重新定義系統(tǒng)環(huán)境變量否則一些系統(tǒng)環(huán)境變量將不會被加載這個問題需要注意Shell腳本的執(zhí)行通??梢圆捎靡韵聨追N方式。1bash script-name或sh script-name這是當(dāng)腳本文件本身沒有可執(zhí)行權(quán)限即文件權(quán)限屬性x位為-號時常使用的方法或者腳本文件開頭沒有指定解釋器時需要使用的方法。這也是老男孩推薦使用的方法。2path/script-name或/script-name指在當(dāng)前路徑下執(zhí)行腳本腳本需要有執(zhí)行權(quán)限?需要將腳本文件的權(quán)限先改為可執(zhí)行即文件權(quán)限屬性加x位?具體方法為chmod x script-name。然后通過腳本絕對路徑或相對路徑就可以直接執(zhí)行腳本了。在企業(yè)生產(chǎn)環(huán)境中不少運(yùn)維人員在寫完Shell腳本之后由于忘記為該腳本設(shè)置執(zhí)行權(quán)限然后就直接應(yīng)用了結(jié)果導(dǎo)致腳本沒有按照自己的意愿手動或定時執(zhí)行對于這一點(diǎn)避免出現(xiàn)該問題的方法就是用第1種方法替代第2種。3source script-name或script-name這種方法通常是使用source或“.”?點(diǎn)號讀入或加載指定的Shell腳本文件如san.sh?然后依次執(zhí)行指定的Shell腳本文件san.sh中的所有語句。這些語句將在當(dāng)前父Shell腳本father.sh進(jìn)程中運(yùn)行其他幾種模式都會啟動新的進(jìn)程執(zhí)行子腳本?。因此使用source或“.”可以將san.sh自身腳本中的變量值或函數(shù)等的返回值傳遞到當(dāng)前父Shell腳本father.sh中使用。這是它和其他幾種方法最大的區(qū)別也是值得讀者特別注意的地方。source或“.”命令的功能是在當(dāng)前Shell中執(zhí)行source或“.”加載并執(zhí)行的相關(guān)腳本文件中的命令及語句而不是產(chǎn)生一個子Shell來執(zhí)行文件中的命令。注意“.”和后面的腳本名之間要有空格。如果讀者學(xué)過PHP開發(fā)就會明白source或“.”相當(dāng)于include的功能。HTTP服務(wù)軟件Apache、Nginx等配置文件里都支持這樣的用法。4shscript-name或cat scripts-name|sh同樣適用于bash不過這種用法不是很常見但有時也可以有出奇制勝的效果例如不用循環(huán)語句來實(shí)現(xiàn)精簡開機(jī)自啟動服務(wù)的案例就是通過將所有字符串拼接為命令的形式然后經(jīng)由管道交給bash操作的案例。范例創(chuàng)建模擬腳本test.sh并輸入如下內(nèi)容。[oldboyoldboy ]$cattest.sh#編輯test.sh腳本文件。echoI am oldboy輸入“echo ‘I am oldboy’”內(nèi)容后按回車鍵然后再按Ctrld組合鍵結(jié)束編輯。此操作為特殊編輯方法這里是作為cat用法的擴(kuò)展知識通過使用來記憶是個好習(xí)慣??,F(xiàn)在使用第1種方法實(shí)踐命令如下[oldboyoldboy ]$cattest.shechoI am oldboy[oldboyoldboy ]$shtest.sh#使用第1種方式的sh命令執(zhí)行test.sh腳本文件。I am oldboy[oldboyoldboy ]$bashtest.sh#使用第1種方式的bash命令執(zhí)行test.sh腳本文件。I am oldboy這里使用第1種方法的bash和sh均可以執(zhí)行腳本并得到預(yù)期的結(jié)果。使用第2種方法實(shí)踐命令如下[oldboyoldboy ]$.test.sh#請注意開頭的“.”后面有空格。I am oldboy[oldboyoldboy ]$sourcetest.sh I am oldboy提示?“.”或source命令的功能相同都是讀入腳本并執(zhí)行腳本。給test.sh添加可執(zhí)行權(quán)限命令如下[oldboyoldboy ]$chmodux test.sh[oldboyoldboy ]$ ./test.sh I am oldboy可以看到給test.sh加完可執(zhí)行權(quán)限后就能執(zhí)行了。前面也提到了這種方法在使用前每次都需要給定執(zhí)行權(quán)限但容易被忘記且多了一些步驟增加了復(fù)雜性。使用第3種方法實(shí)踐時會將source或“.”執(zhí)行的腳本中的變量值傳遞到當(dāng)前的Shell中如下[oldboyoldboy ]$echouserdirpwdtestsource.sh#第一行的內(nèi)容通常用echo處理更方便[oldboyoldboy ]$cattestsource.shuserdirpwd#定義了一個命令變量內(nèi)容是打印當(dāng)前路徑。注意打印命令用反引號[oldboyoldboy ]$shtestsource.sh#采用sh命令執(zhí)行腳本[oldboyoldboy ]$echo$userdir#此處為空并沒有出現(xiàn)當(dāng)前路徑/home/oldboy的輸出這是為什么根據(jù)上面的例子可以發(fā)現(xiàn)通過sh或bash命令執(zhí)行過的腳本若在腳本結(jié)束之后在當(dāng)前Shell窗口中查看userdir變量的值會發(fā)現(xiàn)值是空的?,F(xiàn)在以同樣的步驟改用source或“.”執(zhí)行然后再看看userdir變量的值[oldboyoldboy ]$sourcetestsource.sh#采用source執(zhí)行同一腳本[oldboyoldboy ]$echo$userdir/home/oldboy#此處輸出了當(dāng)前路徑/home/oldboy這又是為什么呢來了解一下系統(tǒng)NFS服務(wù)的腳本是如何使用“.”的# Source function library../etc/init.d/functions#通過.加載系統(tǒng)函數(shù)庫functions說明操作系統(tǒng)及服務(wù)自帶的腳本是我們學(xué)習(xí)的標(biāo)桿和參考雖然有時感覺這些腳本也不是十分規(guī)范?。結(jié)論通過source或“.”加載執(zhí)行過的腳本由于是在當(dāng)前Shell中執(zhí)行腳本因此在腳本結(jié)束之后腳本中的變量包括函數(shù)值在當(dāng)前Shell中依然存在而sh和bash執(zhí)行腳本都會啟動新的子Shell執(zhí)行執(zhí)行完后退回到父Shell。因此變量包括函數(shù)值等無法保留。在進(jìn)行Shell腳本開發(fā)時如果腳本中有引用或執(zhí)行其他腳本的內(nèi)容或配置文件的需求時最好用“.”或source先加載該腳本或配置文件處理完之后再將它們加載到腳本的下面就可以調(diào)用source加載的腳本及配置文件中的變量及函數(shù)等內(nèi)容了。以下采用第4種方法來實(shí)踐[rootoldboy ]# ls -l oldboy.sh-rw-r--r--.1root root28Nov1815:52 oldboy.sh[rootoldboy ]# cat oldboy.shechoI am oldboy teacher.[rootoldboy ]# sholdboy.sh #盡量不要使用這種方法。I am oldboy teacher.[rootoldboy ]# cat oldboy.sh|bash #這種方法在命令行拼接字符串命令后需要執(zhí)行時就會用到 I am oldboy teacher.提示代碼中提到的兩種執(zhí)行方法相當(dāng)于sh scripts-name效率很高但是初學(xué)者用得少。范例已知如下命令及返回結(jié)果請問echo $user的返回的結(jié)果為??。[oldboytest ]$cattest.shuserwhoami[oldboytest ]$shtest.sh[oldboytest ]$echo$user參考的選擇項(xiàng)如下a當(dāng)前用戶boldboyc空無內(nèi)容輸出這是某互聯(lián)網(wǎng)公司Linux運(yùn)維職位的筆試題。在這里c是正確答案原因前面已經(jīng)講過了即使用sh執(zhí)行腳本會導(dǎo)致當(dāng)前Shell無法獲得變量值。通過上述面試題可得出如下的結(jié)論兒子Shell腳本會直接繼承父親Shell腳本的變量、函數(shù)就好像是兒子隨父親姓基因也會繼承父親的等反之則不可以。如果希望反過來繼承就好像是讓父親隨兒子姓讓父親的基因也繼承兒子的?就要用source或“.”在父親Shell腳本中事先加載兒子Shell腳本。6.3、Shell腳本開發(fā)的基本規(guī)范及習(xí)慣Shell腳本的開發(fā)規(guī)范及習(xí)慣非常重要雖然這些規(guī)范不是必須要遵守的但有了好的規(guī)范和習(xí)慣可以大大提升開發(fā)效率并能在后期降低對腳本的維護(hù)成本。當(dāng)多人協(xié)作開發(fā)時大家有一個互相遵守的規(guī)范就顯得更重要了。即使只是一個人開發(fā)最好也采取一套固定的規(guī)范這樣腳本將會更易讀、更易于后期維護(hù)最重要的是要讓自己養(yǎng)成一個一出手就很專業(yè)和規(guī)范的習(xí)慣。下面來看看有哪些規(guī)范這些規(guī)范在第14章也會提及以便于大家進(jìn)一步鞏固。1Shell腳本的第一行是指定腳本解釋器通常為#! /bin/bash或#! /bin/sh2Shell腳本的開頭會加版本、版權(quán)等信息# Date: 16:29 2012-3-30# Author: Created by oldboy# Blog:http://oldboy.blog.51cto.com# Description:This scripts function is.....# Version:1.1可修改“/.vimrc”配置文件配置vim編輯文件時自動加上以上信息的功能。3在Shell腳本中盡量不用中文不限于注釋?。盡量用英文注釋防止本機(jī)或切換系統(tǒng)環(huán)境后中文亂碼的困擾。如果非要加中文請根據(jù)自身的客戶端對系統(tǒng)進(jìn)行字符集調(diào)整如export LANG“zh_CN.UTF-8”并在腳本中重新定義字符集設(shè)置和系統(tǒng)保持一致。4Shell腳本的命名應(yīng)以sh為擴(kuò)展名。例如script-name.sh5Shell腳本應(yīng)存放在固定的路徑下。例如/server/scripts以下則是Shell腳本代碼書寫的良好習(xí)慣。1成對的符號應(yīng)盡量一次性寫出來然后退格在符號里增加內(nèi)容以防止遺漏。這些成對的符號包括{}、[]、、、2中括號?[?]?兩端至少要有1個空格因此鍵入中括號時即可留出空格[ ]?然后再退格鍵入中間的內(nèi)容并確保兩端都至少有一個空格即先鍵入一對中括號然后退1格輸入兩個空格再退1格雙中括號?[?[?]?]?的寫法也是如此。3對于流程控制語句應(yīng)一次性將格式寫完再添加內(nèi)容。比如一次性完成if語句的格式應(yīng)為if條件內(nèi)容then內(nèi)容fi一次性完成for循環(huán)語句的格式應(yīng)為fordo內(nèi)容done4通過縮進(jìn)讓代碼更易讀比如if條件內(nèi)容then內(nèi)容fi5對于常規(guī)變量的字符串定義變量值應(yīng)加雙引號并且等號前后不能有空格需要強(qiáng)引用的指所見即所得的字符引用?則用單引號’ ?如果是命令的引用則用反引號?。例如OLDBOY_FILEtest.txt6腳本中的單引號、雙引號及反引號必須為英文狀態(tài)下的符號其實(shí)所有的Linux字符及符號都應(yīng)該是英文狀態(tài)下的符號這點(diǎn)需要特別注意。