Shell高级编程

admin 发表于 [Linux] 分类,标签: CentOS Linux SSH shell
0

Shell高级编程
1、if语句
if语句的语法格式:
if condition1
then
       command-list
elif condition2
then
       command-list
else
       command-list
fi
if语句以给定的命令command的出口状态作为判断条件,如果出口状态为0则执行紧随着then自己之后的命令。fi表示if语句的结束。

2、case控制结构
case命令能够提供多路分支转移控制功能。用作测试调教的变量可以具有多个值,不同的数值可以引起不同的程序走向。 case语句的语法格式:
case "$variable" in
pattern1)
              command-list;;
pattern2)
              command-list;;
.......
patternN)
              command-list;;
esac
Shell使用给定的变量的值与每个模式(pattern)进行比较。每个模式须以右半括号)结束。当shell发现匹配一个模式时,则执行紧随模式后面的所有命令,知道遇到爽分号(;;),执行结束,shell跳刀紧随esac语句之后的第一个语句开始继续执行。

模式(pattern)可以使用元字符(*),也可以使用运算符|表示模式的逻辑或关系。

3、for循环
根据for命令行中的每个参数,重复执行一组命令或代码块。for语句的语法格式:
for var in word-list
do
      command-list
done
word-list是一系列的参数或称参数表,中间用空格分开。对于参数表中的每一个参数值,重复执行一次do与done之间的命令。在每次循环过程中,shell从给定的参数表中一次取出一个参数值,并把参数值赋值到给定的变量var中,然后执行for循环体中的代码块。

例:给出当前目录中检索文件的大小超过1MB的文件。
#!/usr/bin/ksh
dir=$(pwd)
cd ${dir}
for in in $(find . -size +2048 -print)
do
if [-f "${i}"]
then
ls -s "${i}"
fi
done
exit

4、while循环
while循环结构是在循环体的前面执行条件测试。只要控制条件的测试结果为真,就继续执行循环体中的命令。while的语法结构:
while [condition-is-true]
do
command-list
done
例:求1~100之间的所有整数和。
Number=1
Sum=0
Max=100
while ["$Number" -le "$Max"]
do
Sum='expr $Sum+$Number'
Number='expr $Number+1'
done
echo $Sum

在while循环结构中,控制条件可以由多个语句或命令组成。实际上只有最后一个条件才能决定循环体何时终止执行。

until循环
until循环与while循环结构不同的是:如果条件为假则循环继续执行。语法格式:
until [condition-is-true]
do
command-list
done

5、select循环
select循环结构主要用于建立选择菜单。 select菜单的最大的特点是,编程人员只需要提供菜单的选项内容,而无须组织菜单的表现形式。这一切均由select语句负责实现。select语法格式:
select variable [in list]
do
comand-list
break
done
使用break语句退出select循环。

默认情况下,select语句使用PS3环境变量的值作为命令提示符(#?),我们可以在使用select语句之前给PS3环境变量一个新的值。


6、break和continue命令
break命令用于终止循环,而continue命令用于引起控制机制越过本次循环中余下的所有命令,直接转移到下一次循环迭代。

break命令的语法格式如:break [n]
break命令后面可以加一个选用的数字参数。一个简单的break命令只是终止最内层的循环。但break n命令则可以跳出n层循环,控制将转到n个关键字done后面的命令开始继续执行。

类似于break,continue命令也可带一个选用的数字参数。 如果continue命令后面指定一个数字n,则控制将转到外部嵌套第n层循环体中的起始位置开始继续执行循环体。

7、sleep命令
sleep命令可以使shell暂时处于休眠状态,以秒为单位。sleep命令的语法格式: sleep [n]

8、shift命令
shift命令用于修改位置参数的值。按照指定的数量,从右到左移走左面的位置参数。同时位置参数的总数也相应的减少。${0}是脚本文件的名字,在左移的过程中不受影响。 shift语句的语法格式:
shift [n]

9、getopts命令
getopts命令用于获取以减号"-"或加号"+"为起始字符的命令行选项、选项的参数和命令参数。其语法格式:
setopts optstring name [arg...]

getopts命令是对getopt命令的更新和替代品。在shell脚本中,最好能够使用getopts命令。使用getopts命令,用户能够以任何顺序输入命令选项。getopts命令允许组合使用不带参数的各种选项,也可以分别使用各种选项。

getopts语句使用一个合法的选项字符串确定shell脚本能够接受的选项。如:getopts ior name表示脚本可以接受的合法选项为"-i"、"-o"、"-r"。每次调用getopts语句时,命令行中下一个合法选项就会存入到给定的变量name中。

如果运行脚本时输入了非法的参数,getopts命令将会输出如下形式的出错信息,同时把一个问号(?)字符存储到name变量中:
script_name: illegal option--option_letter

getopts命令的返回值取决于是否成功地获取了选项。如果读取选项(包括非法的选项),getopts语句将返回数值0。
例:
while getopts abs var
do
case ${var} in
a)echo option -a found;;
b)echo option -b found;;
c)echo option -c found;;
esac
done
运行脚本:$testing -adc

