`
gaoyuntao2005
  • 浏览: 311360 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

学习 Shell Scripts

阅读更多

如果您真的很想要走信息这条路,并且想要好好的管理好属于您的主机,那么,别说鸟哥不告诉您, Shell Scripts 真的是必须要学习的一项课题呢!基本上, shell script 有点像是早期的批次档, 亦即是将一些指令汇整起来一次执行,但是 Shell script 拥有更强大的功能,那就是, 他可以进行类似程序 (program) 的撰写,并且,不需要经过编译 (compiler) 就能够执行, 真的很方便。加上,我们可透过 shell script 来简化我们日常的工作管理, 而且,整个 Linux 环境中,一些服务 (services) 的启动都是透过 shell script 的, 如果您对于 script 不了解,嘿嘿!发生问题时,可真是会求助无门喔! 所以,好好的学一学他吧!   


1. 什么是 Shell Script 
1.1 干嘛学习 shell scripts? 
1.2 第一支 script 的撰写与执行 
1.3 撰写 shell script 的良好习惯建立 
2. 简单的 shell script 练习: 
3. 善用判断式: 
3.1 利用 test 指令的测试功能 
3.2 利用判断符号 [ ] 
3.3 Shell script 的预设变数($0, $1...) 
4. 条件判断式: 
4.1 利用 if .... then 
4.2 利用 case ..... esac 判断 
4.3 利用 function 功能 
5. 循环 (loop) 
5.1 while....do....done, until....do....done 
5.2 for...do...done 
6. shell script 的追踪与 debug 
7. 本章习题练习 


-------------------------------------------------------------------------------- 
什么是 Shell scripts ? 

这个有趣的问题赶紧来回答看看,什么是 shell script 呢? shell 我们在 认识 bash 当中已经提过了,那是一个文字接口底下让我们与系统沟通的一个工具接口,那么 script 是啥? 字面上的意义, script 是『脚本、剧本』的意思。整句话是说, shell script 是针对 shell 所写的『剧本!』 什么东西啊?呵呵!其实, shell script 是利用 shell 的功能所写的一个『程序 (program)』,这个程序是使用纯文字文件,将一些 shell 的语法与指令写在里面, 搭配正规表示法、管线命令与数据流重导向等功能,以达到我们所想要的处理目的。

所以,简单的说, shell script 就像是早期 DOS 年代的批次檔 (.bat) ,最简单的功能就是将许多指令汇整写在一起, 让使用者很轻易的就能够 one touch (执行一个档案 "shell script" ,就能够一次执行多个指令), 而, shell script 更提供数组、循环、条件与逻辑判断等重要功能,让使用者也可以直接以 shell 来撰写程序,而不必使用类似 C 程序语言等传统程序撰写的语法呢! 

那,这么说您可以了解了吗?是的! shell script 可以简单的被看成是批次档, 也可以被说成是一个程序语言,且这个程序语言由于都是利用 shell 与相关工具指令, 所以不需要编译即可执行,且拥有不错的除错 (debug) 工具,所以,他可以帮助系统管理员快速的管理好主机。 


-------------------------------------------------------------------------------- 
干嘛学习 shell scripts? 

这是个好问题,我又干嘛一定要学 shell script ?我又不是信息人,没有写程序的概念, 那我干嘛还要学 shell script 呢?不要学可不可以啊?呵呵~如果 Linux 对您而言, 您只是想要『会用』而已,那么,不需要学 shell script 也还无所谓,这部分先给他跳过去, 等到有空的时候,再来好好的瞧一瞧。但是,如果您是真的想要玩清楚 Linux 的来龙去脉, 那么 shell script 就不可不知,为什么呢?因为: 


自动化管理的重要依据:  
不用鸟哥说您也知道,管理一部主机真不是件简单的事情,每天要进行的任务就有: 查询登录档、追踪流量、监控使用者使用主机状态、主机各项硬设备状态、 主机软件更新查询、更不要说得应付其它使用者的突然要求了。而这些工作, 您想要自行手动处理,还是写个简单的程序来帮您每日自动处理分析,若有问题才通知您呢? 当然是让系统自动工作比较好,对吧!呵呵~这就得要良好的 shell script 来帮忙的啦! 


追踪与管理系统的重要工作:  
虽然我们还没有提到服务启动的方法,不过,这里可以先提一下,我们 Linux 系统的服务 ( services ) 启动的接口,在 /etc/init.d/ 这个目录下,所有的档案都是 scripts ; 另外,包括开机 (booting) 过程也都是利用 shell script 来帮忙搜寻系统的相关设定数据, 然后再代入各个服务的设定参数啊!举例来说,如果我们想要重新启动系统登录文件, 可以使用:『/etc/init.d/syslogd restart』,那个 syslogd 档案就是 script 啦! 另外,我曾经在某一代的 FC 上面发现,启动 MySQL 这个数据库服务时,确实是可以启动的, 但是屏幕上却老是出现『failure』,后来才发现,原来是启动 MySQL 那个 script 会主动的以『空的密码』去尝试登入 MySQL ,但我修改过 MySQL 的密码啰~当然就登入失败~ 后来改了改 script ,就略去这个问题啦!如此说来, script 确实是需要学习的啊! 


简单入侵侦测功能:  
当我们的系统有异状时,大多会将这些异状记录在系统记录器,也就是我们常提到的『系统登录文件』, 那么我们可以在固定的几分钟内主动的去分析系统登录文件,若察觉有问题,就立刻通报管理员, 或者是立刻加强防火墙的设定规则,如此一来,您的主机可就能够达到『自我保护』的聪明学习功能啦~ 举例来说,我们可以通过 shell script 去分析『当该封包尝试几次还是联机失败之后,就予以抵挡住该 IP』之类的举动,例如鸟哥写过一个关于抵挡砍站软件的 shell script , 就是用这个想法去达成的呢! 


连续指令单一化:  
其实,对于新手而言, script 最简单的功能就是:『汇整一些在 command line 下达的连续指令,将他写入 scripts 当中,而由直接执行 scripts 来启动一连串的 command line 指令输出入!』例如: 防火墙连续规则 ( iptables ),开机加载程序的项目 ( 就是在 /etc/rc.d/rc.local 里头的数据 ) ,等等都是相似的功能啦! 其实,说穿了,如果不考虑 program 的部分,那么 scripts 也可以想成,仅是帮我们把一大串的指令汇整在一个档案里面, 而直接执行该档案就可以执行那一串又臭又长的指令段!就是这么简单啦! 


简易的数据处理:  
由前一章 正规表示法 的 awk 程序说明中, 您可以发现, awk 可以用来处理简单的数据数据呢!例如薪资单的处理啊等等的。 shell script 的功能更强大,例如鸟哥曾经用 shell script 直接处理数据数据的比对啊, 文字数据的处理啊等等的,撰写方便,速度又快(因为在 Linux 效能较佳), 真的是很不错用的啦! 


跨平台支持与学习历程较短:  
几乎所有的 Unix Like 上面都可以跑 shell script ,连 MS Windows 系列也有相关的仿真器可以用, 此外, shell script 的语法是相当亲和的,看都看的懂得文字,而不是机器码, 很容易学习~这些都是您可以加以考虑的学习点啊! 


上面这些都是您考虑学习 shell script 的特点~此外, shell script 还可以简单的以 vi 来直接编写,实在是很方便的好东西!所以,还是建议您学习一下啦。 

不过,虽然 shell script 号称是程序 (program) ,但实际上, shell script 处理数据的速度上是不太够的。因为 shell script 用的是外部的指令与 bash shell 的一些预设工具,所以,他常常会去呼叫外部的函式库,因此,运算速度上面当然比不上传统的程序语言。 所以啰, shell script 用在系统管理上面是很好的一项工具,但是用在处理大量数值运算上, 就不够好了~而且还很麻烦,因为:Shell scripts 的速度较慢, 且使用的 CPU 资源较多,造成主机资源的分配不良。还好, 我们确实很少看到利用 shell script 在进行大量数据运算的,所以,不必担心的啦! 



-------------------------------------------------------------------------------- 
第一支 script 的撰写与执行 

如同前面讲到的, shell script 其实就是纯文字文件 (ASCII) ,我们可以编辑这个档案, 然后让这个档案来帮我们一次执行多个指令,或者是利用一些运算与逻辑判断来帮我们达成某些功能。 所以啦,要编辑这个档案的内容时,当然就需要具备有 bash shell 指令下达的相关认识。 我们说过,要下达指令需要注意的事项在 bash 章节内已经提过, 在 shell script 的撰写同样需要用到这些注意事项的: 
如同前面 bash command 提到的,指令与参数间的多个空白会被忽略掉;  
而空白行也将被忽略掉!,并且 [tab] 也是不会被理会的!  
如果读取到一个 Enter 符号 ( CR )),就尝试开始执行该行命令;  
至于如果一行的内容太多,则可以使用 \[Enter] 来延伸至下一行;  
此外,使用最多的 # 可做为批注!任何加在 # 后面的字,将全部被视为批注文字而被忽略!  
如此一来,我们在 script 内所撰写的程序,就会被一行一行的执行。好了,那么这个程序假设文件名是 shell.sh 好了,如何执行这个档案?很简单,可以有底下几个方法: 
将 shell.sh 加上可读与执行 (rx) 的权限,然后就能够以 ./shell.sh 来执行了;  
直接以 sh shell.sh 的方式来直接执行即可。 
反正重点就是要让那个 shell.sh 内的指令可以被执行的意思啦!咦!那我为何需要使用 ./shell.sh 来下达指令? 还记得我们在 bash 里面一直强调的,指令是否能够被执行与 PATH 这个环境变量有关, 所以,要执行『目前这个目录下的某个档案』就需要加上 ./ 这个目录啦!另外,其实您也可以将 shell.sh 放在您家目录下的 ~/bin 这个目录中,然后利用 PATH="$PATH":~/bin 的设定, 嘿嘿,就能够直接执行您的 script 啰~ ^_^ 

那,为何 sh shell.sh 也可以执行呢?这是因为 /bin/sh 其实就是 /bin/bash , 使用 sh shell.sh 亦即告诉系统,我想要直接以 bash 的功能来执行 shell.sh 这个档案内的相关指令的意思。 而我们也可以利用 sh 的参数,如 -n 及 -x 来检查与追踪 shell.sh 的语法是否正确呢! ^_^ 


-------------------------------------------------------------------------------- 

撰写第一支 script  
不论是那个门派,要学武功要从扫地做起,那么要学程序呢?呵呵,肯定是由『秀出 Hello World!』 这个字眼开始的!OK!那么鸟哥就先写一支 script 给大家瞧一瞧: 
[root@linux ~]# mkdir scripts; cd scripts 
[root@linux scripts]# vi sh01.sh 
#!/bin/bash 
# Program: 
#       This program is used to show "Hello World !" in screen. 
# History: 
# 2005/08/23 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 
echo -e "Hello World ! \a \n" 
exit 0 

  
在我们这个章节当中,请将所有的撰写的 script 放置到您家目录的 ~/scripts 这个目录内, 比较好管理啦!上面的写法当中,我主要将整个程序的撰写分成数段,大致是这样: 
第一行 #!/bin/bash 在宣告这个 script 使用的 shell 名称: 
因为我们使用的是 bash ,所以,必须要以『 #!/bin/bash 』来宣告这个档案内的语法使用 bash 的语法!那么当这个程序被执行时,他就能够加载 bash 的相关环境设定档, 并且执行 bash 来使我们底下的指令能够执行!这很重要的!(在很多状况中,如果没有设定好这一行, 那么该程序很可能会无法执行,因为系统可能无法判断该程序需要使用什么 shell 来执行啊!) 


程序内容的宣告: 
整个 script 当中,除了第一行的 #! 是用来宣告 shell 的之外,其它的 # 都是『批注』用途! 所以上面的程序当中,第二行以下就是用来说明整个程序的状态。一般来说, 建议您一定要养成说明该 script 的:1. 内容与功能; 2. 版本信息; 3. 作者与联络方式; 4. 建檔日期;5. 历史纪录 等等。这将有助于未来程序的改写与 debug 呢! 


主要环境变量的宣告: 
建议务必要将一些重要的环境变量设定好,鸟哥个人认为, PATH 是当中最重要的! 如此一来,则可让我们这支程序在进行时,可以直接下达指令, 而不必写绝对路径呢!比较好啦! 


主要程序部分 
就将主要的程序写好即可!在这个例子当中,就是 echo 那一行啦! 


执行成果告知 
是否记得我们在 bash 里面要讨论一个指令的执行成功与否,可以使用 $? 这个变量来观察~ 那么我们也可以利用 exit 这个指令来让程序中断,并且回传一个数值给系统。 在我们这个例子当中,我使用 exit 0 ,这代表离开 script ,并且回传一个 0 给系统, 所以我执行完这个 script 后,若接着下达 echo $? 则可得到 0 的值喔! 更聪明的读者应该也知道了,呵呵!利用这个 exit n 的功能,我们还可以自订错误讯息, 让这支程序变得更加的 smart 呢!  
接下来执行看看结果是怎样吧? 
[root@linux scripts]# sh sh01.sh 
Hello World ! 


  
您会看到屏幕是这样,而且应该还会听到『咚』的一声,为什么呢?还记得前一章提到的 printf 吧?用 echo 接着那些特殊的按键也可以发生同样的事情~ 不过, echo 必须要加上 -e 的参数才行! 呵呵!在您写完这个小 script 之后,您就可以大声的说:『我也会写程序了』!哈哈! 很简单有趣吧~ ^_^ 

另外,你也可以利用:『chmod a+x sh01.sh; ./sh01.sh』来执行这个 script 的呢! 


-------------------------------------------------------------------------------- 
撰写 shell script 的良好习惯建立 

一个良好习惯的养成是很重要的~大家在刚开始撰写程序的时候,最容易忽略这部分, 认为程序写出来就好了,其它的不重要。其实,如果程序的说明能够更清楚, 那么对您自己是有很大的帮助的。 

举例来说,鸟哥自己为了自己的需求,曾经撰写了不少的 script 来帮我进行主机 IP 的侦测啊、 登录档分析与管理啊、自动上传下载重要设定档啊等等的,不过,早期就是因为太懒了, 管理的主机又太多了,常常同一个程序在不同的主机上面进行更改,到最后,到底哪一支才是最新的都记不起来, 而且,重点是,我到底是改了哪里??为什么做那样的修改?都忘的一乾二净~真要命~ 

所以,后来鸟哥在写程序的时候,通常会比较仔细的将程序的设计过程给他记录下来, 而且还会记录一些历史纪录,如此一来,好多了~ 至少很容易知道我修改了哪些数据,以及程序修改的理念与逻辑概念等等, 在维护上面是轻松很多很多的喔! 

另外,在一些环境的设定上面,毕竟每个人的环境都不相同,为了取得较佳的执行环境, 我都会自行先定义好一些一定会被用到的环境变量,例如 PATH 这个玩意儿! 这样比较好啦~所以说,建议您一定要养成良好的 script 撰写习惯, 在每个 script 的文件头处记录好: 
script 的功能;  
script 的版本信息;  
script 的作者与联络方式;  
script 的版权宣告方式;  
script 的 History (历史纪录);  
script 内较特殊的指令,使用绝对路径的方式来下达;  
script 运作时需要的环境变量预先宣告与设定。 

-------------------------------------------------------------------------------- 
简单的 shell script 练习 

在第一支 shell script 撰写完毕之后,相信您应该具有基本的撰写功力了。 接下来,在开始更深入的程序概念之前,我们先来玩一些比较有趣的简单的小范例好了。 底下的范例中,达成结果的方式相当的多,建议您先自行撰写看看,写完之后再与鸟哥写的内容比对, 这样才能更加深概念喔!好!不啰唆,我们就一个一个来玩吧! 


-------------------------------------------------------------------------------- 

变量内容由使用者决定  
很多时候我们需要使用者输入一些内容,好让程序可以顺利运作。 简单的来说,大家应该都有安装过软件的经验,安装的时候,他不是会问您『要安装到那个目录去?』吗? 那个让使用者输入的数据的动作,就是让使用者输入变量内容啦。 

你应该还记得在 bash 的时候,我们有学到一个 read 指令吧?忘记的话,请自行回头去阅读一番。 现在,请你以 read 指令的用途,撰写一个 script ,他可以让使用者输入:1 first name 与 2. last name, 最后并且在屏幕上显示:『Your full name is: 』的内容: 
[root@linux scripts]# vi sh02.sh 
#!/bin/bash 
# Program: 
#  Let user keyin their first and last name, and show their full name. 
# History: 
# 2005/08/23 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 

read -p "Please input your first name: " firstname 
read -p "Please input your last name:  " lastname 
echo -e "\nYour full name is: $firstname $lastname" 

  
将上面这个 sh02.sh 执行一下,你就能够发现使用者自己输入的变量可以被取用的哩! 很不错吧!加油! 



-------------------------------------------------------------------------------- 

利用 date 进行档案的建立  
想象一个状况,如果我每天要进行备份,而备份的数据又不想被覆盖掉,也就是说, 我想要将每天备份的数据放在不同的档案中。哇!这真困扰啊?难道要我每天去修改 script ? 不需要啊!因为每天的『日期』并不相同,所以我可以将档名取成类似: backup.20050802 , 不就可以每天一个不同档名了吗?呵呵!确实如此。好了,接下来出个例子: 我想要建立三个空的档案,档名最开头由使用者输入决定,假设使用者输入 filename 好了, 那今天的日期是 2005/08/23 ,我想要以前天、昨天、今天的日期来建立这个档案,亦即 filename_20050821, filename_20050822, filename_20050823 ,该如何是好? 
[root@linux scripts]# vi sh03.sh 
#!/bin/bash 
# Program: 
#  User can keyin filename to touch 3 new files. 
# History: 
# 2005/08/23 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 

# 1. 让使用者输入文件名称,并取得 fileuser 这个变量; 
echo -e "I will use 'touch' command to create 3 files." 
read -p "Please input the filename what you want: " 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 

  
我透过一些简单的动作,这些动作都可以在 bash 那一章里面找到, 包括小指令 (`) 的取得讯息、变量的设定功能、变量的累加以及利用 touch 指令辅助! 如果您开始执行这个 sh03.sh 之后,你可以进行两次输入,一次直接按 [Enter] 来查阅档名是啥? 一次可以输入一些字符,这样来判断你的档案喔!关于 date 的指令应用,请 man date 吧! ^_^ 



