Shell——你只需要瞭解這麼多

一.Shell簡介

Shell是一個用C語言編寫的程序,通過Shell用戶可以訪問操作系統內核服務,類似於DOS下的command和後來的cmd.exe。Shell既是一種命令語言,又是一種程序設計語言。作爲命令語言,它交互式地解釋和執行用戶輸入的命令;作爲程序設計語言,它定義了各種變量、參數、函數、流程控制等等。它調用了系統核心的大部分功能來執行程序、建立文件並以並行的方式協調各個程序的運行。因此,對於用戶來說,shell是最重要的實用程序,深入瞭解和熟練掌握shell的特性極其使用方法,是用好Unix/Linux系統的關鍵。

二.兩類程序設計語言

我經常說道shell腳本,其實是因爲Shell是一種腳本語言,也就是解釋性語言。程序設計語言可以分爲兩類:編譯型語言和解釋型語言。

語言 區別
編譯型語言 需要預先將我們寫好的源代碼轉換成目標代碼,這個過程被稱作“編譯”。運行程序時,直接讀取目標代碼。由於編譯後的目標代碼非常接近計算機底層,因此執行效率很高,這是編譯型語言的優點
解釋型語言 也叫做腳本語言。執行這類程序時,解釋器需要讀取我們編寫的源代碼,並將其轉換成目標代碼,再由計算機運行。因爲每次執行程序都多了編譯的過程,因此效率有所下降

三.Shell腳本解釋器

Linux的Shell腳本解釋器種類衆多,一個系統可以存在多個shell腳本解釋器,可以通過cat /etc/shells 命令查看系統中安裝的shell腳本解釋器。

[root@centos6-1 ~]# cat /etc/shells 
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
[root@centos6-1 ~]# 

bash由於易用和免費,在日常工作中被廣泛使用。同時,Bash也是大多數Linux系統默認的Shell腳本解釋器。

四.Hello World

新建helloworld.sh

[root@centos6-1 ~]# touch helloworld.sh

編輯helloworld.sh文件,添入一下內容

#!/bin/bash
echo "helloworld"
  • #! 是一個約定的標記,它告訴系統這個腳本需要什麼解釋器來執行,即使用哪一種Shell,這裏指定bash
  • echo 是Shell的一個內部指令,用於在屏幕上打印出指定的字符串

賦予當前用戶helloworld.sh的執行權限(剛創建的文件沒有執行權限)

[root@centos6-1 ~]# chmod u+x helloworld.sh

執行hellowo.sh腳本方式一

[root@centos6-1 ~]# ./helloworld.sh 
helloworld
[root@centos6-1 ~]# 

注意,一定要寫成./helloworld.sh,而不是helloworld.sh,linux系統會去PATH裏尋找有沒有叫helloworld.sh的,而helloworld.sh不在PATH裏,所以寫成helloworld.sh是會找不到命令的,要用./helloworld.sh告訴系統說,就在當前目錄找。
執行hellowo.sh腳本方式二

[root@centos6-1 ~]# /bin/sh helloworld.sh 
helloworld
[root@centos6-1 ~]# 

這種運行方式是,直接運行解釋器,其參數就是shell腳本的文件名,當使用這種方式時,腳本中的#!/bin/bash指定的解釋器是不生效的,當前使用什麼解釋器就是什麼解釋器

五.變量

  • 語法格式:變量名=變量值

shell變量定義的嚴格語法限制:

1. 變量名和等號之間不能有空格
2. 變量名首個字符必須爲英文字母
3. 不能包含標點符號但能夠使用下劃線(_)
4. 不能使用空格
5. 不能使用 bash 裏的關鍵字

1.變量類型

類型 解釋
局部變量 局部變量在腳本或命令中定義,僅在當前shell實例中有效,其他shell啓動的程序不能訪問局部變量
環境變量 所有的程序,包括shell啓動的程序,都能訪問環境變量,有些程 序需要環境變量來保證其正常運行。可以用過set命令查看當前環境變量
shell變量 由shell程序設置的特殊變量。shell變量中有一部分是環境變量,有一部分是局部變量,這些變量保證了shell 的正常運行

2.定義變量

name="zaomianbao"

3.引用變量

name="zaomianbao"
echo ${name}
echo $name