如果选项带有参数,则需要在相应的选项字母后面附加一个冒号“:”字符。如果存在冒号,则选项后的字符串将存储到OPTORG变量中。如:while getopts a:b:s var。一个选项要求提供选项参数而未提供,getopts语句将会输出下列形式的出错信息:
script_name: option requires an argument-optiond_letter

当getopts语句执行结束后,OPTIND变量的值将会指向第一个非选项参数的位置参数,也即第一个命令参数。我们可以利用 shift,使之左移$OPTIOND-1个位置,即可使$1指向第一个命令参数,$2指向第二个命令参数,如此等等。

例:
while getopts o:r:nt var
do
case ${var} in
o)output_file="${OPTARG}";;
r)report_file="${OPTARG}";;
n)number_option="yes";;
t)title="no";;
\?)exit2;;
esac
done
echo "Output file=${output_file}"
echo "Report file=${report_file}"
echo "Numbering option=${number_option:-no}"
echo "Title option=${title:-yes}"
echo "Arguments before shift: ${*}"
shift 'expr ${OPTIND}-1'
echo "Arguments afters shif:${*}"


10、while循环的I/O重定向
为了达到循环结构代码块的I/O重定向的目的,可在循环结构结束标志(如关键字done)后面附加运算符<和适当的输入文件。
对于while循环结构语句,下列语法格式表示,循环结构块所需的所有的输入数据均取自指定的输入文件:
while [condition-is-true]
do
command-list
done < datafile

until循环的I/O重定向与while循环的I/O重定向完全相同。

tee命令实现标准输出的I/O重定向,显示并保存脚本的输出数据。语法格式:
tee [-a] file
-a,表示输出的内从附加到文件后面,并不覆盖文件的内容。

basename 路径名,它可以提取路径中的文件名。如:basename /etc/passwd,将提取出文件名passwd。basename "fsafsa",将出去双引号只剩下字符串fsafsa。

for循环的I/O重定向也类似,还可以在 done后使用管道符号(|)进行重定向。

11、here文档
here文档是一种具有特殊用途的代码块。here文档采用I/O重定向的方法,把一系列需要从键盘上的输入的命令,模拟人工输入方法,一行一行的提交给交互式程序或命令。here文档的格式:
COMMAND<<LimitString
command1
command2
.....
commandN
LimitString
特殊I/O重定向符号"<<"和"LimitString"表明here文档的开始,而第二个"LimitString"表示here文档的结束。重定向的效果是将here文档的命令提交给交互程序或命令的标准输入。

选择字符串分隔符"LimitString"时应确保它在Shell脚本中是唯一的,至少在其界定的一系列命令中间不应该出现,以避免产生混淆。

