shell脚本编程进阶

 

流程控制

函数

数组

高级字符串操作

高级变量


条件选择if语句:

选择执行:

注意:if语句可嵌套

单分支:

if 判断条件;then

条件为真的分支代码

fi

双分支:

if 判断条件; then

条件为真的分支代码

else

条件为假的分支代码

fi

shell脚本编程进阶_Linux

if 语句

多分支

if 判断条件1; then

条件为真的分支代码

elif 判断条件2; then

条件为真的分支代码

elif 判断条件3; then

条件为真的分支代码  else

以上条件都为假的分支代码

fi

逐条件进行判断,第一次遇为“真”条件时,执行其分支,

而后结束整个if语句shell脚本编程进阶_Linux_02

If示例:

根据命令的退出状态来执行命令

if ping -c1 -W2 station1 &> /dev/null; then

echo 'Station1 is UP'

elif grep "station1" ~/maintenance.txt &> /dev/null

then

echo 'Station1 is undergoing maintenance‘

else

echo 'Station1 is unexpectedly DOWN!'

exit 1

fi


条件判断:case语句

case 变量引用 in

PAT1)

分支1

;;

PAT2)

分支2

;;

...

*)

默认分支

;;

esac

case支持glob风格的通配符:

*: 任意长度任意字符

?: 任意单个字符

[]:指定范围内的任意单个字符

a|b: a或b


条件判断:case语句

case 变量引用 in

PAT1)

分支1

;;

PAT2)

分支2

;;

...

*)

默认分支

;;

esac

case支持glob风格的通配符:

*: 任意长度任意字符

?: 任意单个字符

[]:指定范围内的任意单个字符

a|b: a或b

shell脚本编程进阶_Linux_03


循环

循环执行

将某代码段重复运行多次

重复运行多少次:

循环次数事先已知

循环次数事先未知

有进入条件和退出条件

for, while, unti

for循环

for 变量名 in 列表;do

循环体

done

执行机制:

依次将列表中的元素赋值给“变量名”; 每次赋值后即执

行一次循环体; 直到列表中的元素耗尽,循环结束

for循环

列表生成方式:

(1) 直接给出列表

(2) 整数列表:

(a) {start..end}

(b) $(seq [start [step]] end)

(3) 返回列表的命令

$(COMMAND)

(4) 使用glob,如:*.sh

(5) 变量引用;

$@, $*

for语句的用法

shell脚本编程进阶_Linux_04shell脚本编程进阶_Linux_05

while循环

while CONDITION; do

循环体

done

CONDITION:循环控制条件;进入循环之前,先做一次判

断;每一次循环之后会再次做判断;条件为“true”,则执行

一次循环;直到条件测试状态为“false”终止循环

因此:CONDTION一般应该有循环控制变量;而此变量的值

会在循环体不断地被修正

进入条件:CONDITION为true

退出条件:CONDITION为false


shell脚本编程进阶_Linux_06

shell脚本编程进阶_Linux_07


until循环

until CONDITION; do

循环体

done

进入条件: CONDITION 为false

退出条件: CONDITION 为true


循环控制语句continue

用于循环体中

continue [N]:提前结束第N层的本轮循环,而直接进入下一

轮判断;最内层为第1层

while CONDTIITON1; do

CMD1

...

if CONDITION2; then

continue

fi

CMDn

...

done

循环控制语句break

用于循环体中

break [N]:提前结束第N层循环,最内层为第1层

while CONDTIITON1; do

CMD1

...

if CONDITION2; then

break

fi

CMDn

...

done

循环控制shift命令

shift [n]

用于将参量列表 list 左移指定次数,缺省为左移一次。

参量列表 list 一旦被移动,最左端的那个参数就从列表中删

除。while 循环遍历位置参量列表时,常用到 shift

./doit.sh a b c d e f g h

./shfit.sh a b c d e f g h

 

示例:doit.sh

#!/bin/bash

# Name: doit.sh

# Purpose: shift through commanline arguments

# Usage: doit.sh [args]

