判斷語句 if…then形式 類似於C/C++中的if-else語句。 單層if 命令格式: if condition then 語句1 語句2 ... fi 示例: a=3 b=4 if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ] then echo ${a}在範圍內 ...
判斷語句
if…then形式
- 類似於
C/C++
中的if-else
語句。
單層if
- 命令格式:
if condition
then
語句1
語句2
...
fi
- 示例:
a=3
b=4
if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ]
then
echo ${a}在範圍內
fi
- 輸出結果:
3在範圍內
單層if-else
- 命令格式
if condition
then
語句1
語句2
...
else
語句1
語句2
...
fi
- 示例:
a=3
b=4
if ! [ "$a" -lt "$b" ]
then
echo ${a}不小於${b}
else
echo ${a}小於${b}
fi
- 輸出結果:
3小於4
多層if-elif-elif-else
- 命令格式
if condition
then
語句1
語句2
...
elif condition
then
語句1
語句2
...
elif condition
then
語句1
語句2
else
語句1
語句2
...
fi
- 示例:
a=4
if [ $a -eq 1 ]
then
echo ${a}等於1
elif [ $a -eq 2 ]
then
echo ${a}等於2
elif [ $a -eq 3 ]
then
echo ${a}等於3
else
echo 其他
fi
- 輸出結果:
其他
case…esac形式
-
類似於
C/C++
中的switch
語句。 -
命令格式
case $變數名稱 in
值1)
語句1
語句2
...
;; # 類似於C/C++中的break
值2)
語句1
語句2
...
;;
*) # 類似於C/C++中的default
語句1
語句2
...
;;
esac
- 示例:
a=4
case $a in
1)
echo ${a}等於1
;;
2)
echo ${a}等於2
;;
3)
echo ${a}等於3
;;
*)
echo 其他
;;
esac
- 輸出結果:
其他
迴圈語句
for…in…do…done
- 命令格式:
for var in val1 val2 val3
do
語句1
語句2
...
done
- 示例1,輸出a 2 cc,每個元素一行:
for i in a 2 cc
do
echo $i
done
- 示例2,輸出當前路徑下的所有文件名,每個文件名一行:
for file in `ls`
do
echo $file
done
- 示例3,輸出1-10
for i in $(seq 1 10)
do
echo $i
done
- 示例4,使用{1..10} 或者
for i in {a..z}
do
echo $i
done
for ((…;…;…)) do…done
- 命令格式:
for ((expression; condition; expression))
do
語句1
語句2
done
- 示例,輸出1-10,每個數占一行:
for ((i=1; i<=10; i++))
do
echo $i
done
while…do…done迴圈
- 命令格式:
while condition
do
語句1
語句2
...
done
- 示例,文件結束符為Ctrl+d,輸入文件結束符後read指令返回false。
while read name
do
echo $name
done
until…do…done迴圈
-
當條件為真時結束。
-
命令格式:
until condition
do
語句1
語句2
...
done
- 示例,當用戶輸入yes或者YES時結束,否則一直等待讀入。
until [ "${word}" == "yes" ] || [ "${word}" == "YES" ]
do
read -p "Please input yes/YES to stop this program: " word
done
break命令
-
跳出當前一層迴圈,註意與C/C++不同的是:break不能跳出case語句。
-
示例
while read name
do
for ((i=1;i<=10;i++))
do
case $i in
8)
break
;;
*)
echo $i
;;
esac
done
done
- 該示例每讀入非EOF的字元串,會輸出一遍1-7。
- 該程式可以輸入Ctrl+d文件結束符來結束,也可以直接用Ctrl+c殺掉該進程。
continue命令
-
跳出當前迴圈。
-
示例:
for ((i=1;i<=10;i++))
do
if [ `expr $i % 2` -eq 0 ]
then
continue
fi
echo $i
done
- 該程式輸出1-10中的所有奇數。
死迴圈的處理方式
-
如果AC Terminal可以打開該程式,則輸入Ctrl+c即可。
-
否則可以直接關閉進程:
- 使用top命令找到進程的PID
- ps aux返回當前打開的所有進程
- 輸入kill -9 PID即可關掉此進程
函數
概述
-
bash中的函數類似於C/C++中的函數,但return的返回值與C/C++不同,返回的是exit code,取值為0-255,0表示正常結束。
-
如果想獲取函數的輸出結果,可以通過echo輸出到stdout中,然後通過$(function_name)來獲取stdout中的結果。
-
函數的return值可以通過$?來獲取。
-
命令格式:
[function] func_name() { # function關鍵字可以省略
語句1
語句2
...
}
不獲取 return值和stdout值
- 示例
func() {
name=yxc
echo "Hello $name"
}
func
- 輸出結果:
Hello yxc
獲取 return值和stdout值
-
不寫return時,預設return 0。
-
示例
func() {
name=yxc
echo "Hello $name"
return 123
}
output=$(func)
ret=$?
echo "output = $output"
echo "return = $ret"
- 輸出結果:
output = Hello yxc
return = 123
函數的輸入參數
-
在函數內,$1表示第一個輸入參數,$2表示第二個輸入參數,依此類推。
-
註意:函數內的$0仍然是文件名,而不是函數名。
-
示例:
func() { # 遞歸計算 $1 + ($1 - 1) + ($1 - 2) + ... + 0
word=""
while [ "${word}" != 'y' ] && [ "${word}" != 'n' ]
do
read -p "要進入func($1)函數嗎?請輸入y/n:" word
done
if [ "$word" == 'n' ]
then
echo 0
return 0
fi
if [ $1 -le 0 ]
then
echo 0
return 0
fi
# $()會讀取函數的stdout而不直接輸出出來
sum=$(func $(expr $1 - 1))
# 只在最後一層輸出函數的stdout
echo $(expr $sum + $1)
}
echo $(func 10)
- 輸出結果:
55
函數內的局部變數
-
可以在函數內定義局部變數,作用範圍僅在當前函數內。
-
可以在遞歸函數中定義局部變數。
-
命令格式:
local 變數名=變數值
- 例如:
#! /bin/bash
func() {
local name=yxc
echo $name
}
func
echo $name
- 輸出結果:
yxc
- 第一行為函數內的name變數,第二行為函數外調用name變數,會發現此時該變數不存在。
exit命令
-
exit命令用來退出當前shell進程,並返回一個退出狀態;使用$?可以接收這個退出狀態。
- return和exit的共同之處都是返回exit code
- 區別是return結束當前函數,exit結束整個shell腳本
-
exit命令可以接受一個整數值作為參數,代表退出狀態。如果不指定,預設狀態值是 0。
-
exit退出狀態只能是一個介於 0~255 之間的整數,其中只有 0 表示成功,其它值都表示失敗。
-
示例:
-
創建腳本test.sh,內容如下:
#! /bin/bash
if [ $# -ne 1 ] # 如果傳入參數個數等於1,則正常退出;否則非正常退出。
then
echo "arguments not valid"
exit 1
else
echo "arguments valid"
exit 0
fi
- 執行該腳本:
acs@9e0ebfcd82d7:~$ chmod +x test.sh
acs@9e0ebfcd82d7:~$ ./test.sh acwing
arguments valid
acs@9e0ebfcd82d7:~$ echo $? # 傳入一個參數,則正常退出,exit code為0
0
acs@9e0ebfcd82d7:~$ ./test.sh
arguments not valid
acs@9e0ebfcd82d7:~$ echo $? # 傳入參數個數不是1,則非正常退出,exit code為1
1
文件重定向
概述
-
每個進程預設打開3個文件描述符:
- stdin標準輸入,從命令行讀取數據,文件描述符為0
- stdout標準輸出,向命令行輸出數據,文件描述符為1
- stderr標準錯誤輸出,向命令行輸出數據,文件描述符為2
-
可以用文件重定向將這三個文件重定向到其他文件中。
重定向命令列表
命令 | 說明 |
---|---|
command > file | 將stdout重定向到file中 |
command < file | 將stdin重定向到file中 |
command >> file | 將stdout以追加方式重定向到file中 |
command n> file | 將文件描述符n重定向到file中 |
command n>> file | 將文件描述符n以追加方式重定向到file中 |
輸入和輸出重定向
# ls -l > 文件 (列表的內容寫入文件a.txt中 覆蓋寫)
# ls -al >> 文件 (列表的內容文件追加到文件aa.txt的末尾)
# cat 文件1 > 文件2 (將文件1的內容覆蓋到文件2)
# echo "內容" >> 文件 (將echo的內容追加到文件末尾)
echo -e "Hello \c" > output.txt # 將stdout重定向到output.txt中
echo "World" >> output.txt # 將字元串追加到output.txt中
read str < output.txt # 從output.txt中讀取字元串
echo $str # 輸出結果:Hello World
同時重定向stdin和stdout
- 創建bash腳本:
#! /bin/bash
read a
read b
echo $(expr "$a" + "$b")
- 創建input.txt,裡面的內容為:
3
4
- 執行命令:
acs@9e0ebfcd82d7:~$ chmod +x test.sh # 添加可執行許可權
acs@9e0ebfcd82d7:~$ ./test.sh < input.txt > output.txt # 從input.txt中讀取內容,將輸出寫入output.txt中
acs@9e0ebfcd82d7:~$ cat output.txt # 查看output.txt中的內容
7
引入外部腳本
概述
-
類似於C/C++中的include操作,bash也可以引入其他文件中的代碼。
-
語法格式:
. filename # 註意點和文件名之間有一個空格
或
source filename
# 引入的文件可以添加路徑,比如使用絕對路徑
source /home/acs/test1.sh
示例
- 創建test1.sh,內容為:
#! /bin/bash
name=yxc # 定義變數name
- 然後創建test2.sh,內容為:
#! /bin/bash
source test1.sh # 或 . test1.sh
echo My name is: $name # 可以使用test1.sh中的變數
- 執行命令:
acs@9e0ebfcd82d7:~$ chmod +x test2.sh
acs@9e0ebfcd82d7:~$ ./test2.sh
My name is: yxc