引用一個定義過的變量,只要在變量名前面加$即可,變量名外面的花括號是可選的,加不加都行,加花括號是爲了幫助解釋器識別變量的邊界。

4.重新定義變量

已定義的變量,可以被重新定義

name="zaomianbao"
echo ${name}
name="tiechui"
echo ${name}

5.只讀變量

使用readonly命令可以將變量定義爲只讀變量,只讀變量的值不能被改變

name="zaomianbao"
readonly name
name="tiechui"

6.刪除變量

name="zaomianbao"
unset name
echo $name

使用unset命令可以刪除變量,變量被刪除後不能再次使用,同時unset命令不能刪除只讀變量。

六.參數傳遞

在執行Shell腳本時,可以向腳本傳遞參數。腳本內獲取參數的格式爲:$n。n代表一個數字,1爲執行腳本的第一個參數,2爲執行腳本的第二個參數,以此類推…
$0 表示當前腳本名稱。

1.修改helloworld.sh爲

#!/bin/bash
echo $1
echo $2
echo $3

2.執行攜帶參數

[root@centos6-1 ~]# ./helloworld.sh haha wowow nini
haha
wowow
nini
[root@centos6-1 ~]#

七.特殊字符

字符 意義
$# 傳遞到腳本的參數個數
$* 以一個單字符串顯示所有向腳本傳遞的參數
$$ 腳本運行的當前進程ID號
$! 後臺運行的最後一個進程的ID號
$@ 與$*相同,但是使用時加引號,並在引號中返回每個參數
$? 顯示最後命令的退出狀態。0表示沒有錯誤,其他任何值表明有錯誤

$*和$@區別:

  • 相同點:都表示傳遞給腳本的所有參數。
  • 不同點:不被" “包含時,$和$@都以$1 $2… $n 的形式組成參數列表。
    被" “包含時,”$
    ” 會將所有的參數作爲一個整體,以"$1 $2 … $n" 的形式組成一個整串;"$@" 會將各個參數分開,以"$1" “$2” … “$n” 的 形式組成一個參數列表。

八.Shell字符串

shell字符串可以用單引號,也可以用雙引號,也可以不用引號

單引號

name='my name is zaomianbao'
  • 單引號字符串中不支持引用變量,任何字符都會原樣輸出
  • 單引號字串中不能出現單引號(對單引號使用轉義符後也不行)

雙引號

name='my name is zaomianbao'
name_again="\"${name}\""
  • 雙引號裏可以引有變量
  • 雙引號裏支持轉義字符

字符串長度

