Unit: 3.5
Link: https://lgwain.gitbooks.io/os/unit35.html
HomeWork: https://lgwain.gitbooks.io/os/lx3b.html
Shell腳本是什麼?
通俗的解釋就是一堆Linux命令的邏輯化處理。
爲什麼要編寫Shell腳本?
在做開發的時候,有的時候需要部署環境或者是打包發佈,往往都需要在終端裏敲好多的命令才能做一件事,但是如果每次部署都要敲一堆命令,那麼效率是非常低的,也會使人感到煩躁。所以,我們可以編寫Shell腳本,將要執行的命令寫在一起,用的時候只需要運行一下腳本就一切都搞定了。
從第一行開始!
爲了確保Shell腳本可以正常運行,請將下面一行代碼寫在Shell腳本的第一行:
#!/bin/bash
確保了腳本總是運行在bash中。
如何執行Shell腳本?
首先我們先新建一個簡單的Shell腳本,讓它輸出 Hello World!
。
$ touch t.sh
$ vi t.sh
# Coding...
$ cat t.sh
#!/bin/bash
echo Hello World!
(一)使用 bash ScriptName
執行Shell腳本:只需要對腳本有讀的權限(chmod 444 ./t.sh
)
$ bash t.sh
Hello World!
(二)像運行命令一樣 ./ScriptName
執行Shell腳本:需要對腳本有執行權限(chmod 555 ./t.sh
)
$ ./t.sh
Hello World!
(三)使用命令 source ScriptName
運行Shell腳本:同樣要對腳本有執行權限
和前兩種執行方式不同的是,前兩種方式是在當前Shell中創建了一個子進程來執行相應的腳本,不會對父進程有影響,而命令 source
會在當前的Shell中執行相應的腳本,直接影響當前的進程。
$ source t.sh
Hello World!
只輸出 Hello World!
看不出來效果,我們在腳本文件中加入一行切換目錄的命令:
#!/bin/bash
cd ../
echo Hello World!
分別使用第二種和第三種方式執行,看效果:
$ pwd
/Users/yuchunyu97/Projects/www/Homework/os04/src/script
# 第二種
$ ./t.sh
Hello World!
$ pwd
/Users/yuchunyu97/Projects/www/Homework/os04/src/script
# 第三種
$ source t.sh
Hello World!
$ pwd
/Users/yuchunyu97/Projects/www/Homework/os04/src
pwd
命令可以顯示當前所在的目錄。
可以看出來第二種方式執行切換目錄的命令並沒有對當前的目錄產生影響,而第三種方式使當前目錄返回了上一級目錄。
在終端輸出 echo
、讀取用戶輸入 read
# echo 命令介紹
$ cat t.sh
#!/bin/bash
# 輸出字符串
echo "Hello World"
# 輸出字符串也可以不加雙引號
echo Hello World
# 輸出雙引號 "
echo \"Hello World\"
# echo命令默認換行,使用 -n 可以設置不換行
echo -n Please Input Something:
# 讀取用戶輸入,並存入變量
read line
# 輸出存在變量裏的字符串
echo "Get It: $line"
# 使用單引號 ' 可以將變量輸出成字符串
echo 'It is not a variable $line'
# 使用反引號 ` 執行命令
echo Current Time: `date`
# 使用大於號 > 將輸出重定向到文件
echo This line is in a file > t.tmp
$ ./t.sh
Hello World
Hello World
"Hello World"
Please Input Something:Hi Shell Script
Get It: Hi Shell Script
It is not a variable $line
Current Time: 2017年11月 3日 星期五 15時33分52秒 CST
$ ls
t.sh t.tmp
$ cat t.tmp
This line is in a file
關於 echo
的詳細介紹:Shell命令:echo 命令詳解
# read 命令介紹
$ cat t.sh
#!/bin/bash
# -p 顯示提示信息,並且不換行
# 可以同時接受多個值,以空格分隔
read -p "Enter your name and age separated by Space: " name age
echo "Hi, $name. Your age is $age"
# -t 限制用戶的輸入時間
read -t 5 -p "You have 5 Seconds to input: " line
echo -e "\nYour input is: $line"
# -s 可以不顯示用戶的輸入
read -s -p "Enter Password: " passwd
echo -e "\nYour password is: $passwd"
$ ./t.sh
Enter your name and age separated by Space: Yuchunyu 20
Hi, Yuchunyu. Your age is 20
You have 5 Seconds to input:
Your input is:
Enter Password:
Your password is: MyPassword
測試/判斷命令 test
在Linux中執行判斷時,如果正確則返回
0
,如果錯誤則返回1
。
$?
臨時存儲當前判斷的結果。
語法:
test expression or [ expression ] or [[ expression ]]
使用表達式來測試文件狀態:
-f <file> 是否爲文件
-d <file> 是否爲目錄
-r <file> 是否有讀權限
-w <file> 是否有寫權限
-x <file> 是否有執行權限
-s <file> 是否有非零大小
例:
$ chmod 444 t.tmp
$ ls -l t.tmp
-r--r--r-- 1 yuchunyu97 staff 23 11 3 15:39 t.tmp
$ cat t.sh
#!/bin/bash
test -f t.tmp
echo Is an ordinary file? $?
test -d t.tmp
echo Is a directory? $?
test -r t.tmp
echo Is Readable? $?
test -w t.tmp
echo Is Writable? $?
test -x t.tmp
echo Is Executable? $?
test -s t.tmp
echo Has Non-Zero Length? $?
$ ./t.sh
Is an ordinary file? 0
Is a directory? 1
Is Readable? 0
Is Writable? 1
Is Executable? 1
Has Non-Zero Length? 0
# 0 表示有
# 1 表示無
字符串測試:
-n <string> 字符串是否不爲空
-z <string> 字符串是否爲空
<string> == <string> 字符串是否相等
<string> != <string> 字符串是否不相等
例:
$ cat t.sh
#!/bin/bash
test -n ""
echo Empty String is not empty? $?
test -z ""
echo Empty String is empty? $?
test "str" == "str1"
echo \"str\" and \"str1\" are equal? $?
test "str" != "str1"
echo \"str\" and \"str1\" are not equal? $?
$ ./t.sh
Empty String is not empty? 1
Empty String is empty? 0
"str" and "str1" are equal? 1
"str" and "str1" are not equal? 0
算數測試:
<value> -eq <value> 是否相等
<value> -ne <value> 是否不相等
<value> -lt <value> 是否小於
<value> -le <value> 是否小於等於
<value> -gt <value> 是否大於
<value> -ge <value> 是否大於等於
例:
$ cat t.sh
#!/bin/bash
test 1 -eq 2
echo 1 equals 2? $?
test 1 -ne 2
echo 1 not equals 2? $?
test 7 -lt 7
echo 7 less than 7? $?
test 7 -le 7
echo 7 less than or equal 7? $?
test 7 -gt 6
echo 7 greater than 6? $?
test 7 -ge 6
echo 7 greater than or equal 6? $?
$ ./t.sh
1 equals 2? 1
1 not equals 2? 0
7 less than 7? 1
7 less than or equal 7? 0
7 greater than 6? 0
7 greater than or equal 6? 0
&& 和 ||
可以用於有條件的執行命令。
command1 && command2
如果command1成立,再執行command2
command1 || command2
如果command1不成立,再執行command2
例:
# 查看當前目錄,有文件 t.tmp
$ ls
t.sh t.tmp
# 如果有 t.tmp,就刪除
# 如果沒有 e.file,就新建一個 e.file
$ cat t.sh
#!/bin/bash
(test -f t.tmp) && rm -f t.tmp
(test -f e.file) || touch e.file
# 執行腳本
$ ./t.sh
# 查看當前目錄, t.tmp被刪除了,新建了一個 e.file
$ ls
e.file t.sh
if
命令
語法:
if [ status(true) ]
then
process
elif [ status(true) ]
then
process
else
process
fi
注: if
和 elif
後面的空格不能省略,還有後面的 [ status ]
中,status兩邊的空格也不能省略。別忘了在最後加 fi
。
例:
$ cat t.sh
#!/bin/bash
read -p "Please input a number: " num
if [ $num -lt 10 ]
then
echo $num is less than 10
elif [ $num -gt 10 ]
then
echo $num is greater than 10
else
echo $num is equal to 10
fi
$ ./t.sh
Please input a number: 2
2 is less than 10
$ ./t.sh
Please input a number: 12
12 is greater than 10
$ ./t.sh
Please input a number: 10
10 is equal to 10
case
命令
語法:
case $var in
pattern1) command1 ;;
pattern2) command2 ;;
*) command3 ;;
esac
注:每一個 pattern
後面有兩個分號 ;;
,最後要加 esac
。
例:
$ cat t.sh
#!/bin/bash
read -p "Please input \"yes\" or \"no\": " var
case $var in
[Yy][Ee][Ss])
echo Your input is YES;;
[Nn][Oo])
echo Your input is NO;;
*)
echo Input Error;;
esac
$ ./t.sh
Please input "yes" or "no": Yes
Your input is YES
$ ./t.sh
Please input "yes" or "no": no
Your input is NO
$ ./t.sh
Please input "yes" or "no": hello
Input Error
while
命令
語法:
while staues(true)
do
commands
[break]
[continue]
done
例:
$ cat t.sh
#!/bin/bash
guess=37
while true
do
read -p "Please input a number to guess: " num
if [ $num -eq $guess ]
then
echo Bingo! It\'s $num
break
elif [ $num -lt $guess ]
then
echo Please guess a bigger number.
continue
elif [ $num -gt $guess ]
then
echo Please guess a smaller number.
continue
fi
done
$ ./t.sh
Please input a number to guess: 30
Please guess a bigger number.
Please input a number to guess: 40
Please guess a smaller number.
Please input a number to guess: 35
Please guess a bigger number.
Please input a number to guess: 37
Bingo! It's 37
注:Shell腳本中給變量賦值時,等號 =
兩邊不能有空格。
for
命令
語法:
for identifier in list
do
commands to be executed on $identifier
done
例:
$ cat t.sh
#!/bin/bash
for i in {1..10}
do
echo $i
done
$ ./t.sh
1
2
3
4
5
6
7
8
9
10
$ cat t.sh
#!/bin/bash
for i in 1 2 3 0 6
do
echo $i
done
$ ./t.sh
1
2
3
0
6
$ cat t.sh
#!/bin/bash
for i in cat dog pig
do
echo $i
done
$ ./t.sh
cat
dog
pig
$ cat t.sh
#!/bin/bash
for i in `ls ../`
do
echo $i
done
$ ./t.sh
a.out
script
sh.c
Shell腳本的參數
在命令行上的參數傳遞給Shell腳本,被存在了特殊的變量裏。
語法:
$1, $2, $3 ... 依次代表傳給Shell腳本的參數
$@ 代表 "$1" "$2" "$3"
$* 代表 "$1 $2 $3"
$# 儲存參數的個數
例:
$ cat t.sh
#!/bin/bash
echo First parameter: $1
echo Second parameter: $2
echo Number of parameters: $#
echo $@
echo $*
$ ./t.sh one two three four five
First parameter: one
Second parameter: two
Number of parameters: 5
one two three four five
one two three four five
shift
命令:位置參數可以用 shift
命令左移。比如 shift 3
表示原來的 $4
現在變成 $1
,原來的 $5
現在變成 $2
等等,原來的 $1
、 $2
、 $3
丟棄, $0
不移動。不帶參數的 shift
命令相當於 shift 1
。
例:
$ cat t.sh
#!/bin/bash
while [ $# -gt 0 ]
do
echo 第一個參數爲:$1
shift
done
$ ./t.sh 1 2 3 4 5
第一個參數爲:1
第一個參數爲:2
第一個參數爲:3
第一個參數爲:4
第一個參數爲:5
這個命令可以讓我們逐個的處理命令行參數。
算數相關的命令
可以使用 let
或者 $(( expr ))
來執行算數運算。
例:
$ cat t.sh
#!/bin/bash
let x=7+8
echo $x
echo $(( (6 + 8)*9 ))
$ ./t.sh
15
126
也可以使用命令 expr
。不過這個比前兩個慢很多。注意使用 (
、 )
、*
的時候需要轉義。
$ echo `expr 3 + 5`
8
$ expr 3 * ( 3 + 5 )
zsh: unknown file attribute:
# ( 、)、* 需要轉義
$ expr 3 \* \( 3 + 5 \)
24
函數
語法:
function func_name() {
statements
[return]
}
例:
$ cat t.sh
#!/bin/bash
function show() {
echo "hello , $1"
}
show world
$ ./t.sh
hello , world