1. Shell簡介
Shell本身是一個用C語言編寫的程序,它是用戶使用Unix/Linux的橋梁,用戶的大部分工作都是通過Shell完成的。Shell既是一種命令語言,又是一種程序設計語言。作為命令語言,它交互式地解釋和執行用戶輸入的命令;作為程序設計語言,它定義了各種變量和參數,並提供了許多在高級語言中才具有的控制結構,包括循環和分支。
它雖然不是Unix/Linux系統內核的一部分,但它調用了系統核心的大部分功能來執行程序、建立文件並以並行的方式協調各個程序的運行。因此,對於用戶來說,shell是最重要的實用程序,深入了解和熟練掌握shell的特性極其使用方法,是用好Unix/Linux系統的關鍵。
可以說,shell使用的熟練程度反映了用戶對Unix/Linux使用的熟練程度。
注意:單獨地學習 Shell 是沒有意義的,請先參考Unix/Linux入門教程,了解 Unix/Linux 基礎。
Shell有兩種執行命令的方式:
交互式(Interactive):解釋執行用戶的命令,用戶輸入一條命令,Shell就解釋執行一條。
批處理(Batch):用戶事先寫一個Shell腳本(Script),其中有很多條命令,讓Shell一次把這些命令執行完,而不必一條一條地敲命令。
Shell腳本和編程語言很相似,也有變量和流程控制語句,但Shell腳本是解釋執行的,不需要編譯,Shell程序從腳本中一行一行讀取並執行這些命令,相當於一個用戶把腳本中的命令一行一行敲到Shell提示符下執行。
Shell初學者請注意,在平常應用中,建議不要用 root 帳號運行 Shell 。作為普通用戶,不管您有意還是無意,都無法破壞系統;但如果是 root,那就不同了,只要敲幾個字母,就可能導致災難性后果。
2. 幾種常見的Shell
Unix/Linux上常見的Shell腳本解釋器有bash、sh、csh、ksh等,習慣上把它們稱作一種Shell。我們常說有多少種Shell,其實說的是Shell腳本解釋器。
bash:bash是Linux標准默認的shell,本教程也基於bash講解。bash由Brian Fox和Chet Ramey共同完成,是BourneAgain Shell的縮寫,內部命令一共有40個。
Linux使用它作為默認的shell是因為它有諸如以下的特色:
-
可以使用類似DOS下面的doskey的功能,用方向鍵查閱和快速輸入並修改命令。
-
自動通過查找匹配的方式給出以某字符串開頭的命令。
-
包含了自身的幫助功能,你只要在提示符下面鍵入help就可以得到相關的幫助。
sh:sh 由Steve Bourne開發,是Bourne Shell的縮寫,sh 是Unix 標准默認的shell。
ash:ash shell 是由Kenneth Almquist編寫的,Linux中占用系統資源最少的一個小shell,它只包含24個內部命令,因而使用起來很不方便。
csh:csh 是Linux比較大的內核,它由以William Joy為代表的共計47位作者編成,共有52個內部命令。該shell其實是指向/bin/tcsh這樣的一個shell,也就是說,csh其實就是tcsh。
ksh:ksh 是Korn shell的縮寫,由Eric Gisin編寫,共有42條內部命令。該shell最大的優點是幾乎和商業發行版的ksh完全兼容,這樣就可以在不用花錢購買商業版本的情況下嘗試商業版本的性能了。
注意:bash是 Bourne Again Shell 的縮寫,是linux標准的默認shell ,它基於Bourne shell,吸收了C shell和Korn shell的一些特性。bash完全兼容sh,也就是說,用sh寫的腳本可以不加修改的在bash中執行。3. 編譯型語言和解釋型語言的區別
編譯型語言
很多傳統的程序設計語言,例如Fortran、Ada、Pascal、C、C++和Java,都是編譯型語言。這類語言需要預先將我們寫好的源代碼(source code)轉換成目標代碼(object code),這個過程被稱作“編譯”。但是,由於編譯型語言多半運作於底層,所處理的是字節、整數、浮點數或是其他機器層級的對象,往往實現一個簡單的功能需要大量復雜的代碼。例如,在C++里,就很難進行“將一個目錄里所有的文件復制到另一個目錄中”之類的簡單操作。
解釋型語言
解釋型語言也被稱作“腳本語言”。執行這類程序時,解釋器(interpreter)需要讀取我們編寫的源代碼(source code),並將其轉換成目標代碼(object code),再由計算機運行。因為每次執行程序都多了編譯的過程,因此效率有所下降。使用腳本編程語言的好處是,它們多半運行在比編譯型語言還高的層級,能夠輕易處理文件與目錄之類的對象;缺點是它們的效率通常不如編譯型語言。不過權衡之下,通常使用腳本編程還是值得的:花一個小時寫成的簡單腳本,同樣的功能用C或C++來編寫實現,可能需要兩天,而且一般來說,腳本執行的速度已經夠快了,快到足以讓人忽略它性能上的問題。腳本編程語言的例子有awk、Perl、Python、Ruby與Shell。
4. 什么時候使用Shell?
- 簡單性:Shell是一個高級語言;通過它,你可以簡潔地表達復雜的操作。
- 可移植性:使用POSIX所定義的功能,可以做到腳本無須修改就可在不同的系統上執行。
- 開發容易:可以在短時間內完成一個功能強大又妤用的腳本。
- 資源密集型的任務,尤其在需要考慮效率時(比如,排序,hash等等)。
- 需要處理大任務的數學操作,尤其是浮點運算,精確運算,或者復雜的算術運算(這種情況一般使用C++或FORTRAN 來處理)。
- 有跨平台(操作系統)移植需求(一般使用C 或Java)。
- 復雜的應用,在必須使用結構化編程的時候(需要變量的類型檢查,函數原型,等等)。
- 對於影響系統全局性的關鍵任務應用。
- 對於安全有很高要求的任務,比如你需要一個健壯的系統來防止入侵、破解、惡意破壞等等。
- 項目由連串的依賴的各個部分組成。
- 需要大規模的文件操作。
- 需要多維數組的支持。
- 需要數據結構的支持,比如鏈表或數等數據結構。
- 需要產生或操作圖形化界面 GUI。
- 需要直接操作系統硬件。
- 需要 I/O 或socket 接口。
- 需要使用庫或者遺留下來的老代碼的接口。
- 私人的、閉源的應用(shell 腳本把代碼就放在文本文件中,全世界都能看到)。
如果你的應用符合上邊的任意一條,那么就考慮一下更強大的語言吧——或許是Perl、Tcl、Python、Ruby——或者是更高層次的編譯語言比如C/C++,或者是Java。即使如此,你會發現,使用shell來原型開發你的應用,在開發步驟中也是非常有用的。
5. 第一個Shell腳本
輸入一些代碼:
#!/bin/bash echo "Hello World !"
運行Shell腳本有兩種方法。
5.1 作為可執行程序
將上面的代碼保存為test.sh,並 cd 到相應目錄:
chmod +x ./test.sh #使腳本具有執行權限 ./test.sh #執行腳本
通過這種方式運行bash腳本,第一行一定要寫對,好讓系統查找到正確的解釋器。
這里的"系統",其實就是shell這個應用程序(想象一下Windows Explorer),但我故意寫成系統,是方便理解,既然這個系統就是指shell,那么一個使用/bin/sh作為解釋器的腳本是不是可以省去第一行呢?是的。
5.2 作為解釋器參數
這種運行方式是,直接運行解釋器,其參數就是shell腳本的文件名,如:/bin/sh test.sh
/bin/php test.php
再看一個例子。下面的腳本使用 read 命令從 stdin 獲取輸入並賦值給 PERSON 變量,最后在 stdout 上輸出:
#!/bin/bash # Author : mozhiyan # Copyright (c) http://see.xidian.edu.cn/cpp/linux/ # Script follows here: echo "What is your name?" read PERSON echo "Hello, $PERSON"
chmod +x ./test.sh $./test.sh What is your name? mozhiyan Hello, mozhiyan
6. Shell變量
6.1 定義變量
定義變量時,變量名不加美元符號($),如:variableName="value"
- 首個字符必須為字母(a-z,A-Z)。
- 中間不能有空格,可以使用下划線(_)。
- 不能使用標點符號。
- 不能使用bash里的關鍵字(可用help命令查看保留關鍵字)。
myUrl="http://see.xidian.edu.cn/cpp/linux/" myNum=100
6.2 使用變量
使用一個定義過的變量,只要在變量名前面加美元符號($)即可,如:your_name="mozhiyan" echo $your_name echo ${your_name}
for skill in Ada Coffe Action Java do echo "I am good at ${skill}Script" done
推薦給所有變量加上花括號,這是個好的編程習慣。
6.3 重新定義變量
已定義的變量,可以被重新定義,如:myUrl="http://see.xidian.edu.cn/cpp/linux/" echo ${myUrl} myUrl="http://see.xidian.edu.cn/cpp/shell/" echo ${myUrl}
6.4 只讀變量
使用 readonly 命令可以將變量定義為只讀變量,只讀變量的值不能被改變。下面的例子嘗試更改只讀變量,結果報錯:
#!/bin/bash myUrl="http://see.xidian.edu.cn/cpp/shell/" readonly myUrl myUrl="http://see.xidian.edu.cn/cpp/danpianji/"
/bin/sh: NAME: This variable is read only.
6.5 刪除變量
使用 unset 命令可以刪除變量。語法:unset variable_name
舉個例子:
#!/bin/sh myUrl="http://see.xidian.edu.cn/cpp/u/xitong/" unset myUrl echo $myUrl
6.6 變量類型
運行shell時,會同時存在三種變量:1) 局部變量
局部變量在腳本或命令中定義,僅在當前shell實例中有效,其他shell啟動的程序不能訪問局部變量。2) 環境變量
所有的程序,包括shell啟動的程序,都能訪問環境變量,有些程序需要環境變量來保證其正常運行。必要的時候shell腳本也可以定義環境變量。3) shell變量
shell變量是由shell程序設置的特殊變量。shell變量中有一部分是環境變量,有一部分是局部變量,這些變量保證了shell的正常運行7.Shell特殊變量
$echo $$
變量 | 含義 |
---|---|
$0 | 當前腳本的文件名 |
$n | 傳遞給腳本或函數的參數。n 是一個數字,表示第幾個參數。例如,第一個參數是$1,第二個參數是$2。 |
$# | 傳遞給腳本或函數的參數個數。 |
$* | 傳遞給腳本或函數的所有參數。 |
$@ | 傳遞給腳本或函數的所有參數。被雙引號(" ")包含時,與 $* 稍有不同,下面將會講到。 |
$? | 上個命令的退出狀態,或函數的返回值。 |
$$ | 當前Shell進程ID。對於 Shell 腳本,就是這些腳本所在的進程ID。 |
命令行參數
運行腳本時傳遞給腳本的參數稱為命令行參數。命令行參數用 $n 表示,例如,$1 表示第一個參數,$2 表示第二個參數,依次類推。請看下面的腳本:
#!/bin/bash echo "File Name: $0" echo "First Parameter : $1" echo "First Parameter : $2" echo "Quoted Values: $@" echo "Quoted Values: $*" echo "Total Number of Parameters : $#"
$./test.sh Zara Ali File Name : ./test.sh First Parameter : Zara Second Parameter : Ali Quoted Values: Zara Ali Quoted Values: Zara Ali Total Number of Parameters : 2
$* 和 $@ 的區別
$* 和 $@ 都表示傳遞給函數或腳本的所有參數,不被雙引號(" ")包含時,都以"$1" "$2" … "$n" 的形式輸出所有參數。但是當它們被雙引號(" ")包含時,"$*" 會將所有的參數作為一個整體,以"$1 $2 … $n"的形式輸出所有參數;"$@" 會將各個參數分開,以"$1" "$2" … "$n" 的形式輸出所有參數。
下面的例子可以清楚的看到 $* 和 $@ 的區別:
#!/bin/bash echo "\$*=" $* echo "\"\$*\"=" "$*" echo "\$@=" $@ echo "\"\$@\"=" "$@" echo "print each param from \$*" for var in $* do echo "$var" done echo "print each param from \$@" for var in $@ do echo "$var" done echo "print each param from \"\$*\"" for var in "$*" do echo "$var" done echo "print each param from \"\$@\"" for var in "$@" do echo "$var"
- done
$*= a b c d "$*"= a b c d $@= a b c d "$@"= a b c d print each param from $* a b c d print each param from $@ a b c d print each param from "$*" a b c d print each param from "$@" a b c d
退出狀態
$? 可以獲取上一個命令的退出狀態。所謂退出狀態,就是上一個命令執行后的返回結果。退出狀態是一個數字,一般情況下,大部分命令執行成功會返回 0,失敗返回 1。
不過,也有一些命令返回其他值,表示不同類型的錯誤。
下面例子中,命令成功執行:
$./test.sh Zara Ali File Name : ./test.sh First Parameter : Zara Second Parameter : Ali Quoted Values: Zara Ali Quoted Values: Zara Ali Total Number of Parameters : 2 $echo $? 0 $
8. Shell替換
舉個例子:
#!/bin/bash a=10 echo -e "Value of a is $a \n"
Value of a is 10
Value of a is 10\n
轉義字符 | 含義 |
---|---|
\\ | 反斜杠 |
\a | 警報,響鈴 |
\b | 退格(刪除鍵) |
\f | 換頁(FF),將當前位置移到下頁開頭 |
\n | 換行 |
\r | 回車 |
\t | 水平制表符(tab鍵) |
\v | 垂直制表符 |
命令替換
命令替換是指Shell可以先執行命令,將輸出結果暫時保存,在適當的地方輸出。命令替換的語法:
`command`
下面的例子中,將命令執行結果保存在變量中:
#!/bin/bash DATE=`date` echo "Date is $DATE" USERS=`who | wc -l` echo "Logged in user are $USERS" UP=`date ; uptime` echo "Uptime is $UP"
Date is Thu Jul 2 03:59:57 MST 2009 Logged in user are 1 Uptime is Thu Jul 2 03:59:57 MST 2009 03:59:57 up 20 days, 14:03, 1 user, load avg: 0.13, 0.07, 0.15
變量替換
變量替換可以根據變量的狀態(是否為空、是否定義等)來改變它的值。可以使用的變量替換形式:
形式 | 說明 |
---|---|
${var} | 變量本來的值 |
${var:-word} | 如果變量 var 為空或已被刪除(unset),那么返回 word,但不改變 var 的值。 |
${var:=word} | 如果變量 var 為空或已被刪除(unset),那么返回 word,並將 var 的值設置為 word。 |
${var:?message} | 如果變量 var 為空或已被刪除(unset),那么將消息 message 送到標准錯誤輸出,可以用來檢測變量 var 是否可以被正常賦值。 若此替換出現在Shell腳本中,那么腳本將停止運行。 |
${var:+word} | 如果變量 var 被定義,那么返回 word,但不改變 var 的值。 |
請看下面的例子:
#!/bin/bash echo ${var:-"Variable is not set"} echo "1 - Value of var is ${var}" echo ${var:="Variable is not set"} echo "2 - Value of var is ${var}" unset var echo ${var:+"This is default value"} echo "3 - Value of var is $var" var="Prefix" echo ${var:+"This is default value"} echo "4 - Value of var is $var" echo ${var:?"Print this message"} echo "5 - Value of var is ${var}"
Variable is not set 1 - Value of var is Variable is not set 2 - Value of var is Variable is not set 3 - Value of var is This is default value 4 - Value of var is Prefix Prefix 5 - Value of var is Prefix
9. Shell運算符
expr 是一款表達式計算工具,使用它能完成表達式的求值操作。
例如,兩個數相加:
#!/bin/bash val=`expr 2 + 2` echo "Total value : $val"
Total value : 4
- 表達式和運算符之間要有空格,例如 2+2 是不對的,必須寫成 2 + 2,這與我們熟悉的大多數編程語言不一樣。
- 完整的表達式要被 ` ` 包含,注意這個字符不是常用的單引號,在 Esc 鍵下邊。
9.1 算術運算符
先來看一個使用算術運算符的例子:#!/bin/sh 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 is equal to b" fi if [ $a != $b ] then echo "a is not equal to b" fi
a + b : 30 a - b : -10 a * b : 200 b / a : 2 b % a : 0 a is not equal to b
- 乘號(*)前邊必須加反斜杠(\)才能實現乘法運算;
- if...then...fi 是條件語句,后續將會講解。
運算符 | 說明 | 舉例 |
---|---|---|
+ | 加法 | `expr $a + $b` 結果為 30。 |
- | 減法 | `expr $a - $b` 結果為 10。 |
* | 乘法 | `expr $a \* $b` 結果為 200。 |
/ | 除法 | `expr $b / $a` 結果為 2。 |
% | 取余 | `expr $b % $a` 結果為 0。 |
= | 賦值 | a=$b 將把變量 b 的值賦給 a。 |
== | 相等。用於比較兩個數字,相同則返回 true。 | [ $a == $b ] 返回 false。 |
!= | 不相等。用於比較兩個數字,不相同則返回 true。 | [ $a != $b ] 返回 true。 |
注意:條件表達式要放在方括號之間,並且要有空格,例如 [$a==$b] 是錯誤的,必須寫成 [ $a == $b ]。
9.2 關系運算符
關系運算符只支持數字,不支持字符串,除非字符串的值是數字。先來看一個關系運算符的例子:
#!/bin/sh a=10 b=20 if [ $a -eq $b ] then echo "$a -eq $b : a is equal to b" else echo "$a -eq $b: a is not equal to b" fi if [ $a -ne $b ] then echo "$a -ne $b: a is not equal to b" else echo "$a -ne $b : a is equal to b" fi if [ $a -gt $b ] then echo "$a -gt $b: a is greater than b" else echo "$a -gt $b: a is not greater than b" fi if [ $a -lt $b ] then echo "$a -lt $b: a is less than b" else echo "$a -lt $b: a is not less than b" fi if [ $a -ge $b ] then echo "$a -ge $b: a is greater or equal to b" else echo "$a -ge $b: a is not greater or equal to b" fi if [ $a -le $b ] then echo "$a -le $b: a is less or equal to b" else echo "$a -le $b: a is not less or equal to b" fi
10 -eq 20: a is not equal to b 10 -ne 20: a is not equal to b 10 -gt 20: a is not greater than b 10 -lt 20: a is less than b 10 -ge 20: a is not greater or equal to b 10 -le 20: a is less or equal to b
運算符 | 說明 | 舉例 |
---|---|---|
-eq | 檢測兩個數是否相等,相等返回 true。 | [ $a -eq $b ] 返回 true。 |
-ne | 檢測兩個數是否相等,不相等返回 true。 | [ $a -ne $b ] 返回 true。 |
-gt | 檢測左邊的數是否大於右邊的,如果是,則返回 true。 | [ $a -gt $b ] 返回 false。 |
-lt | 檢測左邊的數是否小於右邊的,如果是,則返回 true。 | [ $a -lt $b ] 返回 true。 |
-ge | 檢測左邊的數是否大等於右邊的,如果是,則返回 true。 | [ $a -ge $b ] 返回 false。 |
-le | 檢測左邊的數是否小於等於右邊的,如果是,則返回 true。 | [ $a -le $b ] 返回 true。 |
9.3 布爾運算符
先來看一個布爾運算符的例子:#!/bin/sh a=10 b=20 if [ $a != $b ] then echo "$a != $b : a is not equal to b" else echo "$a != $b: a is equal to b" fi if [ $a -lt 100 -a $b -gt 15 ] then echo "$a -lt 100 -a $b -gt 15 : returns true" else echo "$a -lt 100 -a $b -gt 15 : returns false" fi if [ $a -lt 100 -o $b -gt 100 ] then echo "$a -lt 100 -o $b -gt 100 : returns true" else echo "$a -lt 100 -o $b -gt 100 : returns false" fi if [ $a -lt 5 -o $b -gt 100 ] then echo "$a -lt 100 -o $b -gt 100 : returns true" else echo "$a -lt 100 -o $b -gt 100 : returns false" fi
10 != 20 : a is not equal to b 10 -lt 100 -a 20 -gt 15 : returns true 10 -lt 100 -o 20 -gt 100 : returns true 10 -lt 5 -o 20 -gt 100 : returns false
運算符 | 說明 | 舉例 |
---|---|---|
! | 非運算,表達式為 true 則返回 false,否則返回 true。 | [ ! false ] 返回 true。 |
-o | 或運算,有一個表達式為 true 則返回 true。 | [ $a -lt 20 -o $b -gt 100 ] 返回 true。 |
-a | 與運算,兩個表達式都為 true 才返回 true。 | [ $a -lt 20 -a $b -gt 100 ] 返回 false。 |
9.4 字符串運算符
先來看一個例子:#!/bin/sh a="abc" b="efg" if [ $a = $b ] then echo "$a = $b : a is equal to b" else echo "$a = $b: a is not equal to b" fi if [ $a != $b ] then echo "$a != $b : a is not equal to b" else echo "$a != $b: a is equal to b" fi if [ -z $a ] then echo "-z $a : string length is zero" else echo "-z $a : string length is not zero" fi if [ -n $a ] then echo "-n $a : string length is not zero" else echo "-n $a : string length is zero" fi if [ $a ] then echo "$a : string is not empty" else echo "$a : string is empty" fi
abc = efg: a is not equal to b abc != efg : a is not equal to b -z abc : string length is not zero -n abc : string length is not zero abc : string is not empty
運算符 | 說明 | 舉例 |
---|---|---|
= | 檢測兩個字符串是否相等,相等返回 true。 | [ $a = $b ] 返回 false。 |
!= | 檢測兩個字符串是否相等,不相等返回 true。 | [ $a != $b ] 返回 true。 |
-z | 檢測字符串長度是否為0,為0返回 true。 | [ -z $a ] 返回 false。 |
-n | 檢測字符串長度是否為0,不為0返回 true。 | [ -z $a ] 返回 true。 |
str | 檢測字符串是否為空,不為空返回 true。 | [ $a ] 返回 true。 |
9.5 文件測試運算符
文件測試運算符用於檢測 Unix 文件的各種屬性。例如,變量 file 表示文件“/var/www/tutorialspoint/unix/test.sh”,它的大小為100字節,具有 rwx 權限。下面的代碼,將檢測該文件的各種屬性:
#!/bin/sh file="/var/www/tutorialspoint/unix/test.sh" if [ -r $file ] then echo "File has read access" else echo "File does not have read access" fi if [ -w $file ] then echo "File has write permission" else echo "File does not have write permission" fi if [ -x $file ] then echo "File has execute permission" else echo "File does not have execute permission" fi if [ -f $file ] then echo "File is an ordinary file" else echo "This is sepcial file" fi if [ -d $file ] then echo "File is a directory" else echo "This is not a directory" fi if [ -s $file ] then echo "File size is zero" else echo "File size is not zero" fi if [ -e $file ] then echo "File exists" else echo "File does not exist" fi
File has read access File has write permission File has execute permission File is an ordinary file This is not a directory File size is zero File exists
操作符 | 說明 | 舉例 |
---|---|---|
-b file | 檢測文件是否是塊設備文件,如果是,則返回 true。 | [ -b $file ] 返回 false。 |
-c file | 檢測文件是否是字符設備文件,如果是,則返回 true。 | [ -b $file ] 返回 false。 |
-d file | 檢測文件是否是目錄,如果是,則返回 true。 | [ -d $file ] 返回 false。 |
-f file | 檢測文件是否是普通文件(既不是目錄,也不是設備文件),如果是,則返回 true。 | [ -f $file ] 返回 true。 |
-g file | 檢測文件是否設置了 SGID 位,如果是,則返回 true。 | [ -g $file ] 返回 false。 |
-k file | 檢測文件是否設置了粘着位(Sticky Bit),如果是,則返回 true。 | [ -k $file ] 返回 false。 |
-p file | 檢測文件是否是具名管道,如果是,則返回 true。 | [ -p $file ] 返回 false。 |
-u file | 檢測文件是否設置了 SUID 位,如果是,則返回 true。 | [ -u $file ] 返回 false。 |
-r file | 檢測文件是否可讀,如果是,則返回 true。 | [ -r $file ] 返回 true。 |
-w file | 檢測文件是否可寫,如果是,則返回 true。 | [ -w $file ] 返回 true。 |
-x file | 檢測文件是否可執行,如果是,則返回 true。 | [ -x $file ] 返回 true。 |
-s file | 檢測文件是否為空(文件大小是否大於0),不為空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 檢測文件(包括目錄)是否存在,如果是,則返回 true。 | [ -e $file ] 返回 true。 |
10. Shell注釋
#-------------------------------------------- # 這是一個自動打ipa的腳本,基於webfrogs的ipa-build書寫: # https://github.com/webfrogs/xcode_shell/blob/master/ipa-build # 功能:自動為etao ios app打包,產出物為14個渠道的ipa包 # 特色:全自動打包,不需要輸入任何參數 #-------------------------------------------- ##### 用戶配置區 開始 ##### # # # 項目根目錄,推薦將此腳本放在項目的根目錄,這里就不用改了 # 應用名,確保和Xcode里Product下的target_name.app名字一致 # ##### 用戶配置區 結束 #####
11. Shell字符串
11.1 單引號
str='this is a string'
- 單引號里的任何字符都會原樣輸出,單引號字符串中的變量是無效的;
- 單引號字串中不能出現單引號(對單引號使用轉義符后也不行)。
11.2 雙引號
your_name='qinjx' str="Hello, I know your are \"$your_name\"! \n"
- 雙引號里可以有變量
- 雙引號里可以出現轉義字符
11.3 拼接字符串
your_name="qinjx" greeting="hello, "$your_name" !" greeting_1="hello, ${your_name} !" echo $greeting $greeting_1
11.4 獲取字符串長度
string="abcd" echo ${#string} #輸出 4
11.5 提取子字符串
string="alibaba is a great company" echo ${string:1:4} #輸出liba
11.6 查找子字符串
string="alibaba is a great company" echo `expr index "$string" is`
12. Shell數組
bash支持一維數組(不支持多維數組),並且沒有限定數組的大小。類似與C語言,數組元素的下標由0開始編號。獲取數組中的元素要利用下標,下標可以是整數或算術表達式,其值應大於或等於0。
12.1 定義數組
在Shell中,用括號來表示數組,數組元素用“空格”符號分割開。定義數組的一般形式為:array_name=(value1 ... valuen)
例如:
array_name=(value0 value1 value2 value3)
array_name=(
value0
value1
value2
value3
)
array_name[0]=value0 array_name[1]=value1 array_name[2]=value2
12.2 讀取數組
讀取數組元素值的一般格式是:${array_name[index]}
例如:
valuen=${array_name[2]}
#!/bin/sh NAME[0]="Zara" NAME[1]="Qadir" NAME[2]="Mahnaz" NAME[3]="Ayan" NAME[4]="Daisy" echo "First Index: ${NAME[0]}" echo "Second Index: ${NAME[1]}"
$./test.sh
First Index: Zara
Second Index: Qadir
${array_name[*]}
${array_name[@]}
#!/bin/sh NAME[0]="Zara" NAME[1]="Qadir" NAME[2]="Mahnaz" NAME[3]="Ayan" NAME[4]="Daisy" echo "First Method: ${NAME[*]}" echo "Second Method: ${NAME[@]}"
$./test.sh
First Method: Zara Qadir Mahnaz Ayan Daisy
Second Method: Zara Qadir Mahnaz Ayan Daisy
12.3 獲取數組的長度
獲取數組長度的方法與獲取字符串長度的方法相同,例如:# 取得數組元素的個數 length=${#array_name[@]} # 或者 length=${#array_name[*]} # 取得數組單個元素的長度 lengthn=${#array_name[n]}
13. echo命令
echo arg
13.1 顯示轉義字符
echo "\"It is a test\""
"It is a test"
13.2 顯示變量
name="OK" echo "$name It is a test"
OK It is a test
如果變量與其它字符相連的話,需要使用大括號({ }):
mouth=8 echo "${mouth}-1-2009"
8-1-2009
13.3 顯示換行
echo "OK!\n" echo "It is a test"
OK! It is a test
13.4 顯示不換行
echo "OK!\c" echo "It is a test"
OK!It si a test
13.5 顯示結果重定向至文件
echo "It is a test" > myfile
13.6 原樣輸出字符串
若需要原樣輸出字符串(不進行轉義),請使用單引號。例如:echo '$name\"'
13.7 顯示命令執行結果
echo `date`
從上面可看出,雙引號可有可無,單引號主要用在原樣輸出中。
14. printf命令
如同 echo 命令,printf 命令也可以輸出簡單的字符串:
$printf "Hello, Shell\n" Hello, Shell $
printf 命令的語法:
printf format-string [arguments...]
printf()在C語言入門教程中已經講到,功能和用法與 printf 命令類似,請查看:C語言格式輸出函數printf()詳解
這里僅說明與C語言printf()函數的不同:
- printf 命令不用加括號
- format-string 可以沒有引號,但最好加上,單引號雙引號均可。
- 參數多於格式控制符(%)時,format-string 可以重用,可以將所有參數都轉換。
- arguments 使用空格分隔,不用逗號。
# format-string為雙引號 $ printf "%d %s\n" 1 "abc" 1 abc # 單引號與雙引號效果一樣 $ printf '%d %s\n' 1 "abc" 1 abc # 沒有引號也可以輸出 $ printf %s abcdef abcdef # 格式只指定了一個參數,但多出的參數仍然會按照該格式輸出,format-string 被重用 $ printf %s abc def abcdef $ printf "%s\n" abc def abc def $ printf "%s %s %s\n" a b c d e f g h i j a b c d e f g h i j # 如果沒有 arguments,那么 %s 用NULL代替,%d 用 0 代替 $ printf "%s and %d \n" and 0 # 如果以 %d 的格式來顯示字符串,那么會有警告,提示無效的數字,此時默認置為 0 $ printf "The first program always prints'%s,%d\n'" Hello Shell -bash: printf: Shell: invalid number The first program always prints 'Hello,0' $
15. if...else語句
- if ... fi 語句;
- if ... else ... fi 語句;
- if ... elif ... else ... fi 語句。
1) if ... else 語句
if ... else 語句的語法:if [ expression ]
then
Statement(s) to be executed if expression is true
fi
如果 expression 返回 true,then 后邊的語句將會被執行;如果返回 false,不會執行任何語句。
最后必須以 fi 來結尾閉合 if,fi 就是 if 倒過來拼寫,后面也會遇見。
注意:expression 和方括號([ ])之間必須有空格,否則會有語法錯誤。
舉個例子:
#!/bin/sh a=10 b=20 if [ $a == $b ] then echo "a is equal to b" fi if [ $a != $b ] then echo "a is not equal to b" fi
a is not equal to b
2) if ... else ... fi 語句
if ... else ... fi 語句的語法:if [ expression ]
then
Statement(s) to be executed if expression is true
else
Statement(s) to be executed if expression is not true
fi
如果 expression 返回 true,那么 then 后邊的語句將會被執行;否則,執行 else 后邊的語句。
舉個例子:
#!/bin/sh a=10 b=20 if [ $a == $b ] then echo "a is equal to b" else echo "a is not equal to b" fi
a is not equal to b
3) if ... elif ... fi 語句
if ... elif ... fi 語句可以對多個條件進行判斷,語法為:if [ expression 1 ]
then
Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
Statement(s) to be executed if expression 2 is true
elif [ expression 3 ]
then
Statement(s) to be executed if expression 3 is true
else
Statement(s) to be executed if no expression is true
fi
哪一個 expression 的值為 true,就執行哪個 expression 后面的語句;如果都為 false,那么不執行任何語句。
舉個例子:
#!/bin/sh a=10 b=20 if [ $a == $b ] then echo "a is equal to b" elif [ $a -gt $b ] then echo "a is greater than b" elif [ $a -lt $b ] then echo "a is less than b" else echo "None of the condition met" fi
a is less than b
if ... else 語句也可以寫成一行,以命令的方式來運行,像這樣:
if test $[2*3] -eq $[1+5]; then echo 'The two numbers are equal!'; fi;
num1=$[2*3] num2=$[1+5] if test $[num1] -eq $[num2] then echo 'The two numbers are equal!' else echo 'The two numbers are not equal!' fi
The two numbers are equal!
16. case esac命令
case 語句匹配一個值或一個模式,如果匹配成功,執行相匹配的命令。case語句格式如下:
模式1)
command1
command2
command3
;;
模式2)
command1
command2
command3
;;
*)
command1
command2
command3
;;
esac
case工作方式如上所示。取值后面必須為關鍵字 in,每一模式必須以右括號結束。取值可以為變量或常數。匹配發現取值符合某一模式后,其間所有命令開始執行直至 ;;。;; 與其他語言中的 break 類似,意思是跳到整個 case 語句的最后。
取值將檢測匹配的每一個模式。一旦模式匹配,則執行完匹配模式相應命令后不再繼續其他模式。如果無一匹配模式,使用星號 * 捕獲該值,再執行后面的命令。
下面的腳本提示輸入1到4,與每一種模式進行匹配:
echo 'Input a number between 1 to 4' echo 'Your number is:\c' read aNum case $aNum in 1) echo 'You select 1' ;; 2) echo 'You select 2' ;; 3) echo 'You select 3' ;; 4) echo 'You select 4' ;; *) echo 'You do not select a number between 1 to 4' ;; esac
Input a number between 1 to 4 Your number is:3 You select 3
#!/bin/bash option="${1}" case ${option} in -f) FILE="${2}" echo "File name is $FILE" ;; -d) DIR="${2}" echo "Dir name is $DIR" ;; *) echo "`basename ${0}`:usage: [-f file] | [-d directory]" exit 1 # Command to come out of the program with status 1 ;; esac
$./test.sh test.sh: usage: [ -f filename ] | [ -d directory ] $ ./test.sh -f index.htm $ vi test.sh $ ./test.sh -f index.htm File name is index.htm $ ./test.sh -d unix Dir name is unix $
17. for循環
for循環一般格式為:
for 變量 in 列表
do
command1
command2
...
commandN
done
列表是一組值(數字、字符串等)組成的序列,每個值通過空格分隔。每循環一次,就將列表中的下一個值賦給變量。
in 列表是可選的,如果不用它,for 循環使用命令行的位置參數。
例如,順序輸出當前列表中的數字:
for loop in 1 2 3 4 5 do echo "The value is: $loop" done
The value is: 1 The value is: 2 The value is: 3 The value is: 4 The value is: 5
for str in 'This is a string' do echo $str done
This is a string
#!/bin/bash for FILE in $HOME/.bash* do echo $FILE done
/root/.bash_history /root/.bash_logout /root/.bash_profile /root/.bashrc
18. while循環
while command
do
Statement(s) to be executed if command is true
done
命令執行完畢,控制返回循環頂部,從頭開始直至測試條件為假。
以下是一個基本的while循環,測試條件是:如果COUNTER小於5,那么返回 true。COUNTER從0開始,每次循環處理時,COUNTER加1。運行上述腳本,返回數字1到5,然后終止。
COUNTER=0 while [ $COUNTER -lt 5 ] do COUNTER='expr $COUNTER+1' echo $COUNTER done
1 2 3 4 5
echo 'type <CTRL-D> to terminate' echo -n 'enter your most liked film: ' while read FILM do echo "Yeah! great film the $FILM" done
type <CTRL-D> to terminate
enter your most liked film: Sound of Music
Yeah! great film the Sound of Music
19. until命令
until 循環格式為:
until command
do
Statement(s) to be executed until command is true
done
command 一般為條件表達式,如果返回值為 false,則繼續執行循環體內的語句,否則跳出循環。
例如,使用 until 命令輸出 0 ~ 9 的數字:
#!/bin/bash a=0 until [ ! $a -lt 10 ] do echo $a a=`expr $a + 1` done
0
1
2
3
4
5
6
7
8
9
20. 跳出循環
20.1 break命令
break命令允許跳出所有循環(終止執行后面的所有循環)。下面的例子中,腳本進入死循環直至用戶輸入數字大於5。要跳出這個循環,返回到shell提示符下,就要使用break命令。
#!/bin/bash while : do echo -n "Input a number between 1 to 5: " read aNum case $aNum in 1|2|3|4|5) echo "Your number is $aNum!" ;; *) echo "You do not select a number between 1 to 5, game is over!" break ;; esac done
break n
下面是一個嵌套循環的例子,如果 var1 等於 2,並且 var2 等於 0,就跳出循環:
#!/bin/bash for var1 in 1 2 3 do for var2 in 0 5 do if [ $var1 -eq 2 -a $var2 -eq 0 ] then break 2 else echo "$var1 $var2" fi done done
1 0
1 5
20.2 continue命令
continue命令與break命令類似,只有一點差別,它不會跳出所有循環,僅僅跳出當前循環。對上面的例子進行修改:
#!/bin/bash while : do echo -n "Input a number between 1 to 5: " read aNum case $aNum in 1|2|3|4|5) echo "Your number is $aNum!" ;; *) echo "You do not select a number between 1 to 5!" continue echo "Game is over!" ;; esac done
echo "Game is over!"
同樣,continue 后面也可以跟一個數字,表示跳出第幾層循環。
再看一個 continue 的例子:
#!/bin/bash NUMS="1 2 3 4 5 6 7" for NUM in $NUMS do Q=`expr $NUM % 2` if [ $Q -eq 0 ] then echo "Number is an even number!!" continue fi echo "Found odd number" done
Found odd number Number is an even number!! Found odd number Number is an even number!! Found odd number Number is an even number!! Found odd number
21. Shell函數
function_name () {
list of commands
[ return value ]
}
如果你願意,也可以在函數名前加上關鍵字 function:
function function_name () {
list of commands
[ return value ]
}
函數返回值,可以顯式增加return語句;如果不加,會將最后一條命令運行結果作為返回值。
Shell 函數返回值只能是整數,一般用來表示函數執行成功與否,0表示成功,其他值表示失敗。如果 return 其他數據,比如一個字符串,往往會得到錯誤提示:“numeric argument required”。
如果一定要讓函數返回字符串,那么可以先定義一個變量,用來接收函數的計算結果,腳本在需要的時候訪問這個變量來獲得函數返回值。=
先來看一個例子:
#!/bin/bash # Define your function here Hello () { echo "Url is http://see.xidian.edu.cn/cpp/shell/" } # Invoke your function Hello
$./test.sh
Hello World
$
再來看一個帶有return語句的函數:
#!/bin/bash funWithReturn(){ echo "The function is to get the sum of two numbers..." echo -n "Input first number: " read aNum echo -n "Input another number: " read anotherNum echo "The two numbers are $aNum and $anotherNum !" return $(($aNum+$anotherNum)) } funWithReturn # Capture value returnd by last command ret=$? echo "The sum of two numbers is $ret !"
The function is to get the sum of two numbers... Input first number: 25 Input another number: 50 The two numbers are 25 and 50 ! The sum of two numbers is 75 !
再來看一個函數嵌套的例子:
#!/bin/bash # Calling one function from another number_one () { echo "Url_1 is http://see.xidian.edu.cn/cpp/shell/" number_two } number_two () { echo "Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/" } number_one
Url_1 is http://see.xidian.edu.cn/cpp/shell/ Url_2 is http://see.xidian.edu.cn/cpp/u/xitong/
$unset .f function_name
22. Shell函數參數
#!/bin/bash funWithParam(){ echo "The value of the first parameter is $1 !" echo "The value of the second parameter is $2 !" echo "The value of the tenth parameter is $10 !" echo "The value of the tenth parameter is ${10} !" echo "The value of the eleventh parameter is ${11} !" echo "The amount of the parameters is $# !" # 參數個數 echo "The string of the parameters is $* !" # 傳遞給函數的所有參數 } funWithParam 1 2 3 4 5 6 7 8 9 34 73
The value of the first parameter is 1 ! The value of the second parameter is 2 ! The value of the tenth parameter is 10 ! The value of the tenth parameter is 34 ! The value of the eleventh parameter is 73 ! The amount of the parameters is 12 ! The string of the parameters is 1 2 3 4 5 6 7 8 9 34 73 !"
另外,還有幾個特殊變量用來處理參數,前面已經提到:
特殊變量 | 說明 |
---|---|
$# | 傳遞給函數的參數個數。 |
$* | 顯示所有傳遞給函數的參數。 |
$@ | 與$*相同,但是略有區別,請查看Shell特殊變量。 |
$? | 函數的返回值。 |
23. 輸入輸出重定向
23.1 輸出重定向
命令的輸出不僅可以是顯示器,還可以很容易的轉移向到文件,這被稱為輸出重定向。命令輸出重定向的語法為:
$ command > file
例如,下面的命令在顯示器上不會看到任何輸出:
$ who > users
$ cat users oko tty01 Sep 12 07:30 ai tty15 Sep 12 13:32 ruth tty21 Sep 12 10:10 pat tty24 Sep 12 13:07 steve tty25 Sep 12 13:03 $
$ echo line 1 > users $ cat users line 1 $
$ echo line 2 >> users $ cat users line 1 line 2 $
23.2 輸入重定向
和輸出重定向一樣,Unix 命令也可以從文件獲取輸入,語法為:command < file
注意:輸出重定向是大於號(>),輸入重定向是小於號(<)。
例如,計算 users 文件中的行數,可以使用下面的命令:
$ wc -l users 2 users $
$ wc -l < users 2 $
23.3 重定向深入講解
一般情況下,每個 Unix/Linux 命令運行時都會打開三個文件:- 標准輸入文件(stdin):stdin的文件描述符為0,Unix程序默認從stdin讀取數據。
- 標准輸出文件(stdout):stdout 的文件描述符為1,Unix程序默認向stdout輸出數據。
- 標准錯誤文件(stderr):stderr的文件描述符為2,Unix程序會向stderr流中寫入錯誤信息。
如果希望 stderr 重定向到 file,可以這樣寫:
$command 2 > file
$command 2 >> file
如果希望將 stdout 和 stderr 合並后重定向到 file,可以這樣寫:
$command > file 2>&1
$command >> file 2>&1
$command < file1 >file2
命令 | 說明 |
---|---|
command > file | 將輸出重定向到 file。 |
command < file | 將輸入重定向到 file。 |
command >> file | 將輸出以追加的方式重定向到 file。 |
n > file | 將文件描述符為 n 的文件重定向到 file。 |
n >> file | 將文件描述符為 n 的文件以追加的方式重定向到 file。 |
n >& m | 將輸出文件 m 和 n 合並。 |
n <& m | 將輸入文件 m 和 n 合並。 |
<< tag | 將開始標記 tag 和結束標記 tag 之間的內容作為輸入。 |
Here Document
Here Document 目前沒有統一的翻譯,這里暫譯為”嵌入文檔“。Here Document 是 Shell 中的一種特殊的重定向方式,它的基本的形式如下:- command << delimiter
- document
- delimiter
注意:
- 結尾的delimiter 一定要頂格寫,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 縮進。
- 開始的delimiter前后的空格會被忽略掉。
$wc -l << EOF This is a simple lookup program for good (and bad) restaurants in Cape Town. EOF 3 $
#!/bin/bash cat << EOF This is a simple lookup program for good (and bad) restaurants in Cape Town. EOF
This is a simple lookup program for good (and bad) restaurants in Cape Town.
#!/bin/sh filename=test.txt vi $filename <<EndOfCommands i This file was created automatically from a shell script ^[ ZZ EndOfCommands
$ sh test.sh Vim: Warning: Input is not from a terminal $
$ cat test.txt This file was created automatically from a shell script $
/dev/null 文件
如果希望執行某個命令,但又不希望在屏幕上顯示輸出結果,那么可以將輸出重定向到 /dev/null:$ command > /dev/null
如果希望屏蔽 stdout 和 stderr,可以這樣寫:
$ command > /dev/null 2>&1
24. 文件包含
. filename
source filename
例如,創建兩個腳本,一個是被調用腳本 subscript.sh,內容如下:
url="http://see.xidian.edu.cn/cpp/view/2738.html"
#!/bin/bash . ./subscript.sh echo $url
$chomd +x main.sh ./main.sh http://see.xidian.edu.cn/cpp/view/2738.html $