二. 在shell腳本中輸出調(diào)試信息
通過(guò)在程序中加入調(diào)試語(yǔ)句把一些關(guān)鍵地方或出錯(cuò)的地方的相關(guān)信息顯示出來(lái)是最常見(jiàn)的調(diào)試手段。Shell程序員通常使用echo(ksh程序員常使用print)語(yǔ)句輸出信息当船,但僅僅依賴echo語(yǔ)句的輸出跟蹤信息很麻煩题画,調(diào)試階段在腳本中加入的大量的echo語(yǔ)句在產(chǎn)品交付時(shí)還得再費(fèi)力一一刪除。針對(duì)這個(gè)問(wèn)題德频,本節(jié)主要介紹一些如何方便有效的輸出調(diào)試信息的方法苍息。
1. 使用trap命令
trap命令用于捕獲指定的信號(hào)并執(zhí)行預(yù)定義的命令。
其基本的語(yǔ)法是:
trap 'command' signal
其中signal是要捕獲的信號(hào),command是捕獲到指定的信號(hào)之后竞思,所要執(zhí)行的命令表谊。可以用kill –l命令看到系統(tǒng)中全部可用的信號(hào)名盖喷,捕獲信號(hào)后所執(zhí)行的命令可以是任何一條或多條合法的shell語(yǔ)句爆办,也可以是一個(gè)函數(shù)名。
shell腳本在執(zhí)行時(shí)课梳,會(huì)產(chǎn)生三個(gè)所謂的“偽信號(hào)”距辆,(之所以稱(chēng)之為“偽信號(hào)”是因?yàn)檫@三個(gè)信號(hào)是由shell產(chǎn)生的,而其它的信號(hào)是由操作系統(tǒng)產(chǎn)生的)暮刃,通過(guò)使用trap命令捕獲這三個(gè)“偽信號(hào)”并輸出相關(guān)信息對(duì)調(diào)試非常有幫助跨算。
表 1. shell偽信號(hào)
信號(hào)名 何時(shí)產(chǎn)生
EXIT 從一個(gè)函數(shù)中退出或整個(gè)腳本執(zhí)行完畢
ERR 當(dāng)一條命令返回非零狀態(tài)時(shí)(代表命令執(zhí)行不成功)
DEBUG 腳本中每一條命令執(zhí)行之前
通過(guò)捕獲EXIT信號(hào),我們可以在shell腳本中止執(zhí)行或從函數(shù)中退出時(shí),輸出某些想要跟蹤的變量的值沾歪,并由此來(lái)判斷腳本的執(zhí)行狀態(tài)以及出錯(cuò)原因,其使用方法是:
trap 'command' EXIT 或 trap 'command' 0
通過(guò)捕獲ERR信號(hào),我們可以方便的追蹤執(zhí)行不成功的命令或函數(shù)漂彤,并輸出相關(guān)的調(diào)試信息,以下是一個(gè)捕獲ERR信號(hào)的示例程序灾搏,其中的$LINENO是一個(gè)shell的內(nèi)置變量挫望,代表shell腳本的當(dāng)前行號(hào)。
$ cat -n exp1.sh
1 ERRTRAP()
2 {
3 echo "[LINE:$1] Error: Command or function exited with status $?"
4 }
5 foo()
6 {
7 return 1;
8 }
9 trap 'ERRTRAP $LINENO' ERR
10 abc
11 foo
其輸出結(jié)果如下:
$ sh exp1.sh
exp1.sh: line 10: abc: command not found
[LINE:10] Error: Command or function exited with status 127
[LINE:11] Error: Command or function exited with status 1
在調(diào)試過(guò)程中狂窑,為了跟蹤某些變量的值媳板,我們常常需要在shell腳本的許多地方插入相同的echo語(yǔ)句來(lái)打印相關(guān)變量的值,這種做法顯得煩瑣而笨拙泉哈。而通過(guò)捕獲DEBUG信號(hào)蛉幸,我們只需要一條trap語(yǔ)句就可以完成對(duì)相關(guān)變量的全程跟蹤。
以下是一個(gè)通過(guò)捕獲DEBUG信號(hào)來(lái)跟蹤變量的示例程序:
$ cat –n exp2.sh
1 #!/bin/bash
2 trap 'echo “before execute line:$LINENO, a=$a,b=$b,c=$c”' DEBUG
3 a=1
4 if [ "$a" -eq 1 ]
5 then
6 b=2
7 else
8 b=1
9 fi
10 c=3
11 echo "end"
其輸出結(jié)果如下:
$ sh exp2.sh
before execute line:3, a=,b=,c=
before execute line:4, a=1,b=,c=
before execute line:6, a=1,b=,c=
before execute line:10, a=1,b=2,c=
before execute line:11, a=1,b=2,c=3
end
從運(yùn)行結(jié)果中可以清晰的看到每執(zhí)行一條命令之后丛晦,相關(guān)變量的值的變化奕纫。同時(shí),從運(yùn)行結(jié)果中打印出來(lái)的行號(hào)來(lái)分析烫沙,可以看到整個(gè)腳本的執(zhí)行軌跡匹层,能夠判斷出哪些條件分支執(zhí)行了,哪些條件分支沒(méi)有執(zhí)行锌蓄。
2. 使用tee命令
在shell腳本中管道以及輸入輸出重定向使用得非常多升筏,在管道的作用下,一些命令的執(zhí)行結(jié)果直接成為了下一條命令的輸入瘸爽。如果我們發(fā)現(xiàn)由管道連接起來(lái)的一批命令的執(zhí)行結(jié)果并非如預(yù)期的那樣您访,就需要逐步檢查各條命令的執(zhí)行結(jié)果來(lái)判斷問(wèn)題出在哪兒,但因?yàn)槭褂昧斯艿兰艟觯@些中間結(jié)果并不會(huì)顯示在屏幕上灵汪,給調(diào)試帶來(lái)了困難檀训,此時(shí)我們就可以借助于tee命令了。
tee命令會(huì)從標(biāo)準(zhǔn)輸入讀取數(shù)據(jù)识虚,將其內(nèi)容輸出到標(biāo)準(zhǔn)輸出設(shè)備,同時(shí)又可將內(nèi)容保存成文件肢扯。例如有如下的腳本片段妒茬,其作用是獲取本機(jī)的ip地址:
ipaddr=`/sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1'
| cut -d : -f3 | awk '{print $1}'`
#######注意=號(hào)后面的整句是用反引號(hào)(數(shù)字1鍵的左邊那個(gè)鍵)括起來(lái)的担锤。
echo $ipaddr
運(yùn)行這個(gè)腳本,實(shí)際輸出的卻不是本機(jī)的ip地址乍钻,而是廣播地址,這時(shí)我們可以借助tee命令肛循,輸出某些中間結(jié)果,將上述腳本片段修改為:
ipaddr=`/sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1'
| tee temp.txt | cut -d : -f3 | awk '{print $1}'`
echo $ipaddr
之后银择,將這段腳本再執(zhí)行一遍多糠,然后查看temp.txt文件的內(nèi)容:
$ cat temp.txt
inet addr:192.168.0.1 Bcast:192.168.0.255 Mask:255.255.255.0
我們可以發(fā)現(xiàn)中間結(jié)果的第二列(列之間以:號(hào)分隔)才包含了IP地址,而在上面的腳本中使用cut命令截取了第三列浩考,故我們只需將腳本中的cut -d : -f3改為cut -d : -f2即可得到正確的結(jié)果夹孔。
具體到上述的script例子,我們也許并不需要tee命令的幫助析孽,比如我們可以分段執(zhí)行由管道連接起來(lái)的各條命令并查看各命令的輸出結(jié)果來(lái)診斷錯(cuò)誤搭伤,但在一些復(fù)雜的shell腳本中,這些由管道連接起來(lái)的命令可能又依賴于腳本中定義的一些其它變量袜瞬,這時(shí)我們想要在提示符下來(lái)分段運(yùn)行各條命令就會(huì)非常麻煩了怜俐,簡(jiǎn)單地在管道之間插入一條tee命令來(lái)查看中間結(jié)果會(huì)更方便一些。
3. 使用"調(diào)試鉤子"
在C語(yǔ)言程序中邓尤,我們經(jīng)常使用DEBUG宏來(lái)控制是否要輸出調(diào)試信息拍鲤,在shell腳本中我們同樣可以使用這樣的機(jī)制,如下列代碼所示:
if [ “$DEBUG” = “true” ]; then
echo “debugging” #此處可以輸出調(diào)試信息
fi
這樣的代碼塊通常稱(chēng)之為“調(diào)試鉤子”或“調(diào)試塊”汞扎。在調(diào)試鉤子內(nèi)部可以輸出任何您想輸出的調(diào)試信息季稳,使用調(diào)試鉤子的好處是它是可以通過(guò)DEBUG變量來(lái)控制的,在腳本的開(kāi)發(fā)調(diào)試階段澈魄,可以先執(zhí)行export DEBUG=true命令打開(kāi)調(diào)試鉤子景鼠,使其輸出調(diào)試信息,而在把腳本交付使用時(shí)一忱,也無(wú)需再費(fèi)事把腳本中的調(diào)試語(yǔ)句一一刪除莲蜘。
如果在每一處需要輸出調(diào)試信息的地方均使用if語(yǔ)句來(lái)判斷DEBUG變量的值,還是顯得比較繁瑣帘营,通過(guò)定義一個(gè)DEBUG函數(shù)可以使植入調(diào)試鉤子的過(guò)程更簡(jiǎn)潔方便票渠,如下面代碼所示:
$ cat –n exp3.sh
1 DEBUG()
2 {
3 if [ "$DEBUG" = "true" ]; then
4 $@
5 fi
6 }
7 a=1
8 DEBUG echo "a=$a"
9 if [ "$a" -eq 1 ]
10 then
11 b=2
12 else
13 b=1
14 fi
15 DEBUG echo "b=$b"
16 c=3
17 DEBUG echo "c=$c"
在上面所示的DEBUG函數(shù)中,會(huì)執(zhí)行任何傳給它的命令芬迄,并且這個(gè)執(zhí)行過(guò)程是可以通過(guò)DEBUG變量的值來(lái)控制的问顷,我們可以把所有跟調(diào)試有關(guān)的命令都作為DEBUG函數(shù)的參數(shù)來(lái)調(diào)用,非常的方便。
三. 使用shell的執(zhí)行選項(xiàng)
上一節(jié)所述的調(diào)試手段是通過(guò)修改shell腳本的源代碼杜窄,令其輸出相關(guān)的調(diào)試信息來(lái)定位錯(cuò)誤的肠骆,那有沒(méi)有不修改源代碼來(lái)調(diào)試shell腳本的方法呢?答案就是使用shell的執(zhí)行選項(xiàng)塞耕,本節(jié)將介紹一些常用選項(xiàng)的用法:
-n 只讀取shell腳本蚀腿,但不實(shí)際執(zhí)行
-x 進(jìn)入跟蹤方式,顯示所執(zhí)行的每一條命令
-c "string" 從strings中讀取命令
“-n”可用于測(cè)試shell腳本是否存在語(yǔ)法錯(cuò)誤扫外,但不會(huì)實(shí)際執(zhí)行命令莉钙。在shell腳本編寫(xiě)完成之后,實(shí)際執(zhí)行之前筛谚,首先使用“-n”選項(xiàng)來(lái)測(cè)試腳本是否存在語(yǔ)法錯(cuò)誤是一個(gè)很好的習(xí)慣磁玉。因?yàn)槟承﹕hell腳本在執(zhí)行時(shí)會(huì)對(duì)系統(tǒng)環(huán)境產(chǎn)生影響,比如生成或移動(dòng)文件等驾讲,如果在實(shí)際執(zhí)行才發(fā)現(xiàn)語(yǔ)法錯(cuò)誤蚊伞,您不得不手工做一些系統(tǒng)環(huán)境的恢復(fù)工作才能繼續(xù)測(cè)試這個(gè)腳本。
“-c”選項(xiàng)使shell解釋器從一個(gè)字符串中而不是從一個(gè)文件中讀取并執(zhí)行shell命令吮铭。當(dāng)需要臨時(shí)測(cè)試一小段腳本的執(zhí)行結(jié)果時(shí)时迫,可以使用這個(gè)選項(xiàng),如下所示:
sh -c 'a=1;b=2;let c=$a+$b;echo "c=$c"'
"-x"選項(xiàng)可用來(lái)跟蹤腳本的執(zhí)行沐兵,是調(diào)試shell腳本的強(qiáng)有力工具别垮。“-x”選項(xiàng)使shell在執(zhí)行腳本的過(guò)程中把它實(shí)際執(zhí)行的每一個(gè)命令行顯示出來(lái)扎谎,并且在行首顯示一個(gè)"+"號(hào)碳想。 "+"號(hào)后面顯示的是經(jīng)過(guò)了變量替換之后的命令行的內(nèi)容,有助于分析實(shí)際執(zhí)行的是什么命令毁靶。 “-x”選項(xiàng)使用起來(lái)簡(jiǎn)單方便胧奔,可以輕松對(duì)付大多數(shù)的shell調(diào)試任務(wù),應(yīng)把其當(dāng)作首選的調(diào)試手段。
如果把本文前面所述的trap ‘command’ DEBUG機(jī)制與“-x”選項(xiàng)結(jié)合起來(lái)预吆,我們就可以既輸出實(shí)際執(zhí)行的每一條命令龙填,又逐行跟蹤相關(guān)變量的值,對(duì)調(diào)試相當(dāng)有幫助拐叉。
仍以前面所述的exp2.sh為例岩遗,現(xiàn)在加上“-x”選項(xiàng)來(lái)執(zhí)行它:
$ sh –x exp2.sh
+ trap 'echo "before execute line:$LINENO, a=$a,b=$b,c=$c"' DEBUG
++ echo 'before execute line:3, a=,b=,c='
before execute line:3, a=,b=,c=
+ a=1
++ echo 'before execute line:4, a=1,b=,c='
before execute line:4, a=1,b=,c=
+ '[' 1 -eq 1 ']'
++ echo 'before execute line:6, a=1,b=,c='
before execute line:6, a=1,b=,c=
+ b=2
++ echo 'before execute line:10, a=1,b=2,c='
before execute line:10, a=1,b=2,c=
+ c=3
++ echo 'before execute line:11, a=1,b=2,c=3'
before execute line:11, a=1,b=2,c=3
+ echo end
end
在上面的結(jié)果中,前面有“+”號(hào)的行是shell腳本實(shí)際執(zhí)行的命令凤瘦,前面有“++”號(hào)的行是執(zhí)行trap機(jī)制中指定的命令宿礁,其它的行則是輸出信息。
shell的執(zhí)行選項(xiàng)除了可以在啟動(dòng)shell時(shí)指定外蔬芥,亦可在腳本中用set命令來(lái)指定梆靖。 "set -參數(shù)"表示啟用某選項(xiàng)控汉,"set +參數(shù)"表示關(guān)閉某選項(xiàng)。有時(shí)候我們并不需要在啟動(dòng)時(shí)用"-x"選項(xiàng)來(lái)跟蹤所有的命令行返吻,這時(shí)我們可以在腳本中使用set命令姑子,如以下腳本片段所示:
set -x #啟動(dòng)"-x"選項(xiàng)
要跟蹤的程序段
set +x #關(guān)閉"-x"選項(xiàng)
set命令同樣可以使用上一節(jié)中介紹的調(diào)試鉤子—DEBUG函數(shù)來(lái)調(diào)用,這樣可以避免腳本交付使用時(shí)刪除這些調(diào)試語(yǔ)句的麻煩测僵,如以下腳本片段所示:
DEBUG set -x #啟動(dòng)"-x"選項(xiàng)
要跟蹤的程序段
DEBUG set +x #關(guān)閉"-x"選項(xiàng)
四. 對(duì)"-x"選項(xiàng)的增強(qiáng)
"-x"執(zhí)行選項(xiàng)是目前最常用的跟蹤和調(diào)試shell腳本的手段街佑,但其輸出的調(diào)試信息僅限于進(jìn)行變量替換之后的每一條實(shí)際執(zhí)行的命令以及行首的一個(gè)"+"號(hào)提示符,居然連行號(hào)這樣的重要信息都沒(méi)有恨课,對(duì)于復(fù)雜的shell腳本的調(diào)試來(lái)說(shuō)舆乔,還是非常的不方便岳服。幸運(yùn)的是剂公,我們可以巧妙地利用shell內(nèi)置的一些環(huán)境變量來(lái)增強(qiáng)"-x"選項(xiàng)的輸出信息,下面先介紹幾個(gè)shell內(nèi)置的環(huán)境變量:
$LINENO
代表shell腳本的當(dāng)前行號(hào)吊宋,類(lèi)似于C語(yǔ)言中的內(nèi)置宏LINE
$FUNCNAME
函數(shù)的名字纲辽,類(lèi)似于C語(yǔ)言中的內(nèi)置宏func,但宏func只能代表當(dāng)前所在的函數(shù)名,而$FUNCNAME的功能更強(qiáng)大璃搜,它是一個(gè)數(shù)組變量拖吼,其中包含了整個(gè)調(diào)用鏈上所有的函數(shù)的名字,故變量${FUNCNAME[0]}代表shell腳本當(dāng)前正在執(zhí)行的函數(shù)的名字这吻,而變量${FUNCNAME[1]}則代表調(diào)用函數(shù)${FUNCNAME[0]}的函數(shù)的名字吊档,余者可以依此類(lèi)推。
$PS4
主提示符變量$PS1和第二級(jí)提示符變量$PS2比較常見(jiàn)唾糯,但很少有人注意到第四級(jí)提示符變量$PS4的作用怠硼。我們知道使用“-x”執(zhí)行選項(xiàng)將會(huì)顯示shell腳本中每一條實(shí)際執(zhí)行過(guò)的命令,而$PS4的值將被顯示在“-x”選項(xiàng)輸出的每一條命令的前面移怯。在Bash Shell中香璃,缺省的$PS4的值是"+"號(hào)。(現(xiàn)在知道為什么使用"-x"選項(xiàng)時(shí)舟误,輸出的命令前面有一個(gè)"+"號(hào)了吧葡秒?)。
利用$PS4這一特性嵌溢,通過(guò)使用一些內(nèi)置變量來(lái)重定義$PS4的值眯牧,我們就可以增強(qiáng)"-x"選項(xiàng)的輸出信息。例如先執(zhí)行export PS4='+{$LINENO:${FUNCNAME[0]}} ', 然后再使用“-x”選項(xiàng)來(lái)執(zhí)行腳本赖草,就能在每一條實(shí)際執(zhí)行的命令前面顯示其行號(hào)以及所屬的函數(shù)名学少。
以下是一個(gè)存在bug的shell腳本的示例,本文將用此腳本來(lái)示范如何用“-n”以及增強(qiáng)的“-x”執(zhí)行選項(xiàng)來(lái)調(diào)試shell腳本疚顷。這個(gè)腳本中定義了一個(gè)函數(shù)isRoot(),用于判斷當(dāng)前用戶是不是root用戶旱易,如果不是禁偎,則中止腳本的執(zhí)行
$ cat –n exp4.sh
1 #!/bin/bash
2 isRoot()
3 {
4 if [ "$UID" -ne 0 ]
5 return 1
6 else
7 return 0
8 fi
9 }
10 isRoot
11 if ["$?" -ne 0 ]
12 then
13 echo "Must be root to run this script"
14 exit 1
15 else
16 echo "welcome root user"
17 #do something
18 fi
首先執(zhí)行sh –n exp4.sh來(lái)進(jìn)行語(yǔ)法檢查,輸出如下:
$ sh –n exp4.sh
exp4.sh: line 6: syntax error near unexpected token `else'
exp4.sh: line 6: ` else'
發(fā)現(xiàn)了一個(gè)語(yǔ)法錯(cuò)誤阀坏,通過(guò)仔細(xì)檢查第6行前后的命令如暖,我們發(fā)現(xiàn)是第4行的if語(yǔ)句缺少then關(guān)鍵字引起的(寫(xiě)慣了C程序的人很容易犯這個(gè)錯(cuò)誤)。我們可以把第4行修改為if [ "$UID" -ne 0 ]; then來(lái)修正這個(gè)錯(cuò)誤忌堂。再次運(yùn)行sh –n exp4.sh來(lái)進(jìn)行語(yǔ)法檢查盒至,沒(méi)有再報(bào)告錯(cuò)誤。接下來(lái)就可以實(shí)際執(zhí)行這個(gè)腳本了士修,執(zhí)行結(jié)果如下:
$ sh exp4.sh
exp2.sh: line 11: [1: command not found
welcome root user
盡管腳本沒(méi)有語(yǔ)法錯(cuò)誤了枷遂,在執(zhí)行時(shí)卻又報(bào)告了錯(cuò)誤。錯(cuò)誤信息還非常奇怪“[1: command not found”∑宄埃現(xiàn)在我們可以試試定制$PS4的值酒唉,并使用“-x”選項(xiàng)來(lái)跟蹤:
$ export PS4='+{$LINENO:${FUNCNAME[0]}} '
$ sh –x exp4.sh
+{10:} isRoot
+{4:isRoot} '[' 503 -ne 0 ']'
+{5:isRoot} return 1
+{11:} '[1' -ne 0 ']'
exp4.sh: line 11: [1: command not found
+{16:} echo 'welcome root user'
welcome root user
從輸出結(jié)果中,我們可以看到腳本實(shí)際被執(zhí)行的語(yǔ)句沸移,該語(yǔ)句的行號(hào)以及所屬的函數(shù)名也被打印出來(lái)痪伦,從中可以清楚的分析出腳本的執(zhí)行軌跡以及所調(diào)用的函數(shù)的內(nèi)部執(zhí)行情況。由于執(zhí)行時(shí)是第11行報(bào)錯(cuò)雹锣,這是一個(gè)if語(yǔ)句网沾,我們對(duì)比分析一下同為if語(yǔ)句的第4行的跟蹤結(jié)果:
+{4:isRoot} '[' 503 -ne 0 ']'
+{11:} '[1' -ne 0 ']'
可知由于第11行的[號(hào)后面缺少了一個(gè)空格,導(dǎo)致[號(hào)與緊挨它的變量$?的值1被shell解釋器看作了一個(gè)整體蕊爵,并試著把這個(gè)整體視為一個(gè)命令來(lái)執(zhí)行辉哥,故有“[1: command not found”這樣的錯(cuò)誤提示。只需在[號(hào)后面插入一個(gè)空格就一切正常了攒射。
shell中還有其它一些對(duì)調(diào)試有幫助的內(nèi)置變量醋旦,比如在Bash Shell中還有BASH_SOURCE, BASH_SUBSHELL等一批對(duì)調(diào)試有幫助的內(nèi)置變量,您可以通過(guò)man sh或man bash來(lái)查看匆篓,然后根據(jù)您的調(diào)試目的,使用這些內(nèi)置變量來(lái)定制$PS4浑度,從而達(dá)到增強(qiáng)“-x”選項(xiàng)的輸出信息的目的。
五. 總結(jié)
現(xiàn)在讓我們來(lái)總結(jié)一下調(diào)試shell腳本的過(guò)程:
首先使用“-n”選項(xiàng)檢查語(yǔ)法錯(cuò)誤鸦概,然后使用“-x”選項(xiàng)跟蹤腳本的執(zhí)行箩张,使用“-x”選項(xiàng)之前,別忘了先定制PS4變量的值來(lái)增強(qiáng)“-x”選項(xiàng)的輸出信息窗市,至少應(yīng)該令其輸出行號(hào)信息(先執(zhí)行export PS4='+[$LINENO]'先慷,更一勞永逸的辦法是將這條語(yǔ)句加到您用戶主目錄的.bash_profile文件中去),這將使你的調(diào)試之旅更輕松咨察。也可以利用trap,調(diào)試鉤子等手段輸出關(guān)鍵調(diào)試信息论熙,快速縮小排查錯(cuò)誤的范圍,并在腳本中使用“set -x”及“set +x”對(duì)某些代碼塊進(jìn)行重點(diǎn)跟蹤摄狱。這樣多種手段齊下脓诡,相信您已經(jīng)可以比較輕松地抓出您的shell腳本中的臭蟲(chóng)了无午。如果您的腳本足夠復(fù)雜,還需要更強(qiáng)的調(diào)試能力祝谚,可以使用shell調(diào)試器bashdb宪迟,這是一個(gè)類(lèi)似于GDB的調(diào)試工具,可以完成對(duì)shell腳本的斷點(diǎn)設(shè)置交惯,單步執(zhí)行滥壕,變量觀察等許多功能烟勋,使用bashdb對(duì)閱讀和理解復(fù)雜的shell腳本也會(huì)大有裨益桐智。關(guān)于bashdb的安裝和使用蹦玫,不屬于本文范圍,您可參閱http://bashdb.sourceforge.NET/上的文檔并下載試用只锻。