基础shell编程

基础shell编程

1shell脚本介绍

一个shell脚本可以包含一个或多个命令。当然可以不必只为了两个命令就编写一个shell脚本,一切由用户自己决定。

1.1、使用shell脚本的原因

shell脚本在处理自动循环或大的任务方面可节省大量的时间,且功能强大。

1.2、脚本内容

脚本不是复杂的程序,它是按行解释的。脚本第一行总是以#!/bin/sh开始,这段脚本通知shell使用系统上的Bourne shell解释器。任何脚本都可能有注释,加注释需要此行的第一个字符为#,解释器对此行不予解释。在脚本从上到下执行,运行脚本前需要增加其执行权限。确保正确建立脚本路径,这样只用文件名就可以运行它了。

2、条件测试

写脚本时,有时要判断字符串是否相等,可能还要检查文件状态或是数字测试。基于这

些测试才能做进一步动作。Test命令用于测试字符串,文件状态和数字,也很适合于ifthenelse条件结构。

2.1、测试文件状态

test一般有两种格式,即:

test condition

[ condition ]

使用方括号时,要注意在条件两边加上空格。

文件状态测试:

-d    目录

-f     正规文件

-L    符号连接

-r     可读

-s    文件长度大于0、非空

-w   可写

-u    文件有suid位设置

-x    可执行

使用两种方法测试文件scores.txt是否可写并用最后退出状态测试是否成功。记住,0表示成功,其他为失败。

[ -w scores.txt ]

echo $?

0

或者

test –w scores.txt

echo $?

0

2.2、测试时使用逻辑操作符

测试文件状态是否为OK,但是有时要比较两个文件状态。shell提供三种逻辑操作完成此功能。

-a    逻辑与,操作符两边均为真,结果为真,否则为假。

-o    逻辑或,操作符两边一边为真,结果为真,否则为假。

!      逻辑否,条件为假,结果为真。

下面的例子测试两个文件是否均可读。

       [ -w result.txt –a –w scores.txt ]

2.3、字符串测试

字符串测试是错误捕获很重要的一部分,特别在测试用户输入或比较变量时尤为重要。字符串测试有5种格式。

test “string”

test string_operator “string”

test “string” string_operator “string”

[ string_operator string ]

[ string string_operator string ]

这里,string_operator可为:

=     两个字符串相等。

!=    两个字符串不等。

-z    空串。

-n    非空串。

2.4、测试数值

测试数值可以使用许多操作符,一般格式如下:

"number" numeric_operator "number"

或者

[ "number" numeric_operator "number" ]

numeric_operator可为:

-eq   数值相等。

-ne   数值不相等。

-gt   第一个数大于第二个数。

-lt    第一个数小于第二个数。

-le    第一个数小于等于第二个数。

-ge   第一个数大于等于第二个数。

2.5expr用法

expr命令一般用于整数值,但也可用于字符串。一般格式为:

expr argument operator argument

expr也是一个手工命令行计数器。使用乘号时,必须用反斜线屏蔽其特定含义。因为shell可能会误解显示星号的意义。

2.5.1 、增量计数

expr在循环中用于增量计算。首先,循环初始化为0,然后循环值加1,反引号的用法意即替代命令。最基本的一种是从(expr)命令接受输出并将之放入循环变量。

LOOP=0

LOOP=`expr $ LOOP + 1`

2.5.2 、数值测试

可以用expr测试一个数。如果试图计算非整数,将返回错误。这里需要将一个值赋予变量(不管其内容如何),进行数值运算,并将输出导入dev/null,然后测试最后命令状态,如果为0,证明这是一个数,其他则表明为非数值。

VALUE=12

expr $VALUE + 10 > /dev/null

echo $?

0

expr也可以返回其本身的退出状态,不幸的是返回值与系统最后退出命令刚好相反,成功返回1,任何其他值为无效或错误。下面的例子测试两个字符串是否相等,这里字符串为

hello”和“hello”。

VALUE=hello

expr $VALUE = “hello”

1

echo $?