-------------------------------------------------------------------------------- 

数值运算的方法  
各位看官应该还记得,我们可以使用 declare 来定义变量的类型吧?! 这样才能够进行加减运算啊!可惜的是, bash shell 里头预设仅支持到整数的数据。 OK!那我们来玩玩看,如果我们要使用者输入两个变量,然后将两个变量的内容相乘, 最后输出相乘的结果,那可以怎么做? 
[root@linux scripts]# vi sh04.sh 
#!/bin/bash 
# Program: 
#  User can input 2 integer to cross by! 
# History: 
# 2005/08/23 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 
echo -e "You SHOULD input 2 number, I will cross they! \n" 
read -p "first number:  " firstnu 
read -p "second number: " secnu 
total=$(($firstnu*$secnu)) 
echo -e "\nThe number $firstnu x $secnu is ==> $total" 

  
在数字的运算上,我们可以使用『 declare -i total=$firstnu*$secnu 』 也可以使用上面的方式来进行!基本上,鸟哥比较建议使用这样的方式来进行运算:  
var=$((运算内容)) 
不但容易记忆,而且也比较方便的多~未来您可以使用这种方式来计算的呀!至于数值运算上的处理, 则有:+, -, *, /, %等等。 那个 % 是取余数啦~举例来说, 13 对 3 取余数,结果是 13=4*3+1,所以余数是 1 啊!就是: 
[root@linux scripts]# nu=$((13%3)); echo $nu 


  
这样了解了吧?!多多学习与应用喔! ^_^ 


