-Shell 教程 Bash 腳本 基礎語法 MD

Markdown版本筆記 個人GitHub首頁 個人博客 個人微信 個人郵箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

目錄

Shell 簡介

Shell 是一個用 C 語言編寫的程序,它是用戶使用 Linux 的橋樑。Shell 既是一種命令語言,又是一種程序設計語言linux

Shell 是指一種應用程序,這個應用程序提供了一個界面,用戶經過這個界面訪問操做系統內核的服務git

Ken Thompson 的 sh 是第一種 Unix Shell,Windows Explorer 是一個典型的圖形界面 Shellgithub

Shell 腳本

Shell 腳本(shell script),是一種爲 shell 編寫的腳本程序。shell

業界所說的 shell 一般都是指 shell 腳本,但讀者朋友要知道,shellshell script 是兩個不一樣的概念。編程

因爲習慣的緣由,簡潔起見,本文出現的 shell編程 都是指 shell 腳本編程,不是指開發 shell 自身。vim

Shell 環境

Shell 編程跟 JavaScript、php 編程同樣,只要有一個能編寫代碼的文本編輯器和一個能解釋執行腳本解釋器就能夠了。數組

Linux 的 Shell 種類衆多,常見的有:bash

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)

本教程關注的是 Bash,也就是 Bourne Again Shell,因爲易用和免費,Bash 在平常工做中被普遍使用。同時,Bash 也是大多數Linux 系統默認的 Shell微信

在通常狀況下,人們並不區分 Bourne ShellBourne Again Shell,因此,像 #!/bin/sh,它一樣也能夠改成 #!/bin/bash

#! 用於告訴系統其後路徑所指定的程序便是解釋此腳本文件的 Shell 程序。

第一個shell腳本

打開文本編輯器(可使用 vi/vim 命令來建立文件),新建一個文件 test.sh,擴展名爲 sh(sh表明shell),擴展名並不影響腳本執行,見名知意就好,若是你用 php 寫 shell 腳本,擴展名就用 php 好了。

輸入一些代碼,第一行通常是這樣:

實例

#!/bin/bash
# 使用哪種 Shell,能夠省略。不能在 #! 的行末添加註釋
echo "Hello World !" # 向窗口輸出文本
  • #! 是一個約定的標記,它告訴系統這個腳本須要什麼解釋器來執行,即便用哪種 Shell。這一行通常也是能夠省略的。
  • echo 命令用於向窗口輸出文本。

運行 Shell 腳本有兩種方法:

一、做爲可執行程序

將上面的代碼保存爲 test.sh,並 cd 到相應目錄:

chmod +x ./test.sh  #使腳本具備執行權限,能夠省略
./test.sh  #執行腳本

注意,必定要寫成 ./test.sh,而不是 test.sh,運行其它二進制的程序也同樣,直接寫 test.sh,linux 系統會去 PATH 裏尋找有沒有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 裏,你的當前目錄一般不在 PATH 裏,因此寫成 test.sh 是會找不到命令的,要用 ./test.sh 告訴系統說,就在當前目錄找

二、做爲解釋器參數

這種運行方式是,直接運行解釋器,其參數就是 shell 腳本的文件名,如:

/bin/sh test.sh # 一樣能夠按上面那種方式執行【/bin/sh ./test.sh】
/bin/php test.php

這種方式運行的腳本,不須要在第一行指定解釋器信息(寫了也沒用,由於會以運行時指定的解釋器爲準)。

Shell 變量

定義變量

定義變量時,變量名不加美圓符號$,如:

your_name="runoob.com"

注意,變量名和等號之間不能有空格,這可能和你熟悉的全部編程語言都不同!

除了顯式地直接賦值,還能夠用語句給變量賦值,如:

for file in `ls /etc` #注意,這裏用的是反斜槓而不是單引號,表示的是執行結果
    do printf  "當前目錄的文件:"
    echo $file
done
for file in `ls /etc`; do echo 當前目錄的文件:$file; done  #注意,若是換行了能夠省略分號,不然不能省略
for file in $(ls /etc); do echo $file; done

以上語句將 /etc 下目錄的文件名循環出來。

使用變量

使用一個定義過的變量,只要在變量名前面加美圓符號便可,如:

your_name="qinjx"
echo $your_name
echo ${your_name}