0

expr返回1。不要混淆了,这表明成功。现在检验其最后退出状态,返回0表示测试成功,“hello”确实等于“hello”。

3、控制流结构

所有功能脚本必须有能力进行判断,也必须有能力基于一定条件处理相关命令。

3.1、退出状态

任何命令进行时都将返回一个退出状态。如果要观察其退出状态,使用最后状态命令:

$echo $?

要退出当前进程,shell提供命令exit,一般格式为:

exit n

其中,n为一数字。

如果只在命令提示符下键入exit,假定没有在当前状态创建另一个shell,将退出当前shell。如果在脚本中键入exitshell将试图(通常是这样)返回上一个命令返回值。有许多退出脚本值,但其中相对于脚本和一般系统命令最重要的有两种,即:

退出状态0 退出成功,无错误。

退出状态1 退出失败,某处有错误。

可以在shell脚本中加入自己的退出状态(它将退出脚本)。加入脚本本身的退出脚本值是一种好的编程习惯。如果愿意,用户可以在一个用户输入错误后或一个不可覆盖错误后或正常地处理结束后退出脚本。

3.2 控制结构

shell提供一系列命令声明语句等补救措施来帮助你在命令成功或失败时,或需要处

理一个命令清单时采取正确的动作。这些命令语句大概分两类:循环和流控制。

3.2.1 、流控制

ifthenelse语句提供条件测试。测试可以基于各种条件。例如文件的权限、长度、数值或字符串的比较。这些测试返回值或者为真(0),或者为假(1)。基于此结果,可以进行相关操作。

case语句允许匹配模式、单词或值。一旦模式或值匹配,就可以基于这个匹配条件作其他声明。

3.2.2 、循环

循环或跳转是一系列命令的重复执行过程,3种循环语句:

for   循环每次处理依次列表内信息,直至循环耗尽。

until        循环此循环语句不常使用, until循环直至条件为真。条件部分在循环末尾部分。

while       循环while循环当条件为真时,循环执行,条件部分在循环头。

3.3if then else语句

if语句测试条件,测试条件返回真(0)或假(1)后,可相应执行一系列语句。if语句结构对错误检查非常有用。其格式为:

if 条件1

then 命令1

elif 条件2

then 命令2

else 命令3

fi

if语句必须以单词fi终止。在if语句中漏写f i是最一般的错误。我自己有时也是这样。elifelse为可选项,如果语句中没有否则部分,那么就不需要elifelse部分。If语句可以有许多elif部分。最常用的if语句是if then fi结构。

null:命令用法

shell提供了:空命令。空命令永远为真(也正是预想的那样)。

3.4case语句

case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。case语句格式如下:

case i n

模式1)

命令1

;;

模式2

命令2

;;

esac

case工作方式如上所示。取值后面必须为单词in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至;;。

取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续

其他模式。如果无一匹配模式,使用星号*捕获该值,再接受其他输入。

模式部分可能包括元字符,与在命令行文件扩展名例子中使用过的匹配模式类型相同,

即:

*     任意字符。

?      任意单字符。

[..]   类或范围中任意字符。

使用case时,也可以指定“|”符号作为或命令,例如vt100 | vt102匹配模式vt100v t102

3.5for循环

for循环一般格式为:

for 变量名in列表

do

命令1

命令2

done

当变量值在列表里,for循环即执行一次所有命令,使用变量名访问列表中取值。命令可为任何有效的shell命令和语句。变量名为任何单词。In列表用法是可选的,如果不用它, for循环使用命令行的位置参数。i n列表可以包含替换、字符串和文件名

3.6until循环

until循环执行一系列命令直至条件为真时停止。until循环与while循环在处理方式上刚好相反。一般while循环优于until循环,但在某些时候—也只是极少数情况下,until循环更加有用。

until循环格式为:

until 条件

命令1

done

条件可为任意测试条件,测试发生在循环末尾,因此循环至少执行一次—请注意这一

点。

3.7while循环

while循环用于不断执行一系列命令,也用于从输入文件中读取数据,其格式为:

