13.1 什么是 Shell scripts
13.1.1 干嘛学习 shell scripts
13.1.2 第一支 script 的撰写与运行
在 shell script 的撰写中还需要用到底下的注意事项:
- 命令的运行是从上而下、从左而右的分析与运行;
- 命令的下达就如同第五章内提到的: 命令、选项与参数间的多个空白都会被忽略掉;
- 空白行也将被忽略掉,并且 [tab] 按键所推开的空白同样视为空白键;
- 如果读取到一个 Enter 符号 (CR) ,就尝试开始运行该行 (或该串) 命令;
- 至於如果一行的内容太多,则可以使用『 \[Enter] 』来延伸至下一行;
- 『 # 』可做为注解!任何加在 # 后面的数据将全部被视为注解文字而被忽略!
假设你写的这个程序档名是 /home/dmtsai/shell.sh 好了,那如何运行这个文件?很简单,可以有底下几个方法:
- 直接命令下达: shell.sh 文件必须要具备可读与可运行 (rx) 的权限,然后:
- 绝对路径:使用 /home/dmtsai/shell.sh 来下达命令;
- 相对路径:假设工作目录在 /home/dmtsai/ ,则使用 ./shell.sh 来运行
- 变量『PATH』功能:将 shell.sh 放在 PATH 指定的目录内,例如: ~/bin/
- 撰写第一支 script
1、第一行 #!/bin/bash 在宣告这个 script 使用的 shell 名称:
必须要以『 #!/bin/bash 』来宣告这个文件内的语法使用
bash 的语法!
(在很多状况中,如果没有配置好这一行, 那么该程序很可能会无法运行)
2、程序内容的说明:
一般来说,
建议你一定要养成说明该 script 的:1. 内容与功能; 2. 版本资讯; 3. 作者与联络方式; 4. 建档日期;5. 历史纪录 等等。
3、主要环境变量的宣告:
建议务必要将一些重要的环境变量配置好,可以直接下达一些外部命令,而不必写绝对路径呢!
4、主要程序部分
5、运行成果告知 (定义回传值)
使用 exit 0 ,这代表离开 script 并且回传一个 0 给系统
接下来透过刚刚上头介绍的运行方法来运行看看结果吧!
[[email protected] scripts]# sh sh01.sh Hello World ! |
另外,你也可以利用:『chmod a+x sh01.sh; ./sh01.sh』来运行这个 script 的呢!
13.2 简单的 shell script 练习
13.2.1 简单范例
- 对谈式脚本:变量内容由使用者决定
[[email protected] scripts]# vi sh02.sh#!/bin/bash read -p "Please input your first name: " firstname # 提示使用者输入 read -p "Please input your last name: " lastname # 提示使用者输入 echo -e "\nYour full name is: $firstname $lastname" # 结果由萤幕输出 |
- 随日期变化:利用 date 进行文件的创建
[[email protected] scripts]# vi sh03.sh#!/bin/bash # 1. 让使用者输入文件名称,并取得 fileuser 这个变量; echo -e "I will use ‘touch‘ command to create 3 files." # 纯粹显示资讯 read -p "Please input your filename: " fileuser # 提示使用者输入# 2. 为了避免使用者随意按 Enter ,利用变量功能分析档名是否有配置? filename=${fileuser:-"filename"} # 开始判断有否配置档名# 3. 开始利用 date 命令来取得所需要的档名了; date1=$(date --date=‘2 days ago‘ +%Y%m%d) # 前两天的日期 date2=$(date --date=‘1 days ago‘ +%Y%m%d) # 前一天的日期 date3=$(date +%Y%m%d) # 今天的日期 file1=${filename}${date1} # 底下三行在配置档名 file2=${filename}${date2} file3=${filename}${date3} # 4. 将档名创建吧! touch "$file1" # 底下三行在创建文件 touch "$file2" touch "$file3"
13.2.2 script 的运行方式差异 (source, sh script, ./script)
- 利用直接运行的方式来运行 script
[[email protected] scripts]# echo $firstname $lastname <==确认了,这两个变量并不存在喔! [[email protected] scripts]# sh sh02.sh Please input your first name: VBird <==这个名字是鸟哥自己输入的 Please input your last name: Tsai Your full name is: VBird Tsai <==看吧!在 script 运行中,这两个变量有生效 [[email protected] scripts]# echo $firstname $lastname <==事实上,这两个变量在父程序的 bash 中还是不存在的! |
图 2.2.1、sh02.sh 在子程序中运行
- 利用 source 来运行脚本:在父程序中运行
[[email protected] scripts]# source sh02.sh Please input your first name: VBird Please input your last name: Tsai Your full name is: VBird Tsai [[email protected] scripts]# echo $firstname $lastname VBird Tsai <==嘿嘿!有数据产生喔! |
图 2.2.2、sh02.sh 在父程序中运行
13.3 善用判断式
13.3.1 利用 test 命令的测试功能
[[email protected] ~]# test -e /dmtsai |
[[email protected] ~]# test -e /dmtsai && echo "exist" || echo "Not exist" Not exist <==结果显示不存在啊!
测试的标志 | 代表意义 |
1. 关於某个档名的『文件类型』判断,如 test -e filename 表示存在否 | |
-e | 该『档名』是否存在?(常用) |
-f | 该『档名』是否存在且为文件(file)?(常用) |
-d | 该『档名』是否存在且为目录(directory)?(常用) |
-b | 该『档名』是否存在且为一个 block device 装置? |
-c | 该『档名』是否存在且为一个 character device 装置? |
-S | 该『档名』是否存在且为一个 Socket 文件? |
-p | 该『档名』是否存在且为一个 FIFO (pipe) 文件? |
-L | 该『档名』是否存在且为一个连结档? |
2. 关於文件的权限侦测,如 test -r filename 表示可读否 (但 root 权限常有例外) | |
-r | 侦测该档名是否存在且具有『可读』的权限? |
-w | 侦测该档名是否存在且具有『可写』的权限? |
-x | 侦测该档名是否存在且具有『可运行』的权限? |
-u | 侦测该档名是否存在且具有『SUID』的属性? |
-g | 侦测该档名是否存在且具有『SGID』的属性? |
-k | 侦测该档名是否存在且具有『Sticky bit』的属性? |
-s | 侦测该档名是否存在且为『非空白文件』? |
3. 两个文件之间的比较,如: test file1 -nt file2 | |
-nt | (newer than)判断 file1 是否比 file2 新 |
-ot | (older than)判断 file1 是否比 file2 旧 |
-ef | 判断 file1 与 file2 是否为同一文件,可用在判断 hard link 的判定上。 主要意义在判定,两个文件是否均指向同一个 inode 哩! |
4. 关於两个整数之间的判定,例如 test n1 -eq n2 | |
-eq | 两数值相等 (equal) |
-ne | 两数值不等 (not equal) |
-gt | n1 大於 n2 (greater than) |
-lt | n1 小於 n2 (less than) |
-ge | n1 大於等於 n2 (greater than or equal) |
-le | n1 小於等於 n2 (less than or equal) |
5. 判定字串的数据 | |
test -z string | 判定字串是否为 0 ?若 string 为空字串,则为 true |
test -n string |
判定字串是否非为 0 ?若 string 为空字串,则为 false。
注: -n 亦可省略 |
test str1 = str2 | 判定 str1 是否等於 str2 ,若相等,则回传 true |
test str1 != str2 | 判定 str1 是否不等於 str2 ,若相等,则回传 false |
6. 多重条件判定,例如: test -r filename -a -x filename | |
-a | (and)两状况同时成立!例如 test -r file -a -x file,则 file 同时具有 r 与 x 权限时,才回传 true。 |
-o | (or)两状况任何一个成立!例如 test -r file -o -x file,则 file 具有 r 或 x 权限时,就可回传 true。 |
! | 反相状态,如 test ! -x file ,当 file 不具有 x 时,回传 true |
13.3.2 利用判断符号 [ ]
如果我想要知道 $HOME 这个变量是否为空的,可以这样做:
[[email protected] ~]# [ -z "$HOME" ] ; echo $? |
必须要注意中括号的两端需要有空白字节来分隔喔! 假设我空白键使用『□』符号来表示,那么,在这些地方你都需要有空白键:
[ "$HOME" == "$MAIL" ] [□"$HOME"□==□"$MAIL"□] |
所以说,你最好要注意:
- 在中括号 [] 内的每个组件都需要有空白键来分隔;
- 在中括号内的变量,最好都以双引号括号起来;
- 在中括号内的常数,最好都以单或双引号括号起来。
为什么要这么麻烦啊?直接举例来说,假如我配置了 name="VBird Tsai" ,然后这样判定:
[[email protected] ~]# name="VBird Tsai" [[email protected] ~]# [ $name == "VBird" ] bash: [: too many arguments |
[[email protected] scripts]# vi sh06.sh read -p "Please input (Y/N): " yn [ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK, continue" && exit 0 [ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh, interrupt!" && exit 0 echo "I don‘t know what your choice is" && exit 0 |
13.3.3 Shell script 的默认变量($0, $1...)
其实 script 针对参数已经有配置好一些变量名称了!对应如下:
/path/to/scriptname opt1 opt2 opt3 opt4 $0 $1 $2 $3 $4 |
- $# :代表后接的参数『个数』,以上表为例这里显示为『 4 』;
- [email protected] :代表『 "$1" "$2" "$3" "$4" 』之意,每个变量是独立的(用双引号括起来);
- $* :代表『 "$1c$2c$3c$4" 』,其中 c 为分隔字节,默认为空白键,
所以本例中代表『 "$1 $2 $3 $4" 』之意。
[[email protected] scripts]# vi sh07.sh echo "The script name is ==> $0" echo "Total parameter number is ==> $#" [ "$#" -lt 2 ] && echo "The number of parameter is less than 2. Stop here." && exit 0 echo "Your whole parameter is ==> ‘[email protected]‘" echo "The 1st parameter ==> $1" echo "The 2nd parameter ==> $2" |
运行结果如下:
[[email protected] scripts]# sh sh07.sh theone haha quot The script name is ==> sh07.sh <==档名 Total parameter number is ==> 3 <==果然有三个参数 Your whole parameter is ==> ‘theone haha quot‘ <==参数的内容全部 The 1st parameter ==> theone <==第一个参数 The 2nd parameter ==> haha <==第二个参数 |
- shift:造成参数变量号码偏移
[[email protected] scripts]# vi sh08.sh echo "Total parameter number is ==> $#" echo "Your whole parameter is ==> ‘[email protected]‘" shift # 进行第一次『一个变量的 shift 』 echo "Total parameter number is ==> $#" echo "Your whole parameter is ==> ‘[email protected]‘" shift 3 # 进行第二次『三个变量的 shift 』 echo "Total parameter number is ==> $#" echo "Your whole parameter is ==> ‘[email protected]‘" |
这玩意的运行成果如下:
[[email protected] scripts]# sh sh08.sh one two three four five six <==给予六个参数 Total parameter number is ==> 6 <==最原始的参数变量情况 Your whole parameter is ==> ‘one two three four five six‘ Total parameter number is ==> 5 <==第一次偏移,看底下发现第一个 one 不见了 Your whole parameter is ==> ‘two three four five six‘ Total parameter number is ==> 2 <==第二次偏移掉三个,two three four 不见了 Your whole parameter is ==> ‘five six‘ |
13.4 条件判断式
13.4.1 利用 if .... then
- 单层、简单条件判断式
if [ 条件判断式 ]; then 当条件判断式成立时,可以进行的命令工作内容; fi <==将 if 反过来写,就成为 fi 啦!结束 if 之意! |
- && 代表 AND ;
- || 代表 or ;
现在我们来将 sh06.sh 这个脚本修改成为 if ... then 的样式来看看:
[[email protected] scripts]# cp sh06.sh sh06-2.sh <==用改的比较快! [[email protected] scripts]# vi sh06-2.sh read -p "Please input (Y/N): " yn if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then echo "OK, continue" exit 0 fi if [ "$yn" == "N" ] || [ "$yn" == "n" ]; then echo "Oh, interrupt!" exit 0 fi echo "I don‘t know what your choice is" && exit 0 |
- 多重、复杂条件判断式
# 一个条件判断,分成功进行与失败进行 (else) if [ 条件判断式 ]; then 当条件判断式成立时,可以进行的命令工作内容; else 当条件判断式不成立时,可以进行的命令工作内容; fi
如果考虑更复杂的情况,则可以使用这个语法:
# 多个条件判断 (if ... elif ... elif ... else) 分多种不同情况运行 if [ 条件判断式一 ]; then 当条件判断式一成立时,可以进行的命令工作内容; elif [ 条件判断式二 ]; then 当条件判断式二成立时,可以进行的命令工作内容; else 当条件判断式一与二均不成立时,可以进行的命令工作内容; fi |
好!我们来将 sh06-2.sh 改写成这样:
[[email protected] scripts]# cp sh06-2.sh sh06-3.sh [[email protected] scripts]# vi sh06-3.sh read -p "Please input (Y/N): " yn if [ "$yn" == "Y" ] || [ "$yn" == "y" ]; then echo "OK, continue" elif [ "$yn" == "N" ] || [ "$yn" == "n" ]; then echo "Oh, interrupt!" else echo "I don‘t know what your choice is" fi |
我们在第十一章已经学会了 grep 这个好用的玩意儿,那么多学一个叫做 netstat 的命令,这个命令可以查询到目前主机有开启的网络服务端口 (service ports), 相关的功能我们会在服务器架设篇继续介绍,这里你只要知道,我可以利用『 netstat
-tuln 』来取得目前主机有启动的服务, 而且取得的资讯有点像这样:
[[email protected] ~]# netstat -tuln Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN tcp 0 0 :::22 :::* LISTEN udp 0 0 0.0.0.0:111 0.0.0.0:* udp 0 0 0.0.0.0:631 0.0.0.0:* #封包格式 本地IP:端口 远程IP:端口 是否监听 |
上面的重点是『Local Address (本地主机的IP与端口对应)』那个栏位,他代表的是本机所启动的网络服务! IP的部分说明的是该服务位於那个介面上,若为 127.0.0.1 则是仅针对本机开放,若是 0.0.0.0 或 ::: 则代表对整个 Internet 开放 (更多资讯请参考服务器架设篇的介绍)。 每个端口 (port) 都有其特定的网络服务,几个常见的 port 与相关网络服务的关系是:
- 80: WWW
- 22: ssh
- 21: ftp
- 25: mail
- 111: RPC(远程程序呼叫)
- 631: CUPS(列印服务功能)
假设我的主机有兴趣要侦测的是比较常见的 port 21, 22, 25及 80 时,那我如何透过 netstat 去侦测我的主机是否有开启这四个主要的网络服务端口呢?由於每个服务的关键字都是接在冒号『 : 』后面, 所以可以藉由撷取类似『 :80 』来侦测的!那我就可以简单的这样去写这个程序喔:
[[email protected] scripts]# vi sh10.sh # 1. 先作一些告知的动作而已~ echo "Now, I will detect your Linux server‘s services!" echo -e "The www, ftp, ssh, and mail will be detect! \n" # 2. 开始进行一些测试的工作,并且也输出一些资讯罗! testing=$(netstat -tuln | grep ":80 ") # 侦测看 port 80 在否? if [ "$testing" != "" ]; then echo "WWW is running in your system." fi testing=$(netstat -tuln | grep ":22 ") # 侦测看 port 22 在否? if [ "$testing" != "" ]; then echo "SSH is running in your system." fi testing=$(netstat -tuln | grep ":21 ") # 侦测看 port 21 在否? if [ "$testing" != "" ]; then echo "FTP is running in your system." fi testing=$(netstat -tuln | grep ":25 ") # 侦测看 port 25 在否? if [ "$testing" != "" ]; then echo "Mail is running in your system." fi |
能不能写个脚本程序来跑,让使用者输入他的退伍日期,让你去帮他计算还有几天才退伍?
利用『 date --date="YYYYMMDD" +%s 』转成秒数后,接下来的动作就容易的多了!如果你已经写完了程序,对照底下的写法试看看:
[[email protected] scripts]# vi sh11.sh # 1. 告知使用者这支程序的用途,并且告知应该如何输入日期格式? echo "This program will try to calculate :" echo "How many days before your demobilization date..." read -p "Please input your demobilization date (YYYYMMDD ex>20090401): " date2 # 2. 测试一下,这个输入的内容是否正确?利用正规表示法罗~ date_d=$(echo $date2 |grep ‘[0-9]\{8\}‘) # 看看是否有八个数字 if [ "$date_d" == "" ]; then echo "You input the wrong date format...." exit 1 fi # 3. 开始计算日期罗~ declare -i date_dem=`date --date="$date2" +%s` # 退伍日期秒数 declare -i date_now=`date +%s` # 现在日期秒数 declare -i date_total_s=$(($date_dem-$date_now)) # 剩余秒数统计 declare -i date_d=$(($date_total_s/60/60/24)) # 转为日数 if [ "$date_total_s" -lt "0" ]; then # 判断是否已退伍 echo "You had been demobilization before: " $((-1*$date_d)) " ago" else declare -i date_h=$(($(($date_total_s-$date_d*60*60*24))/60/60)) echo "You will demobilize after $date_d days and $date_h hours." fi |
13.4.2 利用 case ..... esac 判断
case $变量名称 in <==关键字为 case ,还有变量前有钱字号 "第一个变量内容") <==每个变量内容建议用双引号括起来,关键字则为小括号 ) 程序段 ;; <==每个类别结尾使用两个连续的分号来处理! "第二个变量内容") 程序段 ;; *) <==最后一个变量内容都会用 * 来代表所有其他值 不包含第一个变量内容与第二个变量内容的其他程序运行段 exit 1 ;; esac <==最终的 case 结尾!『反过来写』思考一下! |
[[email protected] scripts]# vi sh09-2.sh case $1 in "hello") echo "Hello, how are you ?" ;; "") echo "You MUST input parameters, ex> {$0 someword}" ;; *) # 其实就相当於万用字节,0~无穷多个任意字节之意! echo "Usage $0 {hello}" ;; esac
一般来说,使用『 case $变量 in 』这个语法中,当中的那个『 $变量 』大致有两种取得的方式:
- 直接下达式:例如上面提到的,利用『 script.sh variable 』 的方式来直接给予 $1 这个变量的内容,这也是在 /etc/init.d 目录下大多数程序的设计方式。
- 互动式:透过 read 这个命令来让使用者输入变量的内容。
这么说或许你的感受性还不高,好,我们直接写个程序来玩玩:让使用者能够输入 one, two, three , 并且将使用者的变量显示到萤幕上,如果不是 one, two, three 时,就告知使用者仅有这三种选择。
[[email protected] scripts]# vi sh12.sh echo "This program will print your selection !" # read -p "Input your choice: " choice # 暂时取消,可以替换! # case $choice in # 暂时取消,可以替换! case $1 in # 现在使用,可以用上面两行替换! "one") echo "Your choice is ONE" ;; "two") echo "Your choice is TWO" ;; "three") echo "Your choice is THREE" ;; *) echo "Usage $0 {one|two|three}" ;; esac |
13.4.3 利用 function 功能
function fname() { 程序段 }
要注意的是,因为 shell script 的运行方式是由上而下,由左而右, 因此在 shell script 当中的 function 的配置一定要在程序的最前面, 这样才能够在运行时被找到可用的程序段喔!好~我们将 sh12.sh 改写一下,自订一个名为 printit 的函数来使用喔:
[[email protected] scripts]# vi sh12-2.sh function printit(){ echo -n "Your choice is " # 加上 -n 可以不断行继续在同一行显示 } echo "This program will print your selection !" case $1 in "one") printit; echo $1 | tr ‘a-z‘ ‘A-Z‘ # 将参数做大小写转换! ;; "two") printit; echo $1 | tr ‘a-z‘ ‘A-Z‘ ;; "three") printit; echo $1 | tr ‘a-z‘ ‘A-Z‘ ;; *) echo "Usage $0 {one|two|three}" ;; esac |
另外, function 也是拥有内建变量的~他的内建变量与 shell script 很类似, 函数名称代表示 $0 ,而后续接的变量也是以 $1, $2... 来取代的~ 这里很容易搞错喔~因为『 function fname() { 程序段 } 』内的 $0, $1... 等等与 shell script
的 $0 是不同的。以上面 sh12-2.sh 来说,假如我下达:『 sh sh12-2.sh one 』 这表示在 shell script 内的 $1 为 "one" 这个字串。但是在 printit() 内的 $1 则与这个 one 无关。 我们将上面的例子再次的改写一下,让你更清楚!
[[email protected] scripts]# vi sh12-3.sh function printit(){ echo "Your choice is $1" # 这个 $1 必须要参考底下命令的下达 } echo "This program will print your selection !" case $1 in "one") printit 1 # 请注意, printit 命令后面还有接参数! ;; "two") printit 2 ;; "three") printit 3 ;; *) echo "Usage $0 {one|two|three}" ;; esac |
13.5 循环 (loop)
while do done, until do done (不定循环圈)
一般来说,不定回圈最常见的就是底下这两种状态了:
while [ condition ] <==中括号内的状态就是判断式 do <==do 是回圈的开始! 程序段落 done <==done 是回圈的结束 |
『当 condition 条件成立时,就进行回圈,直到 condition 的条件不成立才停止』的意思。还有另外一种不定回圈的方式:
until [ condition ] do 程序段落 done |
[[email protected] scripts]# vi sh13.sh while [ "$yn" != "yes" -a "$yn" != "YES" ] do read -p "Please input yes/YES to stop this program: " yn done echo "OK! you input the correct answer." |
如果使用 until 呢?呵呵有趣罗~ 他的条件会变成这样:
[[email protected] scripts]# vi sh13-2.sh until [ "$yn" == "yes" -o "$yn" == "YES" ] do read -p "Please input yes/YES to stop this program: " yn done echo "OK! you input the correct answer." |
仔细比对一下这两个东西有啥不同喔! ^_^再来,如果我想要计算 1+2+3+....+100 这个数据呢? 利用回圈啊~他是这样的:
[[email protected] scripts]# vi sh14.sh s=0 # 这是加总的数值变量 i=0 # 这是累计的数值,亦即是 1, 2, 3.... while [ "$i" != "100" ] do i=$(($i+1)) # 每次 i 都会添加 1 s=$(($s+$i)) # 每次都会加总一次! done echo "The result of ‘1+2+3+...+100‘ is ==> $s" |
嘿嘿!当你运行了『 sh sh14.sh 』之后,就可以得到 5050 这个数据才对啊!
13.5.2 for...do...done (固定循环)
for
这种语法,则是『 已经知道要进行几次循环』的状态!
for var in con1 con2 con3 ... do 程序段 done
我们可以做个简单的练习。假设我有三种动物,分别是 dog, cat, elephant 三种, 我想每一行都输出这样:『There are dogs...』之类的字样,则可以:
[[email protected] scripts]# vi sh15.sh for animal in dog cat elephant do echo "There are ${animal}s.... " done |
13.5.3 for...do...done 的数值处理
for (( 初始值; 限制值; 运行步阶 )) do 程序段 done
值得注意的是,在『运行步阶』的配置上,如果每次添加 1 ,则可以使用类似『i++』的方式,亦即是 i 每次回圈都会添加一的意思。好,我们以这种方式来进行 1 累加到使用者输入的回圈吧!
[[email protected] scripts]# vi sh19.sh read -p "Please input a number, I will count for 1+2+...+your_input: " nu s=0 for (( i=1; i<=$nu; i=i+1 )) do s=$(($s+$i)) done echo "The result of ‘1+2+3+...+$nu‘ is ==> $s" |
13.6 shell script 的追踪与 debug
scripts 在运行之前,最怕的就是出现语法错误的问题了!那么我们如何 debug 呢?有没有办法不需要透过直接运行该 scripts 就可以来判断是否有问题呢?呵呵!当然是有的!我们就直接以 bash 的相关参数来进行判断吧!
[[email protected] ~]# sh [-nvx] scripts.sh 选项与参数: -n :不要运行 script,仅查询语法的问题; -v :再运行 sccript 前,先将 scripts 的内容输出到萤幕上; -x :将使用到的 script 内容显示到萤幕上,这是很有用的参数! 范例一:测试 sh16.sh 有无语法的问题? [[email protected] ~]# sh -n sh16.sh # 若语法没有问题,则不会显示任何资讯! 范例二:将 sh15.sh 的运行过程全部列出来~ [[email protected] ~]# sh -x sh15.sh + PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/root/bin + export PATH + for animal in dog cat elephant + echo ‘There are dogs.... ‘ There are dogs.... + for animal in dog cat elephant + echo ‘There are cats.... ‘ There are cats.... + for animal in dog cat elephant + echo ‘There are elephants.... ‘ There are elephants.... |
请注意,上面范例二中运行的结果并不会有颜色的显示!鸟哥为了方便说明所以在 + 号之后的数据都加上颜色了! 在输出的信息中,在加号后面的数据其实都是命令串,由於 sh -x 的方式来将命令运行过程也显示出来, 如此使用者可以判断程序码运行到哪一段时会出现相关的资讯!这个功能非常的棒!透过显示完整的命令串,
你就能够依据输出的错误资讯来订正你的脚本了!
熟悉 sh 的用法,将可以使你在管理 Linux 的过程中得心应手!至於在 Shell scripts 的学习方法上面,需要『多看、多模仿、并加以修改成自己的样式!』 是最快的学习手段了!网络上有相当多的朋友在开发一些相当有用的 scripts ,若是你可以将对方的 scripts 拿来,并且改成适合自己主机的样子!那么学习的效果会是最快的呢!