Shell腳本的超詳細講解(推薦!)
一、Shell腳本基礎概念
1.1 什么是shell?
shell英文翻譯過來是外殼的意思,作為計算機語言來理解可以認為它是操作系統(tǒng)的外殼。我們可以通過shell命令來操作和控制操作系統(tǒng),比如Linux中的shell命令就包括ls、cd、pwd等等。
shell是站在內核的基礎上編寫的一個應用程序,它連接了用戶和Linux內核,從而讓用戶能夠更加便捷、高效、安全的使用linux內核,這其實就是shell的本質。
使用專業(yè)術語的說法來解釋,Shell其實是一個命令解釋器,它通過接受用戶輸入的Shell命令來啟動、暫停、停止程序的運行或對計算機進行控制。
1.2 什么是shell腳本
shell腳本就是由Shell命令組成的執(zhí)行文件,將一些命令整合到一個文件中,進行處理業(yè)務邏輯,腳本不用編譯即可運行。它通過解釋器解釋運行,所以速度相對來說比較慢。
1.3 shell腳本的意義
我們在1.2中也解釋道shell腳本其實就是shell命令組成的文件,shell腳本可以記錄命令執(zhí)行的過程和執(zhí)行邏輯,以便以后重復執(zhí)行,還可以批量、定時處理主機,方便管理員進行設置或者管理。
二、創(chuàng)建一個簡單的Shell腳本
2.1 創(chuàng)建一個shell腳本文件
在創(chuàng)建shell腳本時,我們默認新建一個以.sh/.script結尾的文件,主要是為了讓程序員更加快捷的辨認出該文件是一個shell腳本文件。
我們創(chuàng)建一個test.sh的shell腳本文件,其中具體內容為下:
#!/bin/bash echo hello
- " # ”開頭的就是注釋,單行注釋
- <<EOF … EOF 或 :<<! … ! :多行注釋
- #!/bin/bash : 主要用于指定解釋器
- Linux中提供的shell解釋器有:
- /bin/sh
- /bin/bash
- /usr/bin/sh
- /usr/bin/bash
2.2 運行一個Shell腳本
我們根據腳本文件是否具有可執(zhí)行權限,將運行一個shell腳本的方法分為兩大類。
2.2.1 腳本文件無執(zhí)行權限
這種情況下我們有三種方式來運行腳本:
手動在環(huán)境中開啟指定解釋器:sh test.sh

直接在當前環(huán)境中運行的shell中運行腳本:. test.sh

直接在當前環(huán)境中運行的shell中運行腳本:source test.sh

2.2.2 腳本文件有執(zhí)行權限
在這一部分由于我們假設腳本文件有可執(zhí)行器權限,所以我們使用chmod +x test.sh為我們的test.sh文件增加了可執(zhí)行權限。
我們知道當一個文件具有可執(zhí)行權限時我們可以使用該文件的路徑名直接運行該文件,有兩種方式可以運行腳本:
1.絕對路徑名運行腳本文件
絕對路徑就是從根目錄下開始記錄文件路徑名,是文件在計算機上真正存在的路徑。(如果不知道你的文件路徑名,可以在當前位置的shell中使用pwd查詢當前所在位置)

2../相對路徑名的格式運行腳本文件
相對路徑是指以當前的文件作為起點,相較于當前目錄的位置而被指向并且加以引用的文件資源。
比如我們知道test.sh文件的絕對路徑為/home/westos/Desktop/textcpp/test.sh,那么當我們在testcpp文件夾中時,test.sh文件的相對路徑為test.sh。
又因為.代表當前所在位置,故而為其實./test.sh其實就是該文件的絕對路徑,只是表示的方式不同。