while [ $# -gt 0 ] # or (( $# > 0 ))

do

echo  $*

shift

done

shell脚本编程进阶_Linux_08shell脚本编程进阶_Linux_09


创建无限循环

while true; do

循环体

done

until false; do

循环体

Done

特殊用法

while循环的特殊用法(遍历文件的每一行):

while read line; do

循环体

done < /PATH/FROM/SOMEFILE

依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将

行赋值给变量line

特殊用法

双小括号方法,即((…))格式,也可以用于算术运算

双小括号方法也可以使bash Shell实现C语言风格的变量操作

I=10

((I++))

for循环的特殊格式:

for ((控制变量初始化;条件判断表达式;控制变量的修正表达

式))

do

循环体

done

控制变量初始化:仅在运行到循环代码段时执行一次

控制变量的修正表达式:每轮循环结束会先进行控制变量修

正运算,而后再做条件判断

select循环与菜单

select variable in list

do

循环体命令

done

select 循环主要用于创建菜单,按数字顺序排列的

菜单项将显示在标准错误上,并显示 PS3 提示符,

等待用户输入

用户输入菜单列表中的某个数字,执行相应的命令

用户输入被保存在内置变量 REPLY 中


select与case

select 是个无限循环,因此要记住用 break 命令退

出循环,或用 exit 命令终止脚本。也可以按 ctrl+c

退出循环

select 经常和 case 联合使用

与 for 循环类似,可以省略 in list,此时使用位置

shell脚本编程进阶_Linux_10

参量

信号捕捉trap

trap '触发指令' 信号

自定义进程收到系统发出的指定信号后,将执行触发指令

,而不会执行原操作

trap '' 信号

忽略信号的操作

trap '-' 信号

恢复原信号的操作

trap -p

列出自定义信号操作

rap示例

#!/bin/bash

trap 'echo “signal:SIGINT"'  int

trap -p

for((i=0;i<=10;i++))

do

sleep 1

echo $i

done

trap ''  int

trap -p

for((i=11;i<=20;i++))

do

sleep 1

echo $i

done

trap '-'  int

trap -p

for((i=21;i<=30;i++))

do

sleep 1

echo $i

don



函数介绍

函数function是由若干条shell命令组成的语句块,实现代码

重用和模块化编程

它与shell程序形式上是相似的,不同的是它不是一个单独的

进程,不能独立运行,而是shell程序的一部分

函数和shell程序比较相似,区别在于:

Shell程序在子Shell中运行

而Shell函数在当前Shell中运行。因此在当前Shell中,函

数可以对shell中变量进行修改


定义函数:


函数由两部分组成:函数名和函数体

help function

语法一:

function f_name {

...函数体...

}

语法二:

function f_name () {

...函数体...

}

语法三:

f_name (){

...函数体...

}


函数使用

函数的定义和使用:

可在交互式环境下定义函数

可将函数放在脚本文件中作为它的一部分

可放在只包含函数的单独文件中

调用:函数只有被调用才会执行

调用:给定函数名

函数名出现的地方,会被自动替换为函数代码

函数的生命周期:被调用时创建,返回时终止


函数返回值:

 函数有两种返回值:

 函数的执行结果返回值:

   (1) 使用echo等命令进行输出

   (2) 函数体中调用命令的输出结果

函数的退出状态码:

   (1) 默认取决于函数中执行的最后一条命令的退出状态码

   (2) 自定义退出状态码,其格式为:

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

    return 0  无错误返回。

    return 1-255  有错误返回

交互式环境下定义和使用函数

示例:

dir() {

    >ls -l

    >}

定义该函数后,若在$后面键入dir,其显示结果同ls -l的

作用相同

dir

该dir函数将一直保留到用户从系统退出,或执行了如下所

示的unset命令:

unset dir

在脚本中定义及使用函数:

函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至

shell首次发现它后才能使用

调用函数仅使用其函数名即可

示例:

cat func1

#!/bin/bash

# func1

hello()

{

echo "Hello there today's date is `date +%F`"

}

echo "now going to the function hello"

hello

echo "back from the function"

使用函数文件

可以将经常使用的函数存入函数文件,然后将函数文件载

入shell

文件名可任意选取,但最好与相关任务有某种联系。例如

:functions.main

一旦函数文件载入shell,就可以在命令行或脚本中调用

函数。可以使用set命令查看所有定义的函数,其输出列

表包括已经载入shell的所有函数

若要改动函数,首先用unset命令从shell中删除函数。改

动完毕后,再重新载入此文件

函数文件示例:

cat  functions.main

#!/bin/bash

#functions.main

findit()

{

if [ $# -lt 1 ] ;  then

echo "Usage:findit file"

return 1

fi

find / -name $1 –print

}


载入函数

函数文件已创建好后,要将它载入shell

定位函数文件并载入shell的格式:

.  filename 或 source   filename  

注意:此即<点> <空格> <文件名>

这里的文件名要带正确路径

示例:上例中的函数,可使用如下命令:

. functions.main

使用set命令检查函数是否已载入。set命令将在shell中显示

所有的载入函数

示例:

set

findit=( )

{

if [ $# -lt 1 ]; then

echo "usage :findit file";

return 1

fi

find / -name $1 -print

}


执行shell函数

要执行函数,简单地键入函数名即可

示例:

findit groups

/usr/bin/groups

/usr/local/backups/groups.bak


删除shell函数:






shell脚本编程进阶_Linux_11


shell脚本编程进阶_Linux_12

现在对函数做一些改动后,需要先删除函数,使其对shell不

可用。使用unset命令完成删除函数

命令格式为:

unset  function_name

示例:

unset findit

再键入set命令,函数将不再显示

环境函数

使子进程也可使用

声明:export –f  function_name

查看:export  -f 或 declare -x

函数可以接受参数:

传递参数给函数:调用函数时,在函数名后面以空白分隔

给定参数列表即可;例如“testfunc arg


字符串字符串切片

${#var}:返回字符串变量var的长度

${var:offset}:返回字符串变量var中从第offset个字符后(不包括

第offset个字符)的字符开始,到最后的部分,offset的取值在0

到 ${#var}-1 之间(bash4.2后,允许为负值)

${var:offset:number}:返回字符串变量var中从第offset个字符后

(不包括第offset个字符)的字符开始,长度为number的部分

${var:  -length}:取字符串的最右侧几个字符

注意:冒号后必须有一空白字符

${var:offset:-length}:从最左侧跳过offset字符,一直向右取到

距离最右侧lengh个字符之前的内容

${var:  -length:-offset}:先从最右侧向左取到length个字符开始

,再向右取到距离最右侧offset个字符之间的内容

注意:-length前空格

57

字符串处理

基于模式取子串

${var#*word}:其中word可以是指定的任意字符

功能:自左而右,查找var变量所存储的字符串中,第一

次出现的word, 删除字符串开头至第一次出现word字符之间的

所有字符

${var##*word}:同上,贪婪模式,不同的是,删除的

是字符串开头至最后一次由word指定的字符之间的所有内容

示例:

file="var/log/messages“

${file#*/}: log/messages

${file##*/}: messages

字符串处理

${var%word*}:其中word可以是指定的任意字符;

功能:自右而左,查找var变量所存储的字符串中,第一

次出现的word, 删除字符串最后一个字符向左至第一次出现

word字符之间的所有字符;

file="/var/log/messages"

${file%/*}: /var/log

${var%%word*}:同上,只不过删除字符串最右侧的字符向

左至最后一次出现word字符之间的所有字符;

示例:

url=http://www.magedu.com:80

${url##*:} 80

${url%%:*} http

字符串处理

查找替换

${var/pattern/substr}:查找var所表示的字符串中,第

一次被pattern所匹配到的字符串,以substr替换之

${var//pattern/substr}: 查找var所表示的字符串中,

所有能被pattern所匹配到的字符串,以substr替换之

${var/#pattern/substr}:查找var所表示的字符串中,

行首被pattern所匹配到的字符串,以substr替换之

${var/%pattern/substr}:查找var所表示的字符串中,

行尾被pattern所匹配到的字符串,以substr替换之

查找并删除

${var/pattern}:删除var所表示的字符串中第一次被

pattern所匹配到的字符串

${var//pattern}:删除var所表示的字符串中所有被

pattern所匹配到的字符串

${var/#pattern}:删除var所表示的字符串中所有以

pattern为行首所匹配到的字符串

${var/%pattern}:删除var所表示的字符串中所有以

pattern为行尾所匹配到的字符串

字符大小写转换

${var^^}:把var中的所有小写字母转换为大写

${var,,}:把var中的所有大写字母转换为小写

变量赋值

${var:-value} 或 ${var-value}:如果var为空或未设置,那

么返回value;否则返回var的值

${var:+value}:如果var非空,则返回value,否则返回空值

${var:=value}:如果var为空或未设置,那么返回value,并

将value赋值给var;否则返回var的值

${var:?error_info}:如果var为空或未设置,那么在当前终

端打印error_info;否则返回var的值

为脚本程序使用配置文件,实现变量赋值

(1) 定义文本文件,每行定义“name=value”

(2) 在脚本中source此文件即可

63

eval命令

eval命令将会首先扫描命令行进行所有的置换,然后再执行该

命令。该命令适用于那些一次扫描无法实现其功能的变量.该

命令对变量进行两次扫描

示例:

[root@server ~]# CMD=whoami

[root@server ~]# echo  $CMD

whoami

[root@server ~]# eval $CMD

root

[root@server ~]# n=10       

[root@server ~]# echo {0..$n}     

{0..10}

[root@server ~]# eval echo {0..$n}

0 1 2 3 4 5 6 7 8 9 10


间接变量引用

如果第一个变量的值是第二个变量的名字,从第一个变量引

用第二个变量的值就称为间接变量引用

variable1的值是variable2,而variable2又是变量名,

variable2的值为value,间接变量引用是指通过variable1获

得变量值value的行为

variable1=variable2

variable2=value

创建临时文件

mktemp命令:创建并显示临时文件,可避免冲突

mktemp [OPTION]... [TEMPLATE]

TEMPLATE: filename.XXX

X至少要出现三个

OPTION:

-d: 创建临时目录

-p DIR或--tmpdir=DIR:指明临时文件所存放目录位置

示例:

mktemp /tmp/test.XXX

tmpdir=`mktemp –d /tmp/testdir.XXX`

mktemp --tmpdir=/testdir test.XXXXXX


安装复制文件

install命令:

install [OPTION]... [-T] SOURCE DEST 单文件

install [OPTION]... SOURCE... DIRECTORY

install [OPTION]... -t DIRECTORY SOURCE...

install [OPTION]... -d DIRECTORY...创建空目录

选项:

-m MODE,默认755

-o OWNER

-g GROUP

示例:

install -m 700 -o wang -g admins srcfile desfile

install –m –d /testdir/installdir