while 命令

do

命令1

命令2

...

done

虽然通常只使用一个命令,但在whiledo之间可以放几个命令。命令通常用作测试条件。只有当命令的退出状态为0时,dodone之间命令才被执行,如果退出状态不是0,则循环终止。命令执行完毕,控制返回循环顶部,从头开始直至测试条件为假。

3.8、使用breakcontinue控制循环

有时需要基于某些准则退出循环或跳过循环步。shell提供两个命令实现此功能。

break

continue

3.8.1 break

break命令允许跳出循环。break通常在进行一些处理后退出循环或case语句。如果是在一个嵌入循环里,可以指定跳出的循环个数。例如如果在两层循环内,用break 2刚好跳出整个循环。

3.8.2 continue

continue命令类似于break命令,只有一点重要差别,它不会跳出循环,只是跳过这个循环步。

4shell 函数

shell允许将一组命令集或语句形成一个可用块,这些块称为shell函数。函数由两部分组成:

函数标题。

函数体。

标题是函数名。函数体是函数内的命令集合。标题名应该唯一;如果不是,将会混淆结

果,因为脚本在查看调用脚本前将首先搜索函数调用相应的shell

定义函数的格式为:

函数名()

{

命令1

...

}

或者

函数名(){

命令1

...

}

两者方式都可行。如果愿意,可在函数名前加上关键字function,这取决于使用者。

function 函数名()

{ ...

}

可以将函数看作是脚本中的一段代码,但是有一个主要区别。执行函数时,它保留当前

shell和内存信息。此外如果执行或调用一个脚本文件中的另一段代码,将创建一个单独的

shell,因而去除所有原脚本中定义的存在变量。

函数可以放在同一个文件中作为一段代码,也可以放在只包含函数的单独文件中。函数

不必包含很多语句或命令,甚至可以只包含一个echo语句,这取决于使用者。

4.1、在脚本中定义函数

以下是一个简单函数:

hello()

{

echo “Hello there today’s date is `date`”

}

所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。上面的例子中,函数名为hello,函数体包含一个echo语句,反馈当天日期。

4.2、在脚本中使用函数

在脚本中使用函数名hello调用它。函数执行后,控制返回函数调用的下一条语句

4.3、向函数传递参数

向函数传递参数就像在一般脚本中使用特殊变量$1,$2...$9一样,函数取得所传参数后,

将原始参数传回shell脚本,因此最好先在函数内重新设置变量保存所传的参数。函数里调用参数(变量)的转换以下划线开始,后加变量名,如: _ F I L E N A M E_ f i l e n a m e

4.4、从调用函数中返回

当函数完成处理或希望函数基于某一测试语句返回时,可做两种处理:

1) 让函数正常执行到函数末尾,然后返回脚本中调用函数的控制部分。

2) 使用return返回脚本中函数调用的下一条语句,可以带返回值。0为无错误,1为有错误。

return从函数中返回, 用最后状态命令$?决定返回值。

Return 0 无错误返回。

Return 1 有错误返回

如果函数将从测试结果中反馈输出,那么使用替换命令可保存结果,函数调用的替换格式为:

variable name=function_name

函数function_name输出被设置到变量variable_name中。

4.5、在shell中使用函数

当你收集一些经常使用的函数时,可以将之放入函数文件中并将文件载入shell。文件头应包含语句#!/bin/sh,文件名可任意选取,但最好与相关任务有某种实际联系。

. /functions.main<><空格><斜线><文件名>

一旦文件载入shell,就可以在命令行或脚本中调用函数。可以使用set命令查看所有定义的函数。输出列表包括已经载入shell的所有函数。

如果要改动函数,首先用unset命令从shell中删除函数,尽管unset删除了函数以便于此函数对于shell或脚本不可利用,但并不是真正的删除。改动完毕后,再重新载入此文件。有些shell会识别改动,不必使用unset命令,但为了安全起见,改动函数时最好使用unset命令。

4.6、函数调用

