掌握Shell程式設計,一篇就夠了

語言: CN / TW / HK

沒想到收藏數這麼高,文末更新一波福利,友情提示:很乾,錯過就真是你的問題了。

本文首先介紹了 Shell 程式設計是什麼,並帶大家快速入門,隨後講解 Shell 的基本語法並結合案例重點分析用法。包括 Shell 流程控制和自定義函式等。建議收藏。
誰需要學習 Shell 程式設計?

  1. Linux運維工程師:編寫Shell程式進行服務叢集管理。
  2. Python和JavaEE程式設計師:編寫Shell指令碼程式或者是伺服器的維護,比如編寫一個定時備份資料庫的指令碼。
  3. 大資料程式設計師:編寫Shell程式來管理叢集。

Shell 是什麼?
Shell 是一個命令解釋權,它為使用者提供了一個向 Linux 核心傳送請求以便執行程式介面系統級程式,使用者可以用 Shell 來啟動、掛起、停止甚至是編寫一些程式。


Shell 程式設計快速入門
進入 Linux 終端,編寫一個 Shell 指令碼 hello.sh :

#!/bin/bash 
echo 'hello world!'


執行:

# 方法1 
sh hello.sh  

# 方法2 
chmod +x hello.sh 
./hello.sh


終端打印出 hello world! 
說明:

  • #! 告訴系統這個指令碼需要什麼直譯器來執行。
  • 副檔名 .sh 不是強制要求的。
  • 方法1 直接執行直譯器,hello.sh 作為 Shell 直譯器的引數。此時 Shell 指令碼就不需要指定直譯器資訊,第一行可以去掉。
  • 方法2 hello.sh 作為可執行程式執行,Shell 指令碼第一行一定要指定直譯器。

Shell 變數
定義
Shell 變數分為系統變數自定義變數。系統變數有$HOME、$PWD、$USER等,顯示當前 Shell 中所有變數:set 
變數名可以由字母、數字、下劃線組成,不能以數字開頭。
基本語法

  • 定義變數:變數名=變數值,等號兩側不能有空格,變數名一般習慣用大寫。
  • 刪除變數:unset 變數名 。
  • 宣告靜態變數:readonly 變數名,靜態變數不能unset。
  • 使用變數:$變數名

將命令返回值賦給變數(重點)

  • A=`ls` 反引號,執行裡面的命令
  • A=$(ls) 等價於反引號

Shell 環境變數
定義


基本語法

  1. export 變數名=變數值,將 Shell 變數輸出為環境變數。
  2. source 配置檔案路徑,讓修改後的配置資訊立即生效。
  3. echo $變數名,檢查環境變數是否生效

位置引數變數
基本語法

  • $n :$0 代表命令本身、$1-$9 代表第1到9個引數,10以上引數用花括號,如 ${10}。
  • $* :命令列中所有引數,且把所有引數看成一個整體。
  • [email protected] :命令列中所有引數,且把每個引數區分對待。
  • $# :所有引數個數。

例項:
編寫 Shell 指令碼 positionPara.sh ,輸出命令列輸入的各個引數資訊。

#!/bin/bash     
# 輸出各個引數 
echo $0 $1 $2 
echo $* 
echo [email protected] 
echo 引數個數=$#


執行:

chmod +x positionPara.sh 
./positionPara.sh 10 20


執行結果:

./positionPara.sh 10 20 
10 20 
10 20 
引數個數=2


預定義變數
定義
在賦值定義之前,事先在 Shell 指令碼中直接引用的變數。
基本語法

  • $$ :當前程序的 PID 程序號。
  • $! :後臺執行的最後一個程序的 PID 程序號。
  • $? :最後一次執行的命令的返回狀態,0為執行正確,非0執行失敗。

例項:
編寫 Shell 指令碼 prePara.sh ,輸出命令列輸入的各個引數資訊。

#!/bin/bash     
echo 當前的程序號=$$ 
# &:以後臺的方式執行程式 
./hello.sh & 
echo 最後一個程序的程序號=$! 
echo 最後執行的命令結果=$?


執行結果:

當前的程序號=41752 
最後一個程序的程序號=41753 
最後執行的命令結果=0 # hello world!


運算子
基本語法

  • $((運算式)) 或 $[運算式]
  • expr m + n 注意 expr 運算子間要有空格
  • expr m - n
  • expr \*,/,% 分別代表乘,除,取餘

