開始你的bash/shell腳本編程

原文鏈接??

I love bash

對于我自己來說,學習新框架或技術的最佳方式是同時獲得實踐經(jīng)驗浪讳,在本文中,你將自己通過編寫代碼來學習shell腳本的基礎知識涌萤!本文包含語法淹遵,shell腳本的基礎知識到中級shell編程,通過這篇文章你可以學習shell的相關知識负溪,并且通過shell來實現(xiàn)Unix/Linux之間的接口

1_qo-oir60xdhic3wjqpu64g

介紹

您可能已經(jīng)多次遇到過“腳本”這個詞透揣,但腳本的的含義是什么意思呢?簡單的來說川抡,腳本是包含一系列要執(zhí)行的命令辐真。這些命令由解釋器執(zhí)行。一切你可以在命令行中輸入的命令崖堤,你都可以把它放到腳本中侍咱。而且,腳本非常適合自動化任務密幔。如果你發(fā)現(xiàn)自己頻繁重復一些命令楔脯,你可以創(chuàng)建一個腳本來實現(xiàn)它!

welcome

The Linux philosophy is ‘Laugh in the face of danger’. Oops. Wrong One. ‘Do it yourself’. Yes, that’s it.
?—?Linus Torvalds

我們的第一個腳本

script.sh

#!/bin/bash
echo "My First Script!"

運行腳本

$ chmod 755 script.sh # chmod +x script.sh
$ ./script.sh
1__0bdtxxmb9dowmvsztf6za

好流弊??胯甩!你剛剛編寫了你的第一個bash腳本昧廷。
我知道你不理解這個腳本堪嫂,特別對于腳本中的第一行。不要擔心我將在本文中詳細介紹shell腳本木柬,在進入任何主題之前皆串,我總是建議在腦海中形成路線圖或適當?shù)膬?nèi)容索引,并明確我們將要學習的內(nèi)容眉枕。
因此愚战,以下是我們將在文章中討論的一些要點。

  • 腳本解釋器
  • 變量
  • 用戶輸入
  • 測試
  • 條件判斷
  • 循環(huán)語句
  • 腳本參數(shù)傳遞
  • 退出狀態(tài)碼
  • 邏輯操作符
  • 函數(shù)
  • 通配符
  • 調(diào)試

所以齐遵,這將是我們討論的順序寂玲,在本文的最后,我相信你會有足夠的信心編寫自己的shell腳本:)
Happy Learning Guys

1_5w2fofcvl5fdk7oydjgihg

腳本解釋器

你可以從上面腳本的第一行看到 #!/bin/bash 這行指定了你的程序?qū)⑹褂媚莻€解釋器梗摇,基本上是將路徑引用到解釋器拓哟。Linux/Unix中有很多解釋器,其中一些是:bash伶授,zsh断序,sh,csh和ksh等糜烹。

這里推薦一個玩命令行必須知道的一個開源項目oh-my-zsh

0_gp--jderqene-ood

All the best people in life seem to like LINUX.?—?Steve Wozniak

查看你的系統(tǒng)中有那些腳本解釋器

cat /etc/shells

bash: #!/bin/bash
zsh: #!/bin/zsh
ksh: #!/bin/ksh
csh: #!/bin/csh
and so on…

注意??
如果腳本不包含解釋器违诗,則使用你的默認shell執(zhí)行命令,因此代碼可能正常運行疮蹦,雖然是這樣诸迟,但是不推薦這樣做,使用echo $SHELL可以知道你當前使用的解釋器

注釋
注釋以#開始愕乎,#后面的內(nèi)容會被解釋器忽略阵苇,但是#!另當別論

變量
變量指向內(nèi)存中的一塊區(qū)域,變量有對應的變量名和值感论,可以存儲一些可以在將來更改的數(shù)據(jù)绅项,shell中定義變量不需要指定變量的類型

VARIABLE_NAME="Value"

當命名一個變量是你必須記得以下幾點

  • 變量名是區(qū)分大小寫的
  • 為了方便,變量名最好大寫
  • 要使用變量比肄,必須在變量前面加$符號

