马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
如果您觉得本篇CentOSLinux教程讲得好,请记得点击右边漂浮的分享程序,把好文章分享给你的好朋友们!一.Shell的基础语法
1.变量
依照常规,Shell变量由全年夜写字母加下划线构成,有两品种型的Shell变量:
情况变量
情况变量能够从父历程传给子历程,因而Shell历程的情况变量能够从以后Shell历程传给fork出来的子历程。用printenv下令能够显现以后Shell历程的情况变量。
当地变量
只存在于以后Shell历程,用set下令能够显现以后Shell历程中界说的一切变量(包含当地变量和情况变量)和函数。
情况变量是任何历程都有的观点,而当地变量是Shell独有的观点。在Shell中,情况变量和当地变量的界说和用法类似。在Shell中界说或赋值一个变量:
$VARNAME=value
注重等号双方都不克不及有空格,不然会被Shell注释成下令和下令行参数。
一个变量界说后仅存在于以后Shell历程,它是当地变量,用export下令能够把当地变量导出为情况变量,界说和导出情况变量一般能够一步完成:
$exportVARNAME=value也能够分两步完成:
$VARNAME=value$exportVARNAME用unset下令能够删除已界说的情况变量或当地变量。
$unsetVARNAME假如一个变量叫做VARNAME,用${VARNAME}能够暗示它的值,在不引发歧义的情形下也能够用$VARNAME暗示它的值。经由过程以下例子对照这两种暗示法的分歧:
$echo$SHELL$echo$SHELLabc$echo$SHELLabc$echo${SHELL}abc注重,在界说变量时不必$,取变量值时要用$。和C言语分歧的是,Shell变量不必要明白界说范例,现实上Shell变量的值都是字符串,好比我们界说VAR=45,实在VAR的值是字符串45而非整数。Shell变量不必要先界说后利用,假如对一个没有界说的变量取值,则值为空字符串。
2.文件名代换(Globbing):*?[]
这些用于婚配的字符称为通配符(Wildcard),详细以下:
2.1.通配符
*
婚配0个或多个恣意字符
?
婚配一个恣意字符
[多少字符]
婚配方括号中恣意一个字符的一次呈现
$ls/dev/ttyS*$lsch0?.doc$lsch0[0-2].doc$lsch[012][0-9].doc注重,Globbing所婚配的文件名是由Shell睁开的,也就是说在参数还没传给步伐之前已睁开了,好比上述lsch0[012].doc下令,假如以后目次下有ch00.doc和ch02.doc,则传给ls下令的参数实践上是这两个文件名,而不是一个婚配字符串。
3.下令代换:`或$()
由反引号括起来的也是一条下令,Shell先实行该下令,然后将输入了局立即代换到以后下令行中。比方界说一个变量寄存date下令的输入:
$DATE=`date`$echo$DATE下令代换也能够用$()暗示:
$DATE=$(date)
4.算术代换:$(())
用于算术盘算,$(())中的Shell变量取值将转换成整数,比方:
$VAR=45$echo$(($VAR+3))$(())中只能用+-*/和()运算符,而且只能做整数运算。
5.本义字符
和C言语相似,在Shell中被用作本义字符,用于往除紧跟厥后的单个字符的特别意义(回车除外),换句话说,紧跟厥后的字符取字面值。比方:
$echo$SHELL/bin/bash$echo$SHELL$SHELL$echo好比创立一个文件名为“$$”的文件能够如许:
$touch$$另有一个字符固然不具有特别寄义,可是要用它做文件名也很贫苦,就是-号。假如要创立一个文件名以-号开首的文件,如许是不可的:
$touch-hellotouch:invalidoption--hTry`touch--helpformoreinformation.即便加上本义也仍是报错:
$touch-hellotouch:invalidoption--hTry`touch--helpformoreinformation.由于各类UNIX下令都把-号开首的下令行参数看成下令的选项,而不会看成文件名。假如非要处置以-号开首的文件名,能够有两种举措:
$touch./-hello大概
$touch---hello另有一种用法,在后敲回车暗示续行,Shell其实不会立即实行下令,而是把光标移到下一行,给出一个续行提醒符>,守候用户持续输出,最初把一切的续行接到一同看成一个下令实行。比方:
$ls>-l(ls-l下令的输入)
6.单引号
和C言语纷歧样,Shell剧本中的单引号和双引号一样都是字符串的界定符(双引号下一节先容),而不是字符的界定符。单引号用于坚持引号内一切字符的字面值,即便引号内的和回车也不破例,可是字符串中不克不及呈现单引号。假如引号没有配对就输出回车,Shell会给出续行提醒符,请求用户把引号配上对。比方:
$echo$SHELL$SHELL$echoABC(回车)>DE(再按一次回车停止下令)ABCDE
7.双引号
双引号用于坚持引号内一切字符的字面值(回车也不破例),但以下情形除外:
・$加变量名能够取变量的值
・反引号仍暗示下令交换
・$暗示$的字面值
・`暗示`的字面值
・"暗示"的字面值
・暗示的字面值
・除以下情况以外,在别的字符后面的无特别寄义,只暗示字面值
$echo"$SHELL"/bin/bash$echo"`date`"SunApr2011:22:06CEST2003$echo"Idsay:"Goforit""Idsay:"Goforit"$echo""(回车)>"(再按一次回车停止下令)"$echo""
2、Shell剧本语法
1.前提测试:test[
下令test或[能够测试一个前提是不是建立,假如测试了局为真,则该下令的ExitStatus为0,假如测试了局为假,则下令的ExitStatus为1(注重与C言语的逻辑暗示恰好相反)。比方测试两个数的巨细干系:
$VAR=2$test$VAR-gt1$echo$?0$test$VAR-gt3$echo$?1$[$VAR-gt3]$echo$?1固然看起来很奇异,但左方括号[的确是一个下令的名字,传给下令的各参数之间应当用空格离隔,好比,$VAR、-gt、3、]是[下令的四个参数,它们之间必需用空格离隔。下令test或[的参数情势是不异的,只不外test下令不必要]参数。以[下令为例,罕见的测试下令以下表所示:
表1.1.测试下令
[-dDIR]
假如DIR存在而且是一个目次则为真
[-fFILE]
假如FILE存在且是一个一般文件则为真
[-zSTRING]
假如STRING的长度为零则为真
[-nSTRING]
假如STRING的长度非零则为真
[STRING1=STRING2]
假如两个字符串不异则为真
[STRING1!=STRING2]
假如字符串不不异则为真
[ARG1OPARG2]
ARG1和ARG2应当是整数大概取值为整数的变量,OP是-eq(即是)-ne(不即是)-lt(小于)-le(小于即是)-gt(年夜于)-ge(年夜于即是)当中的一个
和C言语相似,测试前提之间还能够做与、或、非逻辑运算:
表1.2.带与、或、非的测试下令
[!EXPR]
EXPR能够是上表中的恣意一种测试前提,!暗示逻辑反
[EXPR1-aEXPR2]
EXPR1和EXPR2能够是上表中的恣意一种测试前提,-a暗示逻辑与
[EXPR1-oEXPR2]
EXPR1和EXPR2能够是上表中的恣意一种测试前提,-o暗示逻辑或
比方:
$VAR=abc$[-dDesktop-a$VAR=abc]$echo$?0注重,假如上例中的$VAR变量事前没有界说,则被Shell睁开为空字符串,会形成测试前提的语法毛病(睁开为[-dDesktop-a=abc]),作为一种好的Shell编程习气,应当老是把变量取值放在双引号当中(睁开为[-dDesktop-a""=abc]):
$unsetVAR$[-dDesktop-a$VAR=abc]bash:[:toomanyarguments$[-dDesktop-a"$VAR"=abc]$echo$?1
2.if/then/elif/else/fi
和C言语相似,在Shell顶用if、then、elif、else、fi这几条下令完成分支把持。这类流程把持语句实质上也是由多少条Shell下令构成的,比方先前讲过的
if[-f~/.bashrc];then.~/.bashrcfi实际上是三条下令,if[-f~/.bashrc]是第一条,then.~/.bashrc是第二条,fi是第三条。假如两条下令写在统一行则必要用;号离隔,一行只写一条下令就不必要写;号了,别的,then前面有换行,但这条下令没写完,Shell会主动续行,把下一行接在then前面看成一条下令处置。和[下令一样,要注重下令和各参数之间必需用空格离隔。if下令的参数构成一便条下令,假如该子下令的ExitStatus为0(暗示真),则实行then前面的子下令,假如ExitStatus非0(暗示假),则实行elif、else大概fi前面的子下令。if前面的子下令一般是测试下令,但也能够是别的下令。Shell剧本没有{}括号,以是用fi暗示if语句块的停止。见下例:
#!/bin/shif[-f/bin/bash]thenecho"/bin/bashisafile"elseecho"/bin/bashisNOTafile"fiif:;thenecho"alwaystrue";fi:是一个特别的下令,称为空下令,该下令不做任何事,但ExitStatus老是真。别的,也能够实行/bin/true或/bin/false失掉真或假的ExitStatus。再看一个例子:
#!/bin/shecho"Isitmorning?Pleaseansweryesorno."readYES_OR_NOif["$YES_OR_NO"="yes"];thenecho"Goodmorning!"elif["$YES_OR_NO"="no"];thenecho"Goodafternoon!"elseecho"Sorry,$YES_OR_NOnotrecognized.Enteryesorno."exit1fiexit0上例中的read下令的感化是守候用户输出一行字符串,将该字符串存到一个Shell变量中。
别的,Shell还供应了&&和||语法,和C言语相似,具有Short-circuit特征,良多Shell剧本喜好写成如许:
test"$(whoami)"!=root&&(echoyouareusinganon-privilegedaccount;exit1)&&相称于“if...then...”,而||相称于“ifnot...then...”。&&和||用于毗连两个下令,而下面讲的-a和-o仅用于在测试表达式中毗连两个测试前提,要注重它们的区分,比方,
test"$VAR"-gt1-a"$VAR"-lt3和以下写法是等价的
test"$VAR"-gt1&&test"$VAR"-lt3
3.case/esac
case下令可类比C言语的switch/case语句,esac暗示case语句块的停止。C言语的case只能婚配整型或字符型常量表达式,而Shell剧本的case能够婚配字符串和Wildcard,每一个婚配分支能够有多少条下令,开端必需以;;停止,实行时找到第一个婚配的分支并实行响应的下令,然后间接跳到esac以后,不必要像C言语一样用break跳出。
#!/bin/shecho"Isitmorning?Pleaseansweryesorno."readYES_OR_NOcase"$YES_OR_NO"inyes|y|Yes|YES)echo"GoodMorning!";;[nN]*)echo"GoodAfternoon!";;*)echo"Sorry,$YES_OR_NOnotrecognized.Enteryesorno."exit1;;esacexit0利用case语句的例子能够在体系办事的剧本目次/etc/init.d中找到。这个目次下的剧本年夜多具有这类情势(以/etc/apache2为例):
case$1instart)...;;stop)...;;reload|force-reload)...;;restart)...*)log_success_msg"Usage:/etc/init.d/apache2{start|stop|restart|reload|force-reload|start-htcacheclean|stop-htcacheclean}"exit1;;esac启动apache2办事的下令是
$sudo/etc/init.d/apache2start$1是一个特别变量,在实行剧本时主动取值为第一个下令行参数,也就是start,以是进进start)分支实行相干的下令。同理,下令行参数指定为stop、reload或restart能够进进别的分支实行中断办事、从头加载设置文件或从头启动办事的相干下令。
4.for/do/done
Shell剧本的for轮回布局和C言语很纷歧样,它相似于某些编程言语的foreach轮回。比方:
#!/bin/shforFRUITinapplebananapear;doecho"Ilike$FRUIT"doneFRUIT是一个轮回变量,第一次轮回$FRUIT的取值是apple,第二次取值是banana,第三次取值是pear。再好比,要将以后目次下的chap0、chap1、chap2等文件名改成chap0~、chap1~、chap2~等(按常规,开端有~字符的文件名暗示一时文件),这个下令能够如许写:
$forFILENAMEinchap?;domv$FILENAME$FILENAME~;done也能够如许写:
$forFILENAMEin`lschap?`;domv$FILENAME$FILENAME~;done
5.while/do/done
while的用法和C言语相似。好比一个考证暗码的剧本:
#!/bin/shecho"Enterpassword:"readTRYwhile["$TRY"!="secret"];doecho"Sorry,tryagain"readTRYdone上面的例子经由过程算术运算把持轮回的次数:
#!/bin/shCOUNTER=1while["$COUNTER"-lt10];doecho"Herewegoagain"COUNTER=$(($COUNTER+1))doneShell另有until轮回,相似C言语的do...while轮回。本章从略。
习题
1、把下面考证暗码的步伐修正一下,假如用户输错五次暗码就报错加入。
6.地位参数和特别变量
有良多特别变量是被Shell“主动赋值”的,我们已碰到了$?和$1,如今总结一下:
表6.1.经常使用的地位参数和特别变量
$0
相称于C言语main函数的argv[0]
$1、$2...
这些称为地位参数(PositionalParameter),相称于C言语main函数的argv[1]、argv[2]...
$#
相称于C言语main函数的argc-1,注重这里的#前面不暗示正文
$@
暗示参数列表"$1""$2"...,比方能够用在for轮回中的in前面。
$?
上一条下令的ExitStatus
$$
以后Shell的历程号
地位参数能够用shift下令左移。好比shift3暗示本来的$4如今酿成$1,本来的$5如今酿成$2等等,本来的$1、$2、$3抛弃,$0不挪动。不带参数的shift下令相称于shift1。比方:
#!/bin/shecho"Theprogram$0isnowrunning"echo"Thefirstparameteris$1"echo"Thesecondparameteris$2"echo"Theparameterlistis$@"shiftecho"Thefirstparameteris$1"echo"Thesecondparameteris$2"echo"Theparameterlistis$@"
7.函数
和C言语相似,Shell中也有函数的观点,可是函数界说中没有前往值也没有参数列表。比方:
#!/bin/shfoo(){echo"Functionfooiscalled";}echo"-=start=-"fooecho"-=end=-"注重函数体的左花括号{和前面的下令之间必需有空格或换行,假如将最初一条下令和右花括号}写在统一行,下令开端必需有;号。
在界说foo()函数时其实不实行函数体中的下令,就像界说变量一样,只是给foo这个名字一个界说,到前面挪用foo函数的时分(注重Shell中的函数挪用不写括号)才实行函数体中的下令。Shell剧本中的函数必需先界说后挪用,一样平常把函数界说都写在剧本的后面,把函数挪用和别的下令写在剧本的最初(相似C言语中的main函数,这才是全部剧本实践入手下手实行下令的中央)。
Shell函数没有参数列表其实不暗示不克不及传参数,现实上,函数就像是迷你剧本,挪用函数时能够传恣意个参数,在函数内一样是用$0、$1、$2等变量来提取参数,函数中的地位参数相称于函数的部分变量,改动这些变量其实不会影响函数表面的$0、$1、$2等变量。函数中能够用return下令前往,假如return前面跟一个数字则暗示函数的ExitStatus。
上面这个剧本能够一次创立多个目次,各目次名经由过程下令行参数传进,剧本逐一测试各目次是不是存在,假如目次不存在,起首打印信息然后试着创立该目次。
#!/bin/shis_directory(){DIR_NAME=$1if[!-d$DIR_NAME];thenreturn1elsereturn0fi}forDIRin"$@";doifis_directory"$DIR"then:elseecho"$DIRdoesntexist.Creatingitnow..."mkdir$DIR>/dev/null2>&1if[$?-ne0];thenecho"Cannotcreatedirectory$DIR"exit1fifidone注重is_directory()前往0暗示真前往1暗示假。
三Shell剧本的调试***
Shell供应了一些用于调试剧本的选项,以下所示:
-n
读一遍剧本中的下令但不实行,用于反省剧本中的语法毛病
-v
一边实行剧本,一边将实行过的剧本下令打印到尺度毛病输入
-x
供应跟踪实行信息,将实行的每条下令和了局顺次打印出来
利用这些选项有三种***,一是在下令行供应参数
$sh-x./script.sh二是在剧本开首供应参数
#!/bin/sh-x第三种***是在剧本顶用set下令启用或禁用参数
#!/bin/shif[-z"$1"];thenset-xecho"ERROR:InsufficientArgs."exit1set+xfiset-x和set+x分离暗示启用和禁用-x参数,如许能够只对剧本中的某一段举行跟踪调试。
欢迎大家来到仓酷云论坛! |