-------------------------------------------------------------------------------- 
善用判断式 

在 bash 章节中,我们提到过 $? 这个变量所代表的意义, 此外,也透过 && 及 || 来作为前一个指令是否能够成功进行的一个参考。 那么,如果我想要知道 /dmtsai 这个目录是否存在时,难道一定要使用 ls 来执行, 然后再以 $? 来判断执行成果吗?呵呵!当然不需要! 我们可以透过『 test 』这个指令来侦测呢! 


-------------------------------------------------------------------------------- 
利用 test 指令的测试功能 

当我要检测系统上面某些档案或者是相关的属性时,利用 test 这个指令来工作, 真是好用得不得了,举例来说,我要检查 /dmtsai 是否存在时,使用: 
[root@linux ~]# test -e /dmtsai 

  
执行结果并不会显示任何讯息,但最后我们可以透过 $? 或 && 及 || 来展现整个结果呢! 例如我们在将上面的例子改写成这样: 
[root@linux ~]# test -e /dmtsai && echo "exist" || echo "Not exist" 

  
最终的结果可以告知我们是『exist』还是『Not exist』呢!那我知道 -e 是测试一个『东西』在不在, 如果还想要测试一下该档名是啥玩意儿时,还有哪些标志可以来判断的呢?呵呵!有底下这些东西喔! 