例項

# 第1種方式 $(()) 
echo $(((2+3)*4))   

# 第2種方式 $[],推薦 
echo $[(2+3)*4]  

# 使用 expr 
TEMP=`expr 2 + 3` 
echo `expr $TEMP \* 4`


條件判斷
基本語法
[ condition ] 注意condition前後要有空格。非空返回0,0為 true,否則為 false 。
例項

#!/bin/bash 
if [ 'test01' = 'test' ] 
then
     echo '等於' 
fi  

# 20是否大於10 
if [ 20 -gt 10] 
then
     echo '大於' 
fi  

# 是否存在檔案/root/shell/a.txt 
if [ -e /root/shell/a.txt ] 
then
     echo '存在' 
fi  

if [ 'test02' = 'test02' ] && echo 'hello' || echo 'world' 
then
     echo '條件滿足,執行後面的語句' 
fi


執行結果:

大於 
hello 
條件滿足,執行後面的語句

流程控制

if 判斷

基本語法

if [ 條件判斷式 ];then   
    程式   
fi

# 或者(推薦)
if [ 條件判斷式 ]
then
    程式
elif [ 條件判斷式 ]
then
    程式
fi

例項

編寫 Shell 程式:如果輸入的引數大於60,輸出“及格”,否則輸出“不及格”。

#!/bin/bash
if [ $1 -ge 60 ]
then
    echo 及格
elif [ $1 -lt 60 ]
then
    echo "不及格" 
fi

case 分支

基本語法

case $變數名 in
"值1")
如果變數值等於值1,則執行此處程式1
;;
"值2")
如果變數值等於值2,則執行此處程式2
;;
...省略其它分支...
*)
如果變數值不等於以上列出的值,則執行此處程式
;;
esac

例項

當命令列引數為1時輸出“週一”,2時輸出“週二”,其他情況輸出“其它”。

case $1 in
"1")
echo 週一
;;
"2")
echo 週二
;;
*)
echo 其它
;;
esac

for 迴圈

基本語法

# 語法1
for 變數名 in 值1 值2 值3...
do
    程式
done

# 語法2
for ((初始值;迴圈控制條件;變數變化))
do
    程式
done

例項

  1. 列印命令列輸入的引數。
#!/bin/bash  

# 使用$* 
for i in "$*" 
do     
    echo "the arg is $i" 
done 
echo "=================="  

# 使用[email protected] 
for j in "[email protected]" 
do     
    echo "the arg is $j" 
done

執行結果(回顧一下 $* 和 [email protected] 的區別):

the arg is 1 2 3 
================== 
the arg is 1 
the arg is 2 
the arg is 3

2. 輸出從1加到100的值。

#!/bin/bash 
SUM=0  
for ((i=1;i<=100;i++)) 
do     
    SUM=$[$SUM+$i] 
done 

echo $SUM

while 迴圈

基本語法

while [ 條件判斷式 ]
do
    程式
done 

例項

輸出從1加到100的值。

#!/bin/bash
SUM=0
i=0

while [ $i -le $1 ]
do
    SUM=$[$SUM+$i]
    i=$[$i+1]
done       
echo $SUM

讀取控制檯輸入

基本語法

read(選項)(引數)
選項

  • -p:指定讀取值時的提示符
  • -t:指定讀取值時等待的時間(秒),如果沒有在指定時間內輸入,就不再等待了。

引數

  • 變數名:讀取值的變數名

例項

讀取控制檯輸入一個num值。

#!/bin/bash

read -p "請輸入一個數num1=" NUM1
echo "你輸入num1的值是:$NUM1"

read -t 10 -p "請在10秒內輸入一個數num2=" NUM2
echo "你輸入num2的值是:$NUM2"

執行結果:

請輸入一個數num1=10
你輸入num1的值是:10
請在10秒內輸入一個數num2=20
你輸入num2的值是:20

函式

和其它程式語言一樣,Shell 程式設計有系統函式和自定義函式,本文只舉兩個常用系統函式。

系統函式

  • basename,刪掉路徑最後一個 / 前的所有部分(包括/),常用於獲取檔名。
    基本語法
    • basename [pathname] [suffix]
    • basename [string] [suffix]
    • 如果指定 suffix,也會刪掉pathname或string的字尾部分。

例項

# basename /usr/bin/sort  
sort  

# basename include/stdio.h  
stdio.h  