例子??

#!/bin/bash
MY_NAME="shellhub"
echo "Hello, I am $MY_NAME"

OR

#!/bin/bash
MY_NAME="shellhub"
echo "Hello, I am ${MY_NAME}"

提示: 可以把命令執(zhí)行后的輸入結果賦值給一個變量

LIST=$(ls)
SERVER_NAME=$(hostname)
0_as7e7vxyi4ruobdb

合法的變量名

THIS3VARIABLE=”ABC”
THIS_IS_VARIABLE=”ABC”
thisIsVariable=”ABC”

不合法的變量名

4Number=”NUM”
This-Is-Var=”VAR”
# No special character apart from underscore is allowed!

用戶輸入

read 命令接收鍵盤的輸入快耿,標準輸入(Standard Input)

read -p "PROMPT MESSAGE" VARIABLE

其中PROMPT MESSAGE為提示用戶的信息,變量VARIABLE可以保存用戶的輸入芳绩,可以在程序中使用該變量

#!/bin/bash
read -p "Please Enter You Name: " NAME
echo "Your Name Is: $NAME"

測試

測試主要用于條件判斷掀亥。[ condition-to-test-for ] ,如[ -e /etc/passwd ]示括,注意的是[]前后必須有空格铺浇,如[-e /etc/passwd]是錯誤的寫法

  1. 文件測試操作
-d FILE_NAM  # True if FILE_NAM is a directory
-e FILE_NAM  # True if FILE_NAM exists
-f FILE_NAM  # True if FILE_NAM exists and is a regular file
-r FILE_NAM  # True if FILE_NAM is readable
-s FILE_NAM  # True if FILE_NAM exists and is not empty
-w FILE_NAM  # True if FILE_NAM has write permission
-x FILE_NAM  # True if FILE_NAM is executable
  1. 字符串測試操作
-z STRING  # True if STRING is empty
-n STRING  # True if STRING is not empty
STRING1 = STRIN2 # True if strings are equal
STRING1 != STRIN2 # True if strings are not equal
  1. 算術測試操作
var1 -eq var2  # True if var1 is equal to var2
var1 -ne var2  # True if var1 not equal to var2
var1 -lt var2  # True if var1 is less than var2
var1 -le var2  # True if var1 is less than or equal to var2
var1 -gt var2  # True if var1 is greater than var2
var1 -ge var2  # True if var1 is greater than or equal to var2

條件判斷

和其他編程語言一樣,shell腳本也能基于條件進行判斷垛膝,我們可以使用if-elseif-elif-else

0_lk05kvg-mx5did9l

Avoid the Gates of Hell. Use Linux!

  1. if 語句
if [ condition-is-true ]
then
  command 1
  command 2
    ...
    ...
  command N
fi

if-else

if [ condition-is-true ]
then
  command 1
elif [ condition-is-true ]
then
  command 2
elif [ condition-is-true ]
then
  command 3
else
  command 4
fi
  1. case語句
    case可以實現(xiàn)和if一樣的功能鳍侣,但是當條件判斷很多的時候,使用if不太方便吼拥,比如使用if進行值的比較
case "$VAR" in
  pattern_1)
    # commands when $VAR matches pattern 1
    ;;
  pattern_2)
    # commands when $VAR matches pattern 2
    ;;
  *)
    # This will run if $VAR doesnt match any of the given patterns
    ;;
esac

例子??

#!/bin/bash
read -p "Enter the answer in Y/N: " ANSWER
case "$ANSWER" in
  [yY] | [yY][eE][sS])
    echo "The Answer is Yes :)"
    ;;
  [nN] | [nN][oO])
    echo "The Answer is No :("
    ;;
  *)
    echo "Invalid Answer :/"
    ;;
esac

迭代語句 - 循環(huán)

可以通過循環(huán)執(zhí)行同一個代碼塊很多次

  1. for循環(huán)
for VARIABLE_NAME in ITEM_1 ITEM_N
do
  command 1
  command 2
    ...
    ...
  command N
done

Example

#!/bin/bash
COLORS="red green blue"
for COLOR in $COLORS
do
  echo "The Color is: ${COLOR}"