测试的标志 代表意义  
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  
-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 判断 file2 与 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  

OK!现在我们就利用 test 来帮我们写几个简单的例子。首先,判断一下, 让使用者输入一个档名,我们判断: 
这个档案是否存在,若不存在则给予一个『Filename does not exist』的讯息,并中断程序;  
若这个档案存在,则判断他是个档案或目录,结果输出『Filename is regular file』或 『Filename is directory』  
判断一下,执行者的身份对这个档案或目录所拥有的权限,并输出权限数据! 
你可以先自行创作看看,然后再跟底下的结果讨论讨论。注意利用 test 与 && 还有 || 等标志! 
[root@linux scripts]# vi sh05.sh 
#!/bin/bash 
# Program: 
#  Let user input a filename, the program will search the filename 
# 1.) exist? 2.) file/directory? 3.) file permissions  
# History: 
# 2005/08/25 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 

# 1. 让使用者输入档名,并且判断使用者是否真的有输入字符串? 
echo -e "The program will show you that filename is exist which input by you.\n\n" 
read -p "Input a filename : " filename 
test -z $filename && echo "You MUST input a filename." && exit 0 
# 2. 判断档案是否存在? 
test ! -e $filename && echo "The filename $filename DO NOT exist" && exit 0 
# 3. 开始判断档案类型与属性 
test -f $filename && filetype="regulare file" 
test -d $filename && filetype="directory" 
test -r $filename && perm="readable" 
test -w $filename && perm="$perm writable" 
test -x $filename && perm="$perm executable" 
# 4. 开始输出信息! 
echo "The filename: $filename is a $filetype" 
echo "And the permission are : $perm" 

  
很有趣的例子吧!您可以自行再以其它的案例来撰写一下可用的功能呢! 