三、基本語法
3.1 變量
變量名其實就是一片內存區(qū)域的地址或者可以說是尋址符號,有了變量我們就可以使用一串固定的字符來表示不固定的目標。
3.1.1 變量類型
在shell中會同時存在三種類型變量。
- 局部變量:局部變量在腳本或命令中定義,僅在當前shell實例中有效,其他shell啟動的程序不能訪問局部變量。
- 環(huán)境變量:所有的程序,包括shell啟動的程序,都能訪問環(huán)境變量,有些程序需要環(huán)境變量來保證其正常運行。必要的時候shell腳本也可以定義環(huán)境變量。
- shell變量:shell變量是由shell程序設置的特殊變量。shell變量中有一部分是環(huán)境變量,有一部分是局部變量,這些變量保證了shell的正常運行
3.1.2 變量操作
- 創(chuàng)建普通變量:name=“test”,組要注意的是等號兩邊不能有空格。
- 創(chuàng)建局部變量:local name=“test”,使用local修飾的變量在函數體外無法訪問,只能在函數體中使用。
- 創(chuàng)建只讀變量:name=“only_read” -> readonly name,這種變量不可以被修改。
- 使用變量:echo $name或者echo ${name}
- 刪除變量:unset name,刪除之后的變量無法被訪問,需要注意無法刪除只讀變量。
3.1.3 字符串變量
3.1.3.1 字符串變量的創(chuàng)建
- 使用單引號創(chuàng)建:var='test'。
這種方式創(chuàng)建的變量只能原樣輸出,變量無效,我們可以借用c中的“字符串常量”的定義理解這種特性。除此以外,單引號中不能出現單獨的單引號,轉義也是不可以的。 - 使用雙引號創(chuàng)建:var="my name is ${name}",這種方式創(chuàng)建的字符串變量有效,也可以出現轉義符。
3.1.3.2 拼接字符串
- 字面量拼接
str01="1""2"或者str01="1"'2',這樣就將1和2兩個字符拼接在了一起。需要注意的是兩個串之間不可以有空格。 - 變量拼接
str03=${part01}${part02}或str04=${part01}"end"或str05="${part01} ${part02}"這三種方式都可以拼接字符串變量。 - 命令拼接
str02= date“end”,這里的date是一個shell命令,需要使用引用,具體如下:
str02=`date`"end"
3.1.3.3 獲取字符串長度
1.使用wc -L命令
wc -L可以獲取到當前行的長度,因此對于單獨行的字符串可以用這個簡單的方法獲取,另外wc -l則是獲取當前字符串內容的行數。
echo "abc" |wc -L
2.使用expr length可以獲取string的長度
expr length ${<!--{C}%3C!%2D%2D%20%2D%2D%3E-->str}3.awk獲取域的個數
但是如果大于10個字符的長度時是否存在問題需要后面確認
echo "abc" |awk -F "" '{print NF}'4.通過awk+length的方式獲取字符串長度
echo “Alex”|awk '{print length($0)}'5.通過echo ${#name}的方式
name=Alex
echo ${#name}
3.1.3.4 提取子字符串
1.如下方式:
| 代碼 | 意義 |
|---|---|
| ${varible##*string} | 從左向右截取最后一個string后的字符串 |
| ${varible#*string} | 從左向右截取第一個string后的字符串 |
| ${varible%%string*} | 從右向左截取最后一個string后的字符串 |
| ${varible%string*} | 從右向左截取第一個string后的字符串 |
例,如下代碼:
$ MYVAR=foodforthought.jpg
$ echo ${MYVAR##*fo}
運行結果為rthought.jpg
2.使用${varible:n1:n2}
截取變量varible從n1到n2之間的字符串,可以根據特定字符偏移和長度,來選擇特定子字符串,如下代碼:
$ EXCLAIM=cowabunga
$ echo ${EXCLAIM:0:3}
運行結果最終顯示cow。
3.1.4 數組
如果說變量是存儲單個變量的內存空間,那么數組就是多個變量的集合,它存儲多個元素在一片連續(xù)的內存空間中。在bash中,只支持一維數組,不支持多維數組。
3.1.3.1 數組定義與引用
定義一個數組方式如下:
數組名=(元素1 元素2 元素3 ... 元素n)
指定數組對應下標的元素進行賦值:
數組名[下標]=值
同時指定多個數組元素進行賦值:
數組名=([下標1]=值1 [下標2]=值2 ... [下標n]=值n)
引用數組對應下標的元素:
${數組名[下標]}
3.1.3.2 遍歷數組元素
使用for(或while循環(huán))循環(huán)遍歷數組元素:
#!/bin/bash
a=(1 2 3 4 5 6)
for((i=0; i<10; i++))
do
echo "a[$i]=${a[$i]}"
done
除此以外我們還可以使用${a[*]}或者${a[@]}來遍歷數組元素,具體代碼如下:
#!/bin/bash
a=(1 2 3 4 5 6)
echo ${a[*]}
echo ${a[@]}3.1.3.3 獲取數組長度
我們可以使用#來獲取數組長度,需要注意的是在shell腳本中我們越界訪問數組時是不會報錯的。
#!/bin/bash
a=(1 2 3 4 5 6)
echo ${a[*]}
echo "a len: ${#a[*]}"
我們先使用其獲取數組中的元素后使用#獲取元素個數即可。
3.1.3.4 合并數組
我們可以如下進行拼接:
#!/bin/bash
a=(1 2 3 4 5 6)
b=("hello" "zhaixue.cc")
c=(${a[*]} ${b[*]})
這樣我們就將兩個數組拼接起來了。
3.1.3.5 刪除數組元素
如果我們想要刪除某個數組元素,具體代碼如下:
#!/bin/bash
a=(1 2 3 4 5 6)
echo ${a[*]}
echo "a len: ${#a[*]}"
unset a[5]
echo ${a[*]}
echo "a len: ${#a[*]}"
執(zhí)行結果如下:

我們如果要刪除整個數組,可以執(zhí)行unset a,舉例代碼如下:
#!/bin/bash
a=(1 2 3 4 5 6)
echo ${a[*]}
echo "a len: ${#a[*]}"
unset a
echo ${a[*]}
echo "a len: ${#a[*]}"
3.1.5 變量傳參
相關的變量含義為:
| 變量 | 含義 |
|---|---|
| $0 | 代表執(zhí)行的文件名 |
| $1 | 代表傳入的第1個參數 |
| $n | 代表傳入的第n個參數 |
| $# | 參數個數 |
| $* | 以一個單字符串顯示所有向腳本傳遞的參數。 |
| $@ | 與$*相同,但是使用時加引號,并在引號中返回每個參數 |
| $$ | 腳本運行的當前進程號 |
| $! | 后臺運行的最后一個進程的ID |
| $? | 顯示最后命令的退出狀態(tài)。0表示沒有錯誤,其他任何值表明有錯誤。 |
3.2 運算符
原生的bash并不支持簡單的數學運算,通常要通過其它命令來實現。
3.2.1 算數運算符
以下表格中的a和b都是變量。
| 運算 | shell中格式 |
|---|---|
| 加法 | expr $a + $b |
| 減法 | expr $a - $b |
| 乘法 | expr $a \* $b |
| 除法 | expr $b / $a |
| 取余 | expr $b % $a |
| 賦值 | a=$b |
| 相等 | [ $a == $b ] |
| 不相等 | [ $a != $b ] |
需注意:
條件表法式需要放在方括號之間,并且要有空格。使用expr進行計算時需要使用反引號,為了讓讀者更容易理解,給出下列示例代碼。
#!/bin/bash a=10 b=20 val=`expr $a + $b` echo "a + b : $val"
3.2.2 關系運算符
關系運算符只支持數字,不支持字符串,除非字符串的值是數字。
| 運算 | shell中的實現 | 主要符號 |
|---|---|---|
| 檢測兩個數是否相等 | [ $a -eq $b ] | -eq |
| 檢測兩個數是否不相等 | [ $a -ne $b ] | -ne |
| 檢測左邊的數是否大于右邊的 | [ $a -gt $b ] | -gt |
| 檢測左邊的數是否小于右邊的 | [ $a -lt $b ] | -lt |
| 檢測左邊的數是否大于等于右邊的 | [ $a -ge $b ] | -ge |
| 檢測左邊的數是否小于等于右邊的 | [ $a -le $b ] | -le |
舉例代碼如下:
#!/bin/bash a=1 b=2 if [ $a != $b ] then echo "$a != $b : a 不等于 b" else echo "$a == $b: a 等于 b"
執(zhí)行結果如下:

3.2.3 布爾運算符
具體如下:
| 運算 | shell中的實現 | 主要符號 |
|---|---|---|
| 非運算 | [ ! false ] | ! |
| 或運算 | [ $a -lt 20 -o $b -gt 100 ] | -o |
| 與運算 | [ $a -lt 20 -a $b -gt 100 ] | -a |
3.2.4 邏輯運算符
具體如下:
| 運算 | shell中的實現 | 主要符號 |
|---|---|---|
| 邏輯的 AND | [[ $a -lt 100 && $b -gt 100 ]] | && |
| 邏輯的 OR | [[ $a -lt 100 || $b -gt 100 ]] | || |
布爾運算符和邏輯運算符的區(qū)別:
語法上,邏輯運算需要雙括弧,布爾運算只需要單大括弧功能上,邏輯運算具有特殊的短路功能,即是在AND運算中第一個表達式為false時則不執(zhí)行第二個表達式,在OR運算中第一個表達式為true時不執(zhí)行第二個表達式。
3.2.5 字符串運算符
下表列出了常用的字符串運算符:
| 運算 | shell中的實現 | 主要符號 |
|---|---|---|
| 檢測兩個字符串是否相等 | [ $a = $b ] | = |
| 檢測兩個字符串是否不相等 | [ $a != $b ] | != |
| 檢測字符串長度是否為0 | [ -z $a ] | -z |
| 檢測字符串長度是否不為 0 | [ -n “$a” ] | -n |
| 檢測字符串是否為空 | [ $a ] | $ |
3.2.6 文件測試運算符
主要用于檢測unix文件的各種屬性:
| 運算 | shell中的實現 | 主要符號 |
|---|---|---|
| 檢測文件是否是塊設備文件 | [ -b $file ] | -b file |
| 檢測文件是否是字符設備文件 | [ -c $file ] | -c file |
| 檢測文件是否是目錄 | [ -d $file ] | -d file |
| 檢測文件是否是普通文件(既不是目錄,也不是設備文件) | [ -f $file ] 返回 true | -f file |
| 檢測文件是否設置了 SGID 位 | [ -g $file ] | -g file |
| 檢測文件是否設置了粘著位(Sticky Bit) | [ -k $file ] | -k file |
| 檢測文件是否是有名管道 | [ -p $file ] | -p file |
| 檢測文件是否設置了 SUID 位 | [ -u $file ] | -u file |
| 檢測文件是否可讀 | [ -r $file ] | -r file |
| 檢測文件是否可寫 | [ -w $file ] | -w file |
| 檢測文件是否可執(zhí)行 | [ -x $file ] | -x file |
| 檢測文件是否為空(文件大小是否大于0) | [ -s $file ] | -s file |
| 檢測文件(包括目錄)是否存在 | [ -e $file ] | -e file |
舉例如下:
#!/bin/bash file="/home/westos/Desktop/textcpp/test.sh" if [ -r $file ] then echo "文件可讀" else echo "文件不可讀" fi
執(zhí)行結果為:

3.2.7 運算指令
1.(( ))
我們可以直接使用雙圓括弧計算其中的內容,如((var=a+b)),該指令經常在if/while等條件判斷中需要計算時使用。
2.let
在計算表達式的時候我們可以直接使用let,如let var=a+b。
3.expr
在前面的內容中我們也提到了它,是非常常用的計算指令,使用時需要在外部增反引號
var=`expr a+b`
4.bc計算器
bc計算器支持shell中的小數進行運算,并且可以交互式或者非交互式的使用?;臼褂梅绞綖?code>var=$(echo "(1.1+2.1)"|bc);
5.$[]
我們可以直接使用這種方式計算中括弧中的內容,如echo $[1+2]
3.3 控制語句
和其他語句不同,shell的流傳呢個控制不可為空。接下來我們?yōu)榇蠹医榻Bsehll中常用的語法。
3.3.1 if語句結構
3.3.1.1 if-fi
就類似于c中的if條件判斷,如下:
if condition
then
command1
command2
...
commandN
fi
3.3.1.2 if-else-fi
代碼如下:
if condition
then
command1
else
command2
fi
若condition成立則執(zhí)行command1,否則執(zhí)行command2。
3.3.1.3 if else-if else
代碼如下:
if condition1
then
command1
elif condition2
then
command2
else
command3
fi
若condition1成立,執(zhí)行command1,若condition1不成立,condition2成立執(zhí)行command2,若兩個condition都不成立就執(zhí)行command3。
3.3.2 循環(huán)結構
3.3.2.1 for循環(huán)
格式為:
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
以上也可以寫做一行,若變量var在列表中,則for循環(huán)執(zhí)行一次所有命令。以以下代碼作為測試:
#!/bin/bash
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
執(zhí)行結果為:

3.3.2.2 while循環(huán)
格式如下:
while condition
do
command
done
我們運行如下代碼:
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
執(zhí)行的最終結果為:

3.3.2.3 無限循環(huán)
我們可以以上兩種語句給出無限循環(huán)的實現,首先看一下for循環(huán)如何實現:
for (( ; ; ))
除此以外我們也可以使用while循環(huán)實現如下:
while :
do
command
done
或者直接將while中的判斷語句置為真:
while true
do
command
done
3.3.2.4 until循環(huán)
until 循環(huán)執(zhí)行一系列命令直至條件為 true 時停止。語法格式如下:
until condition
do
command
done
3.3.2.5 跳出循環(huán)
在循環(huán)過程中,有時候需要在未達到循環(huán)結束條件時強制跳出循環(huán),Shell使用兩個命令來實現該功能:break和continue。
1.break跳出循環(huán)
當我們需要跳出當前循環(huán),或者終止死循環(huán)時,我們就可以使用break來跳出循環(huán)。接下來我們運行如下代碼:
#!/bin/bash
var=1
while(( $var < 5 ))
do
if(( $var>3 ))
then
echo "跳出循環(huán)"
break
fi
echo "$var"
var=`expr $var + 1`
done執(zhí)行結果為:

在該循環(huán)中var>3時break,而是直接跳出循環(huán)。
2.continue跳出循環(huán)
continue命令與break命令類似,只有一點差別,它不會跳出所有循環(huán),僅僅跳出當前循環(huán)。 接下來我們運行如下代碼:
#!/bin/bash
var=1
while(( $var < 5 ))
do
if(( $var>3 ))
then
echo "跳出循環(huán)"
continue
fi
echo "$var"
var=`expr $var + 1`
done
執(zhí)行結果為:

使用continue跳出的循環(huán)只是當前循環(huán),無法跳出整個循環(huán),由于在該代碼中我們每次執(zhí)行到continue就會跳出當前循環(huán),無法執(zhí)行 var=expr $var + 1,所以循環(huán)條件一直成立,就成了死循環(huán)。
3.3.3 case-esac多選擇語句
case ... esac 為多選擇語句,與其他語言中的switch ... case 語句類似,是一種多分支選擇結構,每個 case 分支用右圓括號開始,用兩個分號 ;;表示 break,即執(zhí)行結束,跳出整個 case … esac 語句,esac(就是 case 反過來)作為結束標記。
case 要求取值后面必須為單詞 in,每一模式必須以右括號結束。取值可以為變量或常數,匹配發(fā)現取值符合某一模式后,其間所有命令開始執(zhí)行直至 ;;。
若檢測匹配時無一匹配,使用*捕獲該值,再執(zhí)行后續(xù)命令。
語法格式如下:
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
*)
command1
esac
3.3.3 select-in語句
select in是shell中獨有的一種循環(huán),非常適合終端的交互場景,它可以顯示出帶編號的菜單,用戶出入不同編號就可以選擇不同的菜單,并執(zhí)行不同的功能。
語法格式如下:
select var in seq
do
action
done
我們執(zhí)行如下代碼:
#!/bin/bash echo "What is your favourite OS?" select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do break; done echo "You have selected $var"
執(zhí)行結果為:

四、函數
函數其實就是將一段代碼組合封裝在一起實現某個特定的功能或返回某個特定的值。我們在定義函數時需要先起一個函數名,在使用的時候直接調用函數名即可。
4.1 定義函數
shell中定義函數格式如下:
[ function ] funname [()]
{
action;
[return int;]
}
注意:
1.以上的[ function ]也可以省略
2.當函數沒有return時,默認返回最后一個命令的運行結果作為返回值。
4.2 函數參數
在shell中,調用函數時可以向其傳遞參數。在函數內部直接通過$n獲取參數的值。我們給出示例如下:
#!/bin/bash
funWithParam(){
echo "第一個參數為 $1 !"
echo "第十個參數為 ${10} !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
需要注意$10不能返回第十個參數,當n>10的時候,需要使用$(n)來獲取參數。
4.3 函數作用域
Shell腳本中執(zhí)行函數時并不會開啟子進程,默認在函數外部或函數內部定義和使用變量的效果相同。函數外部的變量在函數內部可以直接調用,反之函數內部的變量也可以在函數外部直接調用。但是這樣會導致變量混淆、數據可能被錯誤地修改等等問題,那么如何解決這些問題呢?
系統(tǒng)為我們提供了一個local語句,該語句可以使在函數內部定義的變量僅在函數內部有效。定義時直接在變量前加local即可。
五、重定向
一個命令通常從一個叫標準輸入的地方讀取輸入,默認情況下,這恰好是你的終端。同樣,一個命令通常將其輸出寫入到標準輸出,默認情況下,這也是你的終端。
一般情況下,每個 Unix/Linux 命令運行時都會打開三個文件:
- 標準輸入文件(stdin):stdin的文件描述符為0,Unix程序默認從stdin讀取數據。
- 標準輸出文件(stdout):stdout 的文件描述符為1,Unix程序默認向stdout輸出數據。
- 標準錯誤文件(stderr):stderr的文件描述符為2,Unix程序會向stderr流中寫入錯誤信息。
但有些時候我們可能需要將數據從其它文件讀入或讀出,這就需要我們重定向。
5.1 輸入重定向
我們可以讓命令從文件中獲取,這樣本來的命令需要從標準輸入stdin中獲取,轉換為從我們的指定文件中獲取。這樣本來需要從鍵盤輸入的命令就會轉移到文件讀取內容。語法如下:
command1 < file
5.2 輸出重定向
同輸入重定向很相似,輸出重定向也是將本來需要輸出標準輸出文件stdout中轉化為我們的指定文件中。語法如下:
command1 > file
5.3 標準錯誤文件重定向
我們可以直接借助標準錯誤文件的文件描述符來重定向stderr,語法如下:
$ command 2>file
擴充一點,如果我們想將stdout標準輸出文件和stderr標準錯誤文件合并重定向到一個指定文件中,語法如下:
$ command > file 2>&1
5.4 Here Document
Here Document 是 Shell 中的一種特殊的重定向方式,用來將輸入重定向到一個交互式 Shell 腳本或程序。它的作用是將兩個 delimiter 之間的內容(document) 作為輸入傳遞給 command?;菊Z法如下:
command << delimiter documentdelimiter
注意:
結尾的delimiter 一定要頂格寫,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 縮進。開始的delimiter前后的空格會被忽略掉。
5.5 /dev/null 文件
如果希望執(zhí)行某個命令,但又不希望在屏幕上顯示輸出結果,那么可以將輸出重定向到 /dev/null中,/dev/null 是一個特殊的文件,寫入到它的內容都會被丟棄;如果嘗試從該文件讀取內容,那么什么也讀不到。但是 /dev/null 文件非常有用,將命令的輸出重定向到它,會起到"禁止輸出"的效果。語法如下:
$ command > /dev/null
總結
到此這篇關于Shell腳本的超詳細講解的文章就介紹到這了,更多相關Shell腳本講解內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
shell腳本5種執(zhí)行方式及腳本不同的執(zhí)行方法和區(qū)別詳解
我們都知道bash?shell?腳本的方法有多種,下面這篇文章主要給大家介紹了關于shell腳本5種執(zhí)行方式及腳本不同的執(zhí)行方法和區(qū)別的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-07-07
使用Linux shell腳本實現FTP定時執(zhí)行批量下載指定文件
使用FTP定時批量下載指定文件的shell腳本,具體實例介紹如下所示,需要的朋友參考下吧2017-04-04
Linux中的service命令與systemctl命令有何區(qū)別
在Linux中,service?和?systemctl?是兩個至關重要且極其相似的命令,它們如此相似,以至于人們很容易想知道它們之間有何不同,是否可以互換使用,下面我們就來看看之前的區(qū)別到底有哪些吧2023-08-08