name='my name is zaomianbao'
echo ${#name}   //執行輸出爲21

截取字符串

name='my name is zaomianbao'
echo ${name:11:20}   //執行輸出zaomianbao

九.shell數組

  • bash支持一維數組(不支持多維數組),並且沒有限定數組的大小。在Shell中,用括號來表示數組,數組元素用“空格”符號分割開。定義數組的一般形式爲:
      array_name=(value1 … valuen)

下面的例子將展示shell數組常見的所有操作

//第一數組
[root@centos6-1 ~]# usernames=(1 2 33 44 adsd1)
//默認讀取第一個
[root@centos6-1 ~]# echo ${usernames}
1
//讀取下標爲0的
[root@centos6-1 ~]# echo ${usernames[0]}
1
//讀取下標爲1的
[root@centos6-1 ~]# echo ${usernames[1]}
2
//讀取所有
[root@centos6-1 ~]# echo ${usernames[*]}
1 2 33 44 adsd1
//同樣是讀取所有
[root@centos6-1 ~]# echo ${usernames[@]}
1 2 33 44 adsd1
//獲取數組長度
[root@centos6-1 ~]# echo ${#usernames[@]}
5
//同樣可以獲取數組長度
[root@centos6-1 ~]# echo ${#usernames[*]}
5
[root@centos6-1 ~]# 

十.shell運算符

  • Shell和其他編程語音一樣,支持包括:算術、關係、布爾、字符串等運算符。
  • 原生bash不支持簡單的數學運算,但是可以通過其他命令來實現,例如 awk 和 expr,expr 最常用。expr 是一款表達式計算工具,使用它能完成表達式的求值操作。

1.算術運算符

運算符 意義
+ 加法
- 減法
* 乘法
/ 除法
% 模,即取餘

下面是詳細例子

#!/bin/bash

a=10
b=20

val=`expr $a + $b`
echo "a + b : $val"

val=`expr $a - $b`
echo "a - b : $val"

val=`expr $a \* $b`
echo "a * b : $val"

val=`expr $b / $a`
echo "b / a : $val"

val=`expr $b % $a`
echo "b % a : $val"

if [ $a == $b ]
then
   echo "a 等於 b"
fi
if [ $a != $b ]
then
   echo "a 不等於 b"
fi

執行

[root@centos6-1 ~]# ./helloworld.sh 
a + b : 30
a - b : -10
a * b : 200
b / a : 2
b % a : 0
a 不等於 b
[root@centos6-1 ~]# 

注意:

-  1.乘號(*)前邊必須加反斜槓(\)
-  2.條件表達式要放在方括號之間,並且要有空格

2.關係運算符

關係運算符只支持數字,不支持字符串,除非字符串的值是數字

運算符 意義
-eq EQUAL等於
-ne NOT EQUAL不等於
-gt GREATER THAN大於
-lt LESS THAN小於
-ge GREATER THAN OR EQUAL 大於等於
-le LESS THAN OR EQUAL 小於等

下面是詳細例子

#!/bin/bash

a=10
b=20

if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等於 b"
else
   echo "$a -eq $b: a 不等於 b"
fi
if [ $a -ne $b ]
then
   echo "$a -ne $b: a 不等於 b"
else
   echo "$a -ne $b : a 等於 b"
fi
if [ $a -gt $b ]
then
   echo "$a -gt $b: a 大於 b"
else
   echo "$a -gt $b: a 不大於 b"
fi
if [ $a -lt $b ]
then
   echo "$a -lt $b: a 小於 b"
else
   echo "$a -lt $b: a 不小於 b"
fi
if [ $a -ge $b ]
then
   echo "$a -ge $b: a 大於或等於 b"
else
   echo "$a -ge $b: a 小於 b"
fi
if [ $a -le $b ]
then
   echo "$a -le $b: a 小於或等於 b"
else
   echo "$a -le $b: a 大於 b"
fi

執行

[root@centos6-1 ~]# ./helloworld.sh  
10 -eq 20: a 不等於 b
10 -ne 20: a 不等於 b
10 -gt 20: a 不大於 b
10 -lt 20: a 小於 b
10 -ge 20: a 小於 b
10 -le 20: a 小於或等於 b
[root@centos6-1 ~]# 

3.布爾運算符

運算符 意義
&&
||

下面是詳細例子

#!/bin/bash

a=10
b=20

if [[ $a -lt 100 && $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi

if [[ $a -lt 100 || $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi

執行

[root@centos6-1 ~]# ./helloworld.sh 
返回 false
返回 true
[root@centos6-1 ~]# 

4.字符串運算符

操作符 意義
-z 字符串長度是否爲0,爲0返回 true
-n 字符串長度是否爲0,不爲0返回 true
str 字符串是否爲空,不爲空返回 true

下面是詳細例子

#!/bin/bash

a="abc"
b="efg"

if [ $a = $b ]
then
   echo "$a = $b : a 等於 b"
else
   echo "$a = $b: a 不等於 b"
fi
if [ $a != $b ]
then
   echo "$a != $b : a 不等於 b"
else
   echo "$a != $b: a 等於 b"
fi
if [ -z $a ]
then
   echo "-z $a : 字符串長度爲 0"
else
   echo "-z $a : 字符串長度不爲 0"
fi
if [ -n $a ]
then
   echo "-n $a : 字符串長度不爲 0"
else
   echo "-n $a : 字符串長度爲 0"
fi
if [ $a ]
then
   echo "$a : 字符串不爲空"
else
   echo "$a : 字符串爲空"
fi

執行

[root@centos6-1 ~]# ./helloworld.sh 
abc = efg: a 不等於 b
abc != efg : a 不等於 b
-z abc : 字符串長度不爲 0
-n abc : 字符串長度不爲 0
abc : 字符串不爲空
[root@centos6-1 ~]# 

5.文件測試運算符

操作符 意義
-b file 文件是否是塊設備文件,如果是,則返回 true
-c file 文件是否是字符設備文件,如果是,則返回 true
-d file 是否是目錄,如果是,則返回 true
-f file 文件是否是普通文件(既不是目錄,也不是設備文件),如果是,則返回 true。
-g file 文件是否設置了 SGID 位,如果是,則返回 true
-k file 文件是否設置了粘着位(Sticky Bit),如果是,則返回 true
-p file 文件是否是具名管道,如果是,則返回 true
-u file 文件是否設置了 SUID 位,如果是,則返回 true
-r file 文件是否可讀,如果是,則返回 true
-w file 文件是否可寫,如果是,則返回 true
-x file 文件是否可執行,如果是,則返回 true
-s file 文件是否爲空(文件大小是否大於0),不爲空返回 true
-e file 文件(包括目錄)是否存在,如果是,則返回 true

下面是詳細例子

#!/bin/bash

file="/com/zaomianbao"
if [ -r $file ]
then
   echo "文件可讀"
else
   echo "文件不可讀"
fi
if [ -w $file ]
then
   echo "文件可寫"
else
   echo "文件不可寫"
fi
if [ -x $file ]
then
   echo "文件可執行"
else
   echo "文件不可執行"
fi
if [ -f $file ]
then
   echo "文件爲普通文件"
else
   echo "文件爲特殊文件"
fi
if [ -d $file ]
then
   echo "文件是個目錄"
else
   echo "文件不是個目錄"
fi
if [ -s $file ]
then
   echo "文件不爲空"
else
   echo "文件爲空"
fi
if [ -e $file ]
then
   echo "文件存在"
else
   echo "文件不存在"
fi

執行

[root@centos6-1 ~]# ./helloworld.sh 
文件不可讀
文件不可寫
文件不可執行
文件爲特殊文件
文件不是個目錄
文件爲空
文件不存在
[root@centos6-1 ~]# 

十一.流程控制

1.if-else


if condition
then
    //做你想做的事
else
    //做你想做的事
fi


if condition1
then
    //做你想做的事
elif condition2 
then 
    //做你想做的事
else
    //做你想做的事
fi

2.case

case 語句匹配一個值或一個模式,如果匹配成功,執行相匹配的命令

case 值 in
模式1)
    //做你想做的事
    ;;
模式2)
    //做你想做的事
    ;;
*)
    //做你想做的事
    ;;
esac

取值後面必須爲關鍵字 in,每一模式必須以右括號結束。取值可以爲變量或常數。匹配發現取值符合某一模式後,其間所有命令開始執行直至 ;;。;; 與其他語言中的 break 類似,意思是跳到整個 case 語句的最後。取值將檢測匹配的每一個模式。一旦模式匹配,則執行完匹配模式相應命令後不再繼續其他模式。如果無一匹配模式,使用星號 * 捕獲該值,再執行後面的命令。

3.for

for 變量 in 列表
do
    //做你想做的事
done

4.while

while command
do
   //做你想做的是
done

5.until

until 循環執行一系列命令直至條件爲 true 時停止。until 循環與 while 循環在處理方式上剛好相反。一般while循環優於until循環,但在某些時候,也只是極少數情況下,until 循環更加有用。

until command
do
   //做你想做的事
done

command 一般爲條件表達式,如果返回值爲 false,則繼續執行循環體內的語句,否則跳出循環。

十二.函數

函數可以讓我們將一個複雜功能劃分成若干模塊,讓程序結構更加清晰,代碼重複利用率更高。像其他編程語言一樣,Shell 也支持函數。Shell 函數必須先定義後使用。

#!/bin/bash

demoFun(){
    echo "這是我的第一個 shell 函數!"
}
echo "-----函數開始執行-----"
demoFun 
echo "-----函數執行完畢-----"

執行

[root@centos6-1 ~]# ./helloworld.sh 
-----函數開始執行-----
這是我的第一個 shell 函數!
-----函數執行完畢-----
[root@centos6-1 ~]# 

如果函數有返回值,則函數返回值可以在調用該函數後通過 $? 來獲得。

參考資料:
https://baike.baidu.com/item/shell/99702?fr=aladdin
http://www.runoob.com/linux/linux-shell.html
https://www.cnblogs.com/maybe2030/p/5022595.html
https://baike.baidu.com/item/POSIX/3792413?fr=aladdin

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章