-------------------------------------------------------------------------------- 
利用判断符号 [ ] 

除了我们很喜欢使用的 test 之外,其实,我们还可以利用判断符号『 [ ] 』来进行数据的判断呢! 举例来说,如果我想要知道 $HOME 这个变量是否为空的,可以这样做: 
[root@linux ~]# [ -z "$HOME" ] 

  
但使用 [] 要特别注意的是,在上述的每个组件中间都需要有空格键来分隔,假设我空格键使用『□』来表示, 那么,在这些地方你都需要有空格键: 
[  "$HOME"  ==  "$MAIL"  ] 
[□"$HOME"□==□"$MAIL"□] 
 ↑       ↑  ↑       ↑ 

  
上面的例子在说明,两个字符串 $HOME 与 $MAIL 是否相同的意思,相当于 test $HOME = $MAIL 的意思啦! 而如果没有空白分隔,例如 [$HOME==$MAIL] 时,我们的 bash 就会显示错误讯息了!这可要很注意啊! 所以说,您最好要注意: 
在中括号 [] 内的每个组件都需要有空格键来分隔;  
在中括号内的变量,最好都以双引号来设定;  
在中括号内的常数,最好都以单或双引号来设定。 
举例来说,假如我设定了 name="VBird Tsai" ,然后这样判定: 
[root@linux ~]# name="VBird Tsai" 
[root@linux ~]# [ $name == "VBird" ] 
bash: [: too many arguments 

  
为什么呢?因为 $name 如果没有使用双引号刮起来,那么上面的判定式会变成:  
[ VBird Tsai == "VBird" ]  
而不是我们要的:  
[ "VBird Tsai" == "VBird" ]  
这可是差很多的喔!另外,中括号的使用方法与标志与 test 几乎一模一样啊~ 只是中括号比较常用在条件判断式 if ..... then ..... fi 的情况中就是了。 好,那我们也继续来做一个小案例好了: 
当执行一个程序的时候,这个程序会让使用者选择 Y 或 N ,  
如果使用者输入 Y 或 y 时,就显示『 OK, continue 』  
如果使用者输入 n 或 N 时,就显示『 Oh, interrupt !』  
如果不是 Y/y/N/n 之内的其它字符,就显示『I don't know what is your choise』 
利用中括号、 && 与 || 来继续吧! 
[root@linux scripts]# vi sh06.sh 
#!/bin/bash 
# Program: 
#  This program will show the user's choice 
# History: 
# 2005/08/25 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 

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 is your choise" && exit 0 

  
很有趣吧!利用这个字符串判别的方法,我们就可以很轻松的将使用者想要进行的工作分门别类呢! 接下来,我们再来谈一些其它有的没有的东西吧! 

Tips: 
为什么判断式里面下达等于要用 == 而不是一个 = 就好了呢?我们在前一章正规表示法里面的 awk 提到, 只有一个 = 用来给予一个变量设定其内容,逻辑判断时,则会给予两个等于, 亦即『比较』而非『设定』的意思~这里要好好的分辨一下喔! ^_^    


-------------------------------------------------------------------------------- 
Shell script 的预设变数($0, $1...) 

其实,当我们执行一个 shell script 时,在这个 shell script 里面就已将帮我们做好一些可用的变量了。 举例来说,在不久的将来,您就会发现,当我们要启动一个系统服务时,可能会下达类似这样的指令: 
[root@linux ~]# /etc/init.d/crond restart 

  
那是啥玩意儿?呵呵!就是『向 /etc/init.d/crond 这个 script 下达 restart 的指令』, 咦!我们不是都使用 read 来读取使用者输入的变量内容吗?为啥我可以直接在 script 后面接上这个参数? 这是因为 shell script 帮我们设定好一些指定的变量了!变量的对应是这样的: 

/path/to/scriptname  opt1  opt2  opt3  opt4  ... 
       $0             $1    $2    $3    $4   ... 

  
这样够清楚了吧?!执行的文件名为 $0 这个变量,第一个接的参数就是 $1 啊~ 所以,只要我们在 script 里面善用 $1 的话,就可以很简单的立即下达某些指令功能了! 好了,来做个例子吧~假设我要执行一个 script ,执行后,该 script 会自动列出自己的档名, 还有后面接的前三个参数,该如何是好? 
[root@linux scripts]# vi sh07.sh 
#!/bin/bash 
# Program: 
#  The program will show it's name and first 3 parameters. 
# History: 
# 2005/08/25 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 

echo "The script naem is ==> $0" 
[ -n "$1" ] && echo "The 1st paramter is ==> $1" || exit 0 
[ -n "$2" ] && echo "The 2nd paramter is ==> $2" || exit 0 
[ -n "$3" ] && echo "The 3th paramter is ==> $3" || exit 0 

  
这支程序里面鸟哥加上了一些控制式,亦即利用 && 及 || 来加以判断 $1 ~ $3 是否存在? 若存在才显示,若不存在就中断~执行结果如下: 
[root@linux scripts]# sh sh07.sh theone haha quot 
The script naem is ==> sh07.sh 
The 1st paramter is ==> theone 
The 2nd paramter is ==> haha 
The 3th paramter is ==> quot 

  
上面这七的例子都很简单吧?几乎都是利用 bash 的相关功能而已~ 不难啦~底下我们就要使用条件判断式来进行一些分别功能的设定了,好好瞧一瞧先~  

-------------------------------------------------------------------------------- 
条件判断式: 

只要讲到『程序』的话,那么条件判断式,亦即是『 if then 』这种判别式肯定一定要学习的! 因为很多时候,我们都必须要依据某些数据来判断程序该如何进行。举例来说,我们在上头不是有练习当使用者输入 Y/N 时,必须要执行不同的讯息输出吗?简单的方式可以利用 && 与 || ,但如果我还想要执行一堆指令呢? 那真的得要 if then 来帮忙啰~底下我们就来聊一聊! 


-------------------------------------------------------------------------------- 
利用 if .... then 

这个 if .... then 是最常见的条件判断式了~简单的说,就是当符合某个条件判断的时候, 就予以进行某项工作就是了。我们可以简单的这样看: 
if [ 条件判断式 ]; then 
当条件判断式成立时,可以进行的指令工作内容; 
fi 

  
至于条件判断式的判断方法,与前一小节的介绍相同啊!较特别的是,如果我有多个条件要判别时, 除了 sh06.sh 那个案例,也就是将多个条件写入一个中括号内的情况之外, 我还可以有多个中括号来隔开喔!而括号与括号之间,则以 && 或 || 来隔开,他们的意义是:  
&& 代表 AND ;  
|| 代表 or ; 
所以,在使用中括号的判断式中, && 及 || 就与指令下达的状态不同了。举例来说, sh06.sh 那个例子我可以改写成这样: 
[root@linux scripts]# vi sh06-2.sh 
#!/bin/bash 
# Program: 
#  This program will show the user's choice 
# History: 
# 2005/08/25 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 

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 is your choise" && exit 0 

  
不过,由这个例子看起来,似乎也没有什么了不起吧? sh06.sh 还比较简单呢~ 但是,如果我们考虑底下的状态,您就会知道 if then 的好处了: 
if [ 条件判断式 ]; then 
当条件判断式成立时,可以进行的指令工作内容; 
else 
当条件判断式不成立时,可以进行的指令工作内容; 
fi 

  
如果考虑更复杂的情况,则可以使用这个语法: 
if [ 条件判断式一 ]; then 
当条件判断式一成立时,可以进行的指令工作内容; 
elif [ 条件判断式二 ]; then 
当条件判断式二成立时,可以进行的指令工作内容; 
else 
当条件判断式一与二均不成立时,可以进行的指令工作内容; 
fi 

  
那我就可以将 sh06-2.sh 改写成这样: 
[root@linux scripts]# vi sh06-3.sh 
#!/bin/bash 
# Program: 
#  This program will show the user's choice 
# History: 
# 2005/08/25 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 

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 is your choise" 
fi 

  
是否程序变得很简单,而且依序判断,可以避免掉重复判断的状况,这样真的很容易设计程序的啦! ^_^ 好了,那么如果我要侦测你所输入的参数是否为 hello 呢 , 也就是说,如果我想要知道,你在程序后面所接的第一个参数 (就是 $1 啊!) 是否为 hello , 
如果是的话,就显示 "Hello, how are you ?";  
如果没有加任何参数,就提示使用者必须要使用的参数下达法;  
而如果加入的参数不是 hello ,就提醒使用者仅能使用 hello 为参数。 
整个程序的撰写可以是这样的: 
[root@linux scripts]# vi sh08.sh 
#!/bin/bash 
# Program: 
#  Show "Hello" from $1.... 
# History: 
# 2005/08/28 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 

if [ "$1" == "hello" ]; then 
echo "Hello, how are you ?" 
elif [ "$1" == "" ]; then 
echo "You MUST input parameters, ex> $0 someword" 
else 
echo "The only parameter is 'hello'" 
fi 

  
然后您可以执行这支程序,分别在 $1 的位置输入 hello, 没有输入与随意输入, 就可以看到不同的输出啰~是否还觉得挺简单的啊! ^_^。事实上, 学到这里,也真的很厉害了~好了,底下我们继续来玩一些比较大一点的啰~ 我们在前一章已经学会了 grep 这个好用的玩意儿,那么多学一个叫做 netstat 的指令, 这个指令可以查询到目前主机有开启的网络服务端口口 (service ports), 相关的功能我们会在服务器架设篇继续介绍,这里您只要知道,我可以利用『 netstat -tuln 』来取得目前主机有启动的服务, 而且取得的信息有点像这样: 
[root@linux ~]# netstat -tuln 
Active Internet connections (only servers) 
Proto Recv-Q Send-Q Local Address   Foreign Address    State 
tcp        0      0 0.0.0.0:199     0.0.0.0:*          LISTEN 
tcp        0      0 :::80           :::*               LISTEN 
tcp        0      0 :::22           :::*               LISTEN 
tcp        0      0 :::25           :::*               LISTEN 

  
上面的重点是特殊字体的那个部分,那些特殊字体的部分代表的就是 port 啰~ 那么每个 port 代表的意义为何呢?几个常见的 port 与相关网络服务的关系是:  
80: WWW  
22: ssh  
21: ftp  
25: mail 
那我如何透过 netstat 去侦测我的主机是否有开启这四个主要的网络服务端口口呢? 我可以简单的这样去写这个程序喔: 
[root@linux scripts]# vi sh09.sh 
#!/bin/bash 
# Program: 
#  Using netstat and grep to detect WWW,SSH,FTP and Mail services. 
# History: 
# 2005/08/28 VBird First release 
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin 
export PATH 

# 1. 先作一些告知的动作而已~ 
echo "Now, the services of your Linux system will be detect!" 
echo -e "The www, ftp, ssh, and mail will be detect! \n" 

# 2. 开始进行一些测试的工作,并且也输出一些信息啰! 
testing=`netstat -tuln | grep ":80 "` 
if [ "$testing" != "" ]; then 
echo "WWW is running in your system." 
fi 
testing=`netstat -tuln | grep ":22 "` 
if [ "$testing" != "" ]; then 
echo "SSH is running in your system." 
fi 
testing=`netstat -tuln | grep ":21 "` 
if [ "$testing" != "" ]; then 
echo "FTP is running in your system." 
fi 
testing=`netstat -tuln | grep ":25 "` 
if [ "$testing" != "" ]; then 
echo "Mail is running in your system." 
fi 

  
这样又能够一个一个的检查啰~是否很有趣啊! ^_^。接下来,我们再来玩更难一点的。 我们知道可以利用 date 来显示日期与时间,也可以利用 $((计算式)) 来计算数值运算。 另外, date 也可以用来显示自 19710101 以来的『总秒数』 (请自行查阅 man date 及 info date) 。那么,您是否可以撰写一支小程序,用来『计算退伍

分享到:
评论

相关推荐

    鸟哥学习Shell Scripts

    学习unix shell编程不错的材料。

    鸟哥的 Linux 私房菜第13章-学习 Shell Scripts1

    第十三章、学习 Shell Scripts最近更新日期:2009/02/18如果你真的很想要走信息这条路,并且想要好好的管理好属于你的主机,那么,别说鸟哥不告诉

    Wicked Cool Shell Scripts

    从提供的信息来看,文章摘录自一本名为《Wicked Cool Shell Scripts》的书籍,这本书由Dave Taylor和Brandon Perry共同编写,内容涵盖了为Linux、OSX和UNIX系统设计的101个shell脚本。书籍受到了业界的高度评价,被...

    13_学习_Shell_Scripts

    学习Shell Scripts的原因** 学习Shell脚本的原因主要在于以下几点: - **自动化日常任务**:通过编写脚本,你可以将重复性的任务集成到一个可执行文件中,减少手动操作,提高效率。 - **系统管理**:在Linux环境...

    cdr-rep shell scripts

    "cdr-rep shell scripts" 是一个与 Informix 数据库管理系统相关的脚本集合,主要用于处理、管理和报告 Informix 数据。在 IT 领域,尤其是在数据库管理中,shell 脚本通常被用来自动化日常任务,如数据备份、监控、...

    Linux操作系统学习

    第0章 计算机概论 第1章 Linux是什么 第2章 Linux 如何学习 第3章 主机规划与磁盘分区 第4章 安装Centos5.x 与多重引导小技巧 第5章 首次登入与在线求助(man page) ...第13章 学习Shell Scripts ........

    Private_Shell_Scripts

    在本集合中,我们有机会学习到各种基础和高级的Shell脚本编写技巧。 1. **Shell脚本基础**:首先,我们需要了解Bash(Bourne-Again SHell)是最常见的Shell类型,它是Linux默认的Shell。基础概念包括变量、条件语句...

    shellscripts:暴力框架的 Shellscripts

    总的来说,"shellscripts:暴力框架的 Shellscripts"是一个关于利用Shell脚本增强Chisimba框架功能的学习资源。通过研究和实践这些脚本,用户可以提升自己的Shell编程技能,并能够更好地利用Chisimba框架进行自动化...

    linux shell scripts

    学习Shell脚本的过程中,还会涉及一些重要的命令,如`cd`改变目录,`ls`列出目录内容,`mkdir`创建目录,`rm`删除文件或目录,`cp`复制文件或目录,`mv`移动或重命名文件或目录。 `Shell.pdf`可能包含了关于Bash ...

    ShellScripts2009

    通过学习和实践"ShellScripts2009",你可以提升对Linux系统的掌控能力,更好地利用Shell脚本提高工作效率。无论你是系统管理员还是开发者,掌握Shell脚本都将为你打开一扇通往自动化和效率提升的大门。

    Shell_Scripts.zip

    学习和使用Shell脚本,需要掌握基本的Shell语法,如变量、条件语句、循环、函数等。同时,熟悉Linux命令行工具也是必不可少的,因为许多脚本都是基于这些工具构建的。 总的来说,这个"Shell_Scripts.zip"压缩包为...

    shellscripts:ITN170

    "shellscripts:ITN170"可能指的是一个关于Shell脚本编程的课程或者项目,其中包含了对Shell脚本深入学习和实践的内容。在这个名为"shellscripts-master"的压缩包文件中,我们可以期待找到一系列关于Shell脚本编写、...

    sample_shellscripts

    标题“sample_shellscripts”暗示了这是一个关于Shell脚本的示例集合。Shell脚本是Linux或Unix操作系统中的一种编程方式,它允许用户通过命令行执行一系列操作,从而自动化日常任务。在这一压缩包中,"sample_shell...

    shell_scripts:常用的一些 shell 脚本

    "shell_scripts"这个压缩包文件包含了作者自定义的一些常用脚本,可以帮助提高工作效率,简化操作流程。下面将详细阐述Shell脚本的基本概念、常用命令以及如何创建和运用这些脚本。 一、Shell脚本基础 1. Shell:...

    shellScripts:只是一些用于测试的shell脚本

    这个压缩包文件"shellScripts:只是一些用于测试的shell脚本"显然包含了一系列用于实验和学习目的的Shell脚本。以下是对这些脚本可能涉及的知识点的详细解释: 1. **Shell基础**:Shell是操作系统提供的一个命令行...

    shellscripts:包含一些将文件转换为 mp4 格式的 shell 脚本

    这个名为"shellscripts"的压缩包显然包含了几个这样的脚本,专门用于将文件转换成mp4格式,以及检查和修复mp3文件。让我们深入探讨一下shell脚本及其在这些特定任务中的应用。 首先,让我们关注将文件转换为mp4格式...

Global site tag (gtag.js) - Google Analytics