# basename include/stdio.h .h 
stdio
  • dirname,刪掉路徑最後一個 / 後的所有部分(包括/),常用於獲取檔案路徑。
    基本語法
    • dirname pathname
    • 如果路徑中不含 / ,則返回 '.' (當前路徑)。

例項

# dirname /usr/bin/  
/usr  

# dirname dir1/str dir2/str 
dir1 
dir2  

# dirname stdio.h 
.

自定義函式

基本語法

[ function ] funname[()]
{
    Action;
    [return int;]
}

# 呼叫
funname 引數1 引數2...

例項

計算輸入兩個引數的和。

#!/bin/bash

function getSum(){
    SUM=$[$n1+$n2]
    echo "sum=$SUM"
}   

read -p "請輸入第一個引數n1:" n1
read -p "請輸入第二個引數n2:" n2

# 呼叫 getSum 函式
getSum $n1 $n2

恭喜!你已經掌握了 Shell 的基本語法,入門很簡單。想要更系統的探索Shell程式設計,可以和我一起深入學習接下來的高階篇。老樣子,向大家推薦一本最值得購入和收藏的程式設計師必讀好書:

《深入理解計算機系統》屬於聖經級別的眾多國內外名校教材(北大清華上海交大,國外簡直更多了),罕見的豆瓣評分9.5,也是我最喜歡的專業書。讀過好幾遍了,不管是學生還是開發老手,這絕對是程式設計師最值得投資並且之後不會後悔的書,有點難,但很有用,想要電子版的也可以私信我,免費送你

如果本文對你有幫助,收藏完了也點個贊互相鼓勵一下吧~另外歡迎大家關注我的主頁,會不定期輸出有價值的內容。

更多幹貨

不看後悔系列:

Linux針對很多常用命令增加了很多新的更加有用高效的新命令,這些命令不但可以大大提高工作效率和體驗,讓你在同事面前裝那啥的利器,如果能在面試新工作時提起這類命令,更是能給面試官眼前一亮的加分項,下面展示了幾個在工作中最常用的命令。

  • 如果你想要有語法高亮的 cat,可以試試 ccat 命令。
  • exa 增強了 ls 命令,如果你需要在很多目錄上瀏覽各種檔案 ,ranger 命令可以比 cd  cat 更有效率,甚至可以在你的終端預覽圖片。
  • fd 是一個比 find 更簡單更快的命令,他還會自動地忽略掉一些你配置在 .gitignore 中的檔案,以及 .git 下的檔案。
  • fzf 會是一個很好用的檔案搜尋神器,其主要是搜尋當前目錄以下的檔案,還可以使用 fzf --preview 'cat {}'邊搜尋檔案邊瀏覽內容。
  • grep 是一個上古神器,然而,ackag  rg 是更好的grep,和上面的 fd一樣,在遞迴目錄匹配的時候,會使用你配置在 .gitignore 中的規則。
  • rm 是一個危險的命令,尤其是各種 rm -rf …,所以,trash 是一個更好的刪除命令。
  • man 命令是好讀文件的命令,但是man的文件有時候太長了,所以,你可以試試 tldr 命令,把文件上的一些示例整出來給你看。
  • 如果你想要一個圖示化的ping,你可以試試 prettyping 
  • 如果你想搜尋以前打過的命令,不要再用 Ctrl +R 了,你可以使用加強版的 hstr 
  • htop 是 top 的一個加強版。然而,還有很多的各式各樣的top,比如:用於看IO負載的 iotop,網路負載的 iftop, 以及把這些top都整合在一起的 atop
  • ncdu 比 du 好用多了。另一個選擇是 nnn
  • 如果你想把你的命令列操作錄製成一個 SVG 動圖,那麼你可以嘗試使用 asciinema  svg-trem 
  • httpie 是一個可以用來替代 curl  wget 的 http 客戶端,httpie 支援 json 和語法高亮,可以使用簡單的語法進行 http 訪問: http -v github.com
  • tmux 在需要經常登入遠端伺服器工作的時候會很有用,可以保持遠端登入的會話,還可以在一個視窗中檢視多個 shell 的狀態。
  • sshrc 是個神器,在你登入遠端伺服器的時候也能使用本機的 shell 的 rc 檔案中的配置。
  • goaccess 這個是一個輕量級的分析統計日誌檔案的工具,主要是分析各種各樣的 access log。