done

Another Example

for (( VAR=1;VAR<N;VAR++ ))
do
  command 1
  command 2
    ...
    ...
  command N
done

在當前所有txt文件前面追加new實現(xiàn)重命名

#!/bin/bash
FILES=$(ls *txt)
NEW="new"
for FILE in $FILES
do
  echo "Renaming $FILE to new-$FILE"
  mv $FILE $NEW-$FILE
done
  1. while 循環(huán)
    當所給的條件為true時倚聚,循環(huán)執(zhí)行while里面的代碼塊
while [ CONNDITION_IS_TRUE ]
do
  # Commands will change he entry condition
  command 1
  command 2
    ...
    ...
  command N
done

判斷條件可以是任意的測試或者命令,如果測試或命令返回0凿可,則表示條件成立惑折,如果為非0則退出循環(huán),如果一開始條件就不成立枯跑,則循環(huán)永遠不會執(zhí)行惨驶。
如果你不知道退出狀態(tài)碼是什么請不要擔心,我后面會告訴你 :)

0_rs8u95tcmwukmaqm

例子 一行一行讀取文件內(nèi)容

#!/bin/bash
LINE=1
while read CURRENT_LINE
do
  echo "${LINE}: $CURRENT_LINE"
  ((LINE++))
done < /etc/passwd
# This script loops through the file /etc/passwd line by line

注意??
continue 用于結束本次循環(huán)
break 用于結束整個循環(huán)

參數(shù)傳遞

當我們運行腳本的時候敛助,可以傳遞參數(shù)供腳本內(nèi)部使用$ ./script.sh param1 param2 param3 param4
這些參數(shù)將被存儲在特殊的變量中

$0 -- "script.sh"
$1 -- "param1"
$2 -- "param2"
$3 -- "param3"
$4 -- "param4"
$@ -- array of all positional parameters

這些變量可以在腳本中的任何地方使用粗卜,就像其他全局變量一樣

退出狀態(tài)碼

任何一個命令執(zhí)行完成后都會產(chǎn)生一個退出狀態(tài)碼,范圍0-255纳击,狀態(tài)碼可以用來檢查錯誤

  • 0 表示正確執(zhí)行并正常退出
  • 非0表示執(zhí)行過程中出錯续扔,沒有正常退出

上一條命令執(zhí)行后的退出狀態(tài)碼被保存在變量$?

例子 使用ping檢查主機和服務器之間是否可以抵達

#!/bin/bash
HOST="google.com"
ping -c 1 $HOST     # -c is used for count, it will send the request, number of times mentioned
RETURN_CODE=$?
if [ "$RETURN_CODE" -eq "0" ]
then
  echo "$HOST reachable"
else
  echo "$HOST unreachable"
fi

自定義退出狀態(tài)碼
默認的狀態(tài)碼是上一條命令執(zhí)行的結果,我們可以通過exit來自定義狀態(tài)碼

exit 0
exit 1
exit 2
  ...
  ...
exit 255

邏輯操作符

shell腳本支持邏輯與和邏輯或
邏輯與 &&
邏輯或 ||

Example
mkdir tempDir && cd tempDir && mkdir subTempDir
這個例子中焕数,如果創(chuàng)建tempDir成功纱昧,執(zhí)行后面的cd,繼續(xù)創(chuàng)建subTempDir

函數(shù)

可以把一些列的命令或語句定義在一個函數(shù)內(nèi)堡赔,從程序的其他地方調(diào)用

0_a9vgsszcprsdt9hx

注意??

  • 函數(shù)包含了一些列你要重復調(diào)用的指令(函數(shù)必須先定義后調(diào)用)
  • 把函數(shù)定義在程序開始或主程序之前是一個最佳實踐

語法

function function_name() {
    command 1
    command 2
    command 3
      ...
      ...
    command N
}

調(diào)用函數(shù) 簡單的給出函數(shù)名字

#!/bin/bash
function myFunc () {
    echo "Shell Scripting Is Fun!"
}
myFunc # call

函數(shù)參數(shù)傳遞