變量名外面的花括號是可選的,加不加都行,加花括號是爲了幫助解釋器識別變量的邊界,好比下面這種狀況:

for skill in Ada Coffe Action Java; do
    echo "I am good at ${skill}Script"
done
I am good at AdaScript
I am good at CoffeScript
I am good at ActionScript
I am good at JavaScript

若是不給skill變量加花括號,寫成echo "I am good at $skillScript",解釋器就會把$skillScript當成一個變量(其值爲空),代碼執行結果就不是咱們指望的樣子了。

推薦給全部變量加上花括號,這是個好的編程習慣。

已定義的變量,能夠被從新定義,如:

your_name="tom"
echo $your_name
your_name="alibaba"
echo $your_name

這樣寫是合法的,但注意,第二次賦值的時候不能加美圓符,使用變量的時候才加美圓符

只讀變量

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

readonly myUrl="http://www.google.com"
myUrl="http://www.google.com"
readonly myUrl

下面的例子嘗試更改只讀變量,結果報錯:

readonly myUrl="http://www.google.com"
myUrl="http://www.runoob.com" #報錯 ./test.sh: line 2: myUrl: readonly variable

刪除變量

使用 unset 命令能夠刪除變量。語法:

unset variable_name

變量被刪除後不能再次使用。unset 命令不能刪除只讀變量

myUrl="http://www.runoob.com"
unset myUrl
echo $myUrl #不報錯,但沒有任何輸出
readonly myUrl="http://www.runoob.com"
unset myUrl #報錯./test.sh: line 2: unset: myUrl: cannot unset: readonly variable

Shell 字符串

字符串是shell編程中最經常使用最有用的數據類型(除了數字和字符串,也沒啥其它類型好用了),字符串能夠用單引號,也能夠用雙引號,也能夠不用引號。單雙引號的區別跟PHP相似。

單引號

str='this is a string'

單引號字符串的限制:

  • 單引號裏的任何字符都會【原樣輸出】,單引號字符串中的變量是無效的
  • 單引號字串中不能出現單獨一個的單引號,對單引號使用轉義符後也不行()
  • 單引號字串中可成對出現一對單引號,做爲字符串拼接使用
name=白乾濤
test1='hello, ${name}sir!'    #不加符號,原樣輸出,hello, ${name}sir!
test2='hello, `$name`sir!'    #加反斜槓,原樣輸出,hello, `$name`sir!
test3='hello, "$name"sir!'    #加雙引號,原樣輸出,hello, "$name"sir!
test4='hello, '$name'sir!'    #加單引號,正常輸出,hello, 白乾濤sir!
echo $test1 $test2 $test3 $test4

雙引號

雙引號裏能夠有變量,能夠出現轉義字符

name=白乾濤
test1="hello, ${name}sir!"      #不加符號,hello, 白乾濤sir!
test2="hello, \`$name\`sir!"   #加反斜槓且轉義,hello, `白乾濤`sir!
test3="hello, "$name"sir!"     #加雙引號,hello, 白乾濤sir!
test4="hello, \"$name\"sir!"  #加雙引號且轉義,hello, "白乾濤"sir!
test5="hello, '$name'sir!"      #加單引號,hello, '白乾濤'sir!
test6="hello, \'$name\'sir!"   #加單引號且轉義,hello, \'白乾濤\'sir!
echo $test1 $test2 $test3 $test4 $test5 $test6

echo "hello, `$name`sir!"      #反斜槓必須轉義,不然報錯./test.sh: line 10: 白乾濤: command not found

字符串基本操做

string="baiqiantao"
echo "字符串長度:${#string}" #字符串長度:4
echo "子串爲:${string:3:4}" #從第 index 個字符開始截取 length 個字符。子串爲:qian
echo "字符位置:`expr index "$string" qt`"  # 字符位置:4(index+1)
# 查找字符 q 或 t 的位置(哪一個字母先出現就計算哪一個),以上是反引號 `,而不是單引號 '

Shell 數組

bash支持一維數組(不支持多維數組),而且沒有限定數組的大小

相似於 C 語言,數組元素的下標由 0 開始編號。獲取數組中的元素要利用下標,下標能夠是整數或算術表達式,其值應大於或等於 0。

定義數組