函数的两种不同方法:从原文件中调用函数和使用脚本中的函数。

4.7、定位文件不只用于函数

定位文件不只针对于函数,也包含组成配置文件的全局变量。

5、向脚本传递参数

5.1shift命令

向脚本传递参数时,有时需要将每一个参数偏移以处理选项,这就是shift命令的功能。

它每次将参数位置向左偏移一位。

5.2getopts

getopts可以编写脚本,使控制多个命令行参数更加容易。getopts用于形成命令行处理标准形式。

getopts一般格式为:

getopts option_string variable

如:getopts ahfgv OPTION

option_string为指定的5个选项(-a-h-f-g-v),variableOPTION

5.2.1 getopts使用方式

getopts读取option_string,获知脚本中使用了有效选项。getopts查看所有以连字符开头的参数,将其视为选项,如果输入选项,将把这与option_string对比,如果匹配发现,变量设置为OPTION,如果未发现匹配字符,变量能够设置为?。重复此处理过程直到选项输入完毕。

getopts接收完所有参数后,返回非零状态,意即参数传递成功,变量OPTION保存最后处理参数。

5.2.2 、使用getopts指定变量取值

有时有必要在脚本中指定命令行选项取值。getopts 为此提供了一种方式,即在option_string中将一个冒号放在选项后。例如:

getopts :ahfvc: OPTION

上面一行脚本指出,选项ahfv可以不加实际值进行传递,而选项c必须取值。使用选项取值时,必须使用变量OPTARG保存该值。如果试图不取值传递此选项,会返回一个错误信息。错误信息提示并不明确,因此可以用自己的反馈信息屏蔽它,方法如下:

将冒号放在option_string开始部分。

getopts :ahfgvc: OPTION

在脚本中指定命令行选项时,最好使其命名规则与UNIXLINUX一致。下面是一些选项及其含义的列表。

-a    扩展

-c    计数、拷贝

-d    目录、设备

-e    执行

-f    文件名、强制

-h    帮助

-I     忽略状态

-l     注册文件

-o    完整输出

-q    退出

-p    路径

-v    显示方式或版本

6shell嵌入命令

实际上已经用过了许多shell嵌入命令。可能要想什么是shell嵌入,这些命令是在实际的Bourne shell里创建而不是存在于/binusr/bin目录里。嵌入命令比系统里的相同命令要快。

6.1shell嵌入命令完整列表

           空,永远返回为true

.             从当前shell中执行操作

break      退出forwhileuntilcase语句

cd           改变到当前目录

continue  执行循环的下一步

echo              反馈信息到标准输出

eval         读取参数,执行结果命令

exec        执行命令,但不在当前shell

exit         退出当前shell

export     导出变量,使当前shell可利用它

pwd        显示当前目录

read        从标准输入读取一行文本

readonly  使变量只读

return      退出函数并带有返回值

set          控制各种参数到标准输出的显示

shift        命令行参数向左偏移一个

test         评估条件表达式

times       显示shell运行过程的用户和系统时间

trap         当捕获信号时运行指定命令

ulimit      显示或设置shell资源

umask     显示或设置缺省文件创建模式

unset       shell内存中删除变量或函数

wait        等待直到子进程运行完毕,报告终止

6.2set

set可用于在脚本内部给出其运行参数,以下举例说明。假定有一段脚本控制两个参数,但并不向脚本传递参数而是在脚本内部设置其取值。可以用set命令完成此功能。格式为:

set param1 param2 ..

当测试一段脚本且脚本包含参数时,这样使用set命令有很多用处。其一就是不必在每次运行脚本时重复输入参数。

6.3 times

times命令给出用户脚本或任何系统命令的运行时间。第一行给出shell消耗时间,第二行给出运行命令消耗的时间。

6.4 type

使用type查询命令是否仍驻留系统及命令类型。type打印命令名是否有效及该命令在系统的位置。

6.5wait

wait命令等待直到一个用户子进程完成,可以在wait命令中指定进程ID号。如果并未指定,则等待直到所有子进程完成。

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值