和腳本一樣识脆,也可以給函數(shù)傳遞參數(shù)完成特殊的任務,第一個參數(shù)存儲在變量$1中善已,第二個參數(shù)存儲在變量$2中...存璃,$@存儲所有的參數(shù),參數(shù)之間使用空格分割 myFunc param1 param2 param3 ...

變量的作用范圍

全局變量: 默認情況下雕拼,shell中的變量都定義為全局變量纵东,你可以從腳本中的任何位置使用變量,但是變量在使用之前必須先定義
本地變量: 本地變量只能在方法內(nèi)部訪問啥寇,可以通過local關鍵詞定義一個本地變量偎球,定義一個本地變量的最佳實踐是在函數(shù)內(nèi)部

通配符

使用通配符可以完成特定的匹配
一些常用的通配符
* 可以通配一個或多個任意字符

*.txt
hello.*
great*.md

?匹配一個字符

?.md
Hello?

[]匹配括號內(nèi)部的任意一個字符

He[loym], [AIEOU]

[!]不匹配括號內(nèi)的任何字符

`[!aeiou]`

預先定義的通配符

  • [[:alpha:]]
  • [[:alnum:]]
  • [[:space:]]
  • [[:upper:]]]
  • [[:lower:]]
  • [[:digit:]]

匹配通配符 有些情況下我們想匹配*?等特殊字符,可以使用轉義字符
\*
\?

調(diào)試

0_tkeark2bzm7xxvsb

bash提供一些可選項幫助你調(diào)試程序
Some Options:

  1. -x option
    它在執(zhí)行時打印命令和參數(shù)辑甜。它被稱為打印調(diào)試衰絮,跟蹤或x跟蹤。我們可以通過修改第一行來使用它
  2. -e option
    它代表“出錯”磷醋。如果命令以非零退出狀態(tài)退出猫牡,這將導致腳本立即退出。
  3. -v option
    它在讀取時打印shell命令/輸入行邓线。

注意:這些選項可以組合使用淌友,一次可以使用多個選項煌恢!

#!/bin/bash-xe
#!/bin/bash-ex
#!/bin/bash-x-e
#!/bin/bash-e-x

盡管有許多工具可用于幫助調(diào)試,但只有在了解其工作原理的情況下才能調(diào)試代碼震庭。所以瑰抵,確保花足夠的時間實際練習編寫腳本并自己調(diào)試它們器联,這樣你就可以知道你可以犯錯誤的地方二汛,這樣你就不會再這樣做:)

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拨拓,隨后出現(xiàn)的幾起案子肴颊,更是在濱河造成了極大的恐慌,老刑警劉巖渣磷,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婿着,死亡現(xiàn)場離奇詭異,居然都是意外死亡幸海,警方通過查閱死者的電腦和手機祟身,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來物独,“玉大人袜硫,你說我怎么就攤上這事〉猜ǎ” “怎么了婉陷?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長官研。 經(jīng)常有香客問我秽澳,道長,這世上最難降的妖魔是什么戏羽? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任担神,我火速辦了婚禮,結果婚禮上始花,老公的妹妹穿的比我還像新娘妄讯。我一直安慰自己,他們只是感情好酷宵,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布亥贸。 她就那樣靜靜地躺著,像睡著了一般浇垦。 火紅的嫁衣襯著肌膚如雪炕置。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音朴摊,去河邊找鬼默垄。 笑死,一個胖子當著我的面吹牛仍劈,可吹牛的內(nèi)容都是我干的厕倍。 我是一名探鬼主播寡壮,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贩疙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了况既?” 一聲冷哼從身側響起这溅,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎棒仍,沒想到半個月后悲靴,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡莫其,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年癞尚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片乱陡。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡浇揩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出憨颠,到底是詐尸還是另有隱情辟癌,我是刑警寧澤盹愚,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響智绸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜昵观,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一蜂奸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧嚷节,春花似錦聂儒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至碍论,卻和暖如春谅猾,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工税娜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留坐搔,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓敬矩,卻偏偏與公主長得像概行,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子弧岳,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容