在 Shell 中,用小括號來表示數組,數組元素用空格或換行符號分割開,初始化時不須要定義數組大小。

定義數組的通常形式爲:

數組名=(值1 值2 ... 值n)
array=(A 2 "C"
4.3
'5')

還能夠單獨定義數組的各個份量,能夠不使用連續的下標,並且下標的範圍沒有限制:

array[1]=1
array[5]=5
array[n]=白乾濤 #這裏的n表明某一個整數,若是未定義直接使用,表明0

數組的基本操做

基本操做

  • 獲取數組全部元素:${array_name[*]}${array_name[@]}
  • 獲取數組某個元素的值:${array_name[index]},index是從0開始的
  • 獲取數組的長度:${#array_name[*]}${#array_name[@]}
  • 獲取數組某個元素的長度:${#array_name[index]}
array=(A 2 "C" 4.3 '5')
array[8]=8
array[n]=白乾濤 #這裏的n表明某一個整數,若是未定義直接使用,表明0

echo "數組的元素爲: ${array[*]}" #白乾濤 2 C 4.3 5 8
echo "第一個元素爲: ${array[0]}" #白乾濤
echo "數組的長度爲:${#array[*]}" #6
echo "第一個元素長度爲: ${#array[0]}" #3

Shell 註釋

# 開頭的就是註釋,會被解釋器忽略。
若是在開發過程當中,遇到大段的代碼須要臨時註釋起來,過一下子又取消註釋,能夠把這一段要註釋的代碼用一對花括號括起來,定義成一個函數,沒有地方調用這個函數,這塊代碼就不會執行,達到了和註釋同樣的效果。

多行註釋還可使用如下格式:

:<<EOF
註釋內容...
EOF

EOF 也可使用其餘符號。

Shell 傳遞參數

咱們能夠在執行 Shell 腳本時,向腳本傳遞參數,腳本內獲取參數的格式爲:$n,n 表明第 n 個參數

echo "你的性別:$2";
echo "你的年齡:$1";

執行腳本:

./test.sh 29 男
你的性別:男
你的年齡:29

特殊字符處理參數

有幾個特殊字符用來處理參數:

符號 說明
$0 執行的文件名
$# 傳遞到腳本的參數個數
$* 以一個單字符串顯示全部向腳本傳遞的參數
$@ $*相同,可是使用時加引號,並在引號中返回每一個參數
$$ 腳本運行的當前進程ID號
$! 後臺運行的最後一個進程的ID號
$- 顯示Shell使用的當前選項,與set命令功能相同。
$? 顯示最後命令的退出狀態。0表示沒有錯誤,其餘任何值代表有錯誤。
echo "你的年齡:$1";
echo -e  "你的性別:$2\n";

echo "執行的文件名:$0";
echo -e "參數個數爲:$#\n";

echo "傳遞的參數做爲一個字符串顯示:$*";
echo -e "傳遞的參數做爲一個字符串顯示:$@\n";

echo "腳本運行的當前進程ID號:$$";
echo "後臺運行的最後一個進程的ID號 :$!";
echo "顯示Shell使用的當前選項:$-";
echo "顯示最後命令的退出狀態:$?";

執行腳本,輸出結果以下所示:

./test.sh 29 男
你的年齡:29
你的性別:男

執行的文件名:./test.sh
參數個數爲:2

傳遞的參數做爲一個字符串顯示:29 男
傳遞的參數做爲一個字符串顯示:29 男

腳本運行的當前進程ID號:14372
後臺運行的最後一個進程的ID號 :
顯示Shell使用的當前選項:hB
顯示最後命令的退出狀態:0

$*$@ 的異同點

  • 相同點:都是引用全部參數
  • 不一樣點:只有在雙引號中體現出來,假設在腳本運行時寫了三個參數 一、二、3
    • " * " 等價於 "1 2 3"(傳遞了一個參數)
    • "@" 等價於 "1" "2" "3"(傳遞了三個參數)。

相同點:都是引用全部參數

for i in $*; do # 【$*】、【$@】、【"$@"】的結果是同樣的
    echo $i
done
./test.sh 29 男 白乾濤
29
男
白乾濤

不一樣點:在雙引號中,"$*"的做用是將全部參數當作一個參數

for i in "$*"; do
    echo $i
done
./test.sh 29 男 白乾濤
29 男 白乾濤

Shell 基本運算符

Shell 和其餘編程語言同樣,支持多種運算符,包括:

  • 算數運算符
  • 關係運算符
  • 布爾運算符
  • 字符串運算符
  • 文件測試運算符

原生bash不支持簡單的數學運算,可是能夠經過其餘命令來實現,例如 awkexpr。expr 是一款表達式計算工具,使用它能完成表達式的求值操做。

val=`expr 2 + 2`
echo "兩數之和爲 : $val" #兩數之和爲 : 4

兩點注意:

  • 表達式和運算符之間必需要有空格,例如 2+2 是不對的,必須寫成 2 + 2,這與咱們熟悉的大多數編程語言不同
  • 完整的表達式要被反引號包含,注意這個字符不是經常使用的單引號

算術運算符

下表列出了經常使用的算術運算符,假定變量 a 爲 10,變量 b 爲 20:

運算符 說明
+ 加法
- 減法
* 乘法
/ 除法
% 取餘
= 賦值
== 相等
!= 不相等

注意:

  • 乘號*前邊必須加反斜槓\才能實現乘法運算
  • 在 MAC 中 shell 的 expr 語法是:$((表達式)),此處表達式中的 *不須要轉義符號\

關係運算符

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

下表列出了經常使用的關係運算符,假定變量 a 爲 10,變量 b 爲 20:

運算符 說明
-eq 檢測兩個數是否相等
-ne 檢測兩個數是否不相等
-gt 檢測左邊的數是否大於右邊的
-lt 檢測左邊的數是否小於右邊的
-ge 檢測左邊的數是否大於等於右邊的
-le 檢測左邊的數是否小於等於右邊的

布爾運算符

下表列出了經常使用的布爾運算符,假定變量 a 爲 10,變量 b 爲 20:

運算符 說明
! 非運算
-o 或運算,or
-a 與運算,and

邏輯運算符

如下介紹 Shell 的邏輯運算符,假定變量 a 爲 10,變量 b 爲 20:

  • && 邏輯與 [[ $a -lt 100 && $b -gt 100 ]] 返回 false
  • || 邏輯或 [[ $a -lt 100 || $b -gt 100 ]] 返回 true

字符串運算符

下表列出了經常使用的字符串運算符,假定變量 a 爲 "abc",變量 b 爲 "efg":

運算符 說明
= 檢測兩個字符串是否相等
!= 檢測兩個字符串是否不相等
-z 檢測字符串長度是否爲0
-n 檢測字符串長度是否不爲0
$ 檢測字符串是否不爲空

文件測試運算符

文件測試運算符用於檢測 Unix 文件的各類屬性。

操做符 說明
-b file 檢測文件是否是塊設備文件
-c file 檢測文件是否是字符設備文件
-d file 檢測文件是否是目錄
-f file 檢測文件是否是普通文件既不是目錄,也不是設備文件
-g file 檢測文件是否設置了 SGID 位
-k file 檢測文件是否設置了粘着位(Sticky Bit)
-p file 檢測文件是否是有名管道
-u file 檢測文件是否設置了 SUID 位
-r file 檢測文件是否可讀
-w file 檢測文件是否可寫
-x file 檢測文件是否可執行
-s file 檢測文件是否爲空(文件大小是否大於0)
-e file 檢測文件(包括目錄)是否存在

其餘檢查符:

  • -S: 判斷某文件是否 socket
  • -L: 檢測文件是否存在而且是一個符號連接

Shell echo 命令

Shell 的 echo 指令與 PHP 的 echo 指令相似,都是用於字符串的輸出。
echo 會自動添加換行符。

echo "It is a test" #顯示普通字符串,每輸出一次會自動換行
echo It is a test    #雙引號徹底能夠省略
echo "\"It is a test\""  #顯示轉義字符【"It is a test"】,雙引號一樣也能夠省略
name=白乾濤
echo "$name It is a test" #顯示變量,雙引號一樣也能夠省略
echo -e "It is a test\n" #顯示換行,【-e】爲開啓轉義,【\n】表示換行
echo -e "It is a test\c" #顯示不換行,【\c】表示不換行,【\c】後面的內容會丟棄
echo '---$name\"' #用單引號能夠原樣輸出字符串,不進行轉義或取變量
echo `date` #使用反引號能夠顯示命令執行的結果
It is a test
It is a test
"It is a test"
白乾濤 It is a test
It is a test

It is a test---$name\"
2019年11月 4日 0:05:17

Shell printf 命令

printf 命令模仿 C 程序庫裏的 printf() 程序。
printf 由 POSIX 標準所定義,所以使用 printf 的腳本比使用 echo 移植性好
printf 使用引用文本或空格分隔的參數,外面能夠在 printf 中使用格式化字符串,還能夠制定字符串的寬度、左右對齊方式等。
默認 printf 不會像 echo 自動添加換行符,咱們能夠手動添加 \n。

printf 命令的語法:

printf format-string [arguments...] #格式控制字符串 爲參數列表

格式替代符

%s%c%d%f都是格式替代符,分別表明替換字符串、字符、整數、浮點數,例如:

printf "%-9s %-6s %5s\n" 姓名 性別 體重kg
printf "%-9s %-3s %5.2f\n" 白乾濤 男 66.1
printf "%-9s %-3s %5.2f\n" 白乾濤 M 66.1
printf "%-9s %-3s %5.2f\n" 乾濤 男 6.1
printf "%-9s %-3s %5.2f\n" baiqiantao 男 666.1234
姓名    性別 體重kg   #空格數四、1
白乾濤 男 66.10     #空格數一、1
白乾濤 M   66.10       #空格數一、3
乾濤    男  6.10       #空格數四、2
qiantao   男 666.12  #空格數三、1

其中:

  • %-9s 指寬度爲9個字符(一箇中文算3個字符、一個英文算一個字符),若是寬度不足則自動以空格填充超過也會將內容所有顯示出來。其實能夠理解爲最少顯示n個字符。
  • -表示左對齊,沒有則表示右對齊。
  • %-5.2f 指格式化爲小數,其中5表明(最少)顯示幾個字符(小數點也算在內),.2指(強制)保留2位小數。

使用案例

基本案例

printf "年齡:30\n"     #能夠省略參數列表(此時即便有參數列表也是無效的)【年齡:30】
printf "年齡:%d\n" 30  #雙引號【年齡:30】
printf '年齡:%d\n' 30  #單引號,與雙引號效果同樣
printf 年齡:%d 30      # 沒有引號也能夠輸出

錯誤案例

printf %s "包青天\n" #【換行失敗】有格式化字符時,參數列表中的換行符無效
printf %s\n "白乾濤" #【換行失敗】格式化字符中有換行符時,須要用雙引號引住

# 打印內容【包青天\n白乾濤n】

格式只指定了一個參數,但多出的參數仍然會按照該格式輸出,format-string 被重用

printf 姓名:%s 白乾濤 包青天 #【姓名:白乾濤姓名:包青天】
printf "姓名:%s\n" 白乾濤 包青天 #【姓名:白乾濤(換行)姓名:包青天】
printf "%s %s %s\n" a b c d e f g #每3個一個換行
姓名:白乾濤姓名:包青天姓名:白乾濤
姓名:包青天
a b c
d e f
g

若是沒有 arguments,那麼 %s 用NULL代替,%d 用 0 代替,%c 用空格代替,%f 用 0.000000 代替

printf "%s和 %d 和%c和 %f \n" #【和 0 和 和 0.000000】

printf 的轉義序列

序列 說明
\a 警告字符,一般爲ASCII的BEL字符
\b 後退
\c 抑制(不顯示)輸出結果中任何結尾的換行字符(只在%b格式指示符控制下的參數字符串中有效),並且,任何留在參數裏的字符、任何接下來的參數以及任何留在格式字符串中的字符,都被忽略
\f 換頁(formfeed)
\n 換行
\r 回車(Carriage return)
\t 水平製表符
\v 垂直製表符
\\ 一個字面上的反斜槓字符
\ddd 表示1到3位數八進制值的字符。僅在格式字符串中有效
\0ddd 表示1到3位的八進制值字符
printf "%s\n" "白乾濤\n包青天" #【白乾濤\n包青天】
printf "%b\n" "白乾濤\n包青天" #【白乾濤(換行)包青天】

2019-9-1

相關文章
相關標籤/搜索