例:
vi $1<<EOF
i
I cannot choose the best
The best choose me.
^[
:wq
EOF
注释:^[是一个字符,表示ESC键。

here文档也支持变量和命令的替换,为了禁止here文档中使用参数替换或命令替换,可以在第一个字符串分隔符"LimitString"前后增加单引号或双引号,或在第一个字符串分隔符前加转义字符。

利用here文档和":"命令,可以注解掉shell脚本中的代码。从而避免了在每一行前加注解字符(#)。

12、函数
函数的语法格式:
function_name(){
command-list
}
注意,如果整个函数定义与命令位于同一行上,则左花括号和右花括号之前必须存在一个空格。同时,每个命令之后除附加分号之外,至少必须有一个空格。如:function_name(){ com1; com2; ...}
另外,函数与圆括号之间必须连在一起,之间不能有空格。
例:
exchange()
{
temp=${colors1}
colors1=${colors2}
colors2=${temp}
return
}

在定义函数时,不能在函数体内使用exit命令,因为函数的执行不是子程序调用,函数与当前的shell脚本同属于一个进程。当在函数中执行exit命令时,将会引起当前shell脚本或进程的终止执行。
在函数定义中,表示整个函数执行结束的替代方法是利用shell的内部命令return实现,用来终止函数的执行。只有在函数定义中才可以使用return命令,但也并非必需的。实际上,仅当期望的函数返回数值时,才需要使用return语句,如果函数中未用到return命令,则函数运行结束时将返回函数体中的执行的最后一条命令的出口状态。如同exit语句,return语句也可以带一个整数参数选项,以便作为函数执行结束时返回一个出口状态数值,并将这个出口状态赋值到$?变量。return [n]

例:计算闰年
$cat leap-year
#!/bin/sh
leap-year(){
if [ 'expr $1%4' -ne 0 ]
then
return 0
elif [[ 'expr $1%100' -ne 0 || 'expr $1%400' -eq 0 ]]
then
return 1
else
return 0
fi
}

shell函数也可以提供参数,而函数则可以处理传递给自己的参数。如上例我们使用:leap-year 2008

函数也可以在shell脚本中定义,在脚本中执行,最后随脚本的终止而取消。函数的定义必须位于调用的函数的语句之前。函数名不能与变量同名,如果函数名与已声明的变量名同名,shell将会给出一个出错信息。

无论何时调用函数,将会重新设置当前shell进程使用的位置参数,当调用的函数时提供的参数成为新的位置参数。即shell将使用调用函数时提供的参数重新为位置参数赋值。函数按位置引用传递给自己的参数$1、$2、...如果调用函数时未提供参数,位置参数将被清除。

shell脚本通常只传递参数给函数。如果把变量名作为参数传递给函数,函数将把变量名作为字符串常量进行处理。

13、并列结构
命令的逻辑与(&&)并列结构和逻辑或(||)并列结构提供一种依次执行一系列命令方法,能有效的替代复杂的if/then语句结构,甚至case语句结构。
逻辑与并列结构的语法格式:
command-1 && command-2 &&command-3 .......
命令的逻辑与并列结构表示从第一个命令的开始,依次执行每个命令。如果当前命令的返回值为0,则继续执行下一个命令。如果中间某个命令的返回值为非零,则整个命令链的执行结束。

逻辑或并列结构的语法格式:
command-1 || command-2 || .....
它与逻辑与的并列结构相反,命令的逻辑或并列结构意味着从第一个命令开始,依次执行每一个命令,如果当前命令的返回值为非0,则继续执行下一个命令如果某个命令的返回值为0,则整个命令链的执行结束。

14、数组
同普通变量一样,数组元素可以采用variable[n]=value的形式进行赋值或初始化。为了引用数组的内容,可以使用${variable[n]}的变量替换形式。

为了引入数组,在korn Shell中,我们可以使用下列set -A arrayname语句:
set -A arrayname element1 element2.....elementN
如:set -a weekday Sunday Monday Tuesday Wednesday Thursday Friday Saturday

在Bash中,可以采用显示的delare -a variable语句引入整个数组。
如:declare -a weekday
weekday[0]=Sunday
weekday[1]=Monday
....
输出数组中的所有元素:${weekday[@]}
使用#字符求取整个数组有多少个元素:echo ${#weekday[@]}或echo ${#weekday[*]}
还可以使用#号求取数组元素的长度:echo ${#weekday[0]},将输出6。

unset命令可以删除数组元素,甚至整个数组。如:
unset weekday[1],将去除weekday[1]的值。
unset weekday,将去除数组weekday所有元素的值。

通过赋值语句可以实现数组的复制,如:
array2="${array1[@]}"或array2=("$array1[@]}")

15、信号捕捉处理
信号是一种影响进程运行状态的外部事件,是由用户终端、操作系统内核或其他进程发送给指定进程的消息,用于通知进程某种事件已经发生。

shell脚本中,trap命令用于指定需要捕捉的信号以及应采取的相应的处理动作。trap命令的语法格式:
trap ["command-list"] [signal...]或trap ['comand-list'] [signal...]
命令是无论何时收到指定的信号时都应当执行的命令或一组命令。一旦命令运行结束,程序的控制逻辑将恢复到因受到信号而中断的位置开始继续执行。通常指定的命令并非单个命令,而是一组命令,前后以单引号、双引号括起来,中间使用分号隔开。

shell脚本中,只有0、1、2、3、15、16、17等信号能够捕捉:
0,EXIT ,进程结束信号。无论何时执行exit语句,即可产生此信号,即使没有明显的执行exit语句,脚本运行正常结束也可产生此信号。仅当脚本运行结束时才能执行相应的例行处理动作。
1,HUP,(终止进程)终端通信连接断开时产生的信号。通常,一旦捕捉到此信号,shell脚本将会立即停止运行,除非使用nohup命令
2,INT,(终止进程)按下中断键(Delete键或Ctrl-c键)时产生的信号。
3,QUIT,(终止进程,生成内存映像文件),按下Quit键(Ctrl+\键)时产生的信号。
9,KILL,(终止进程)不可捕捉或忽略的kill信号,供系统管理员使用kill命令终止任何进程。
12,SYS,(终止进程,生成内存映像文件)发现非法系统调用时产生的信号。
15,TERM,(终止进程)终止信号。这是kill命令产生的默认终止信号。

shell脚本中,有4个信号不应捕捉:其中信号9和23是不能捕捉的,而信号18和19则不应捕捉。

例:
#!/usr/bin/ksh
trap 'echo "variable setting--\na=$a\nb=$b"' EXIT
echo "This line will print before the \"trap\" statement"
echo "even though the \"trap\" statement occurs first"
a=''''
b=36
exit 0

如果没有指定任何命令或明显地指定作一个null值,则表示忽略指定的信号。如:
trap '' 2 或trap ':' 2 3,注意trap之后是两个单引号。

在trap语句中省略command-list,shell将按默认的处理动作执行。如:trap 1 2 3


 

发表我的评论