Download presentation
Presentation is loading. Please wait.
1
Shell编程基础
2
第八章、shell编程基础 本章的要求 熟悉shell基础 熟悉shell变量及环境变量 熟悉使用shell测试语句
3
8.1 Linux下shell编程基础
4
Shell脚本的本质 编译型语言 解释型语言 Shell脚本语言是解释型语言 Shell脚本的本质: Shell命令的有序集合。 4
5
shell 编程的基本过程 基本过程分为三步: Step1. 建立 shell 文件 包含任意多行操作系统命令或shell命令的文本文件;
用chmod命令修改权限; Step3. 执行shell文件 直接在命令行上调用shell程序. 5
6
实例 Step1: 建立shell文件 (可用任何建立文本文件的方法) $ cat prog1.sh #!/bin/bash date
$ chmod prog1.sh Step3: 执行该shell程序 $ prog1.sh prog1.sh: not found (shell在标准搜索路径中找不到prog1.sh) Step4: 指定路径或修改环境变量PATH后执行shell程序 $ ./prog1.sh 2009年 12月 16日 星期二 14:52:57 CST 6
7
8.2 Linux下shell变量及环境变量
8
Shell变量 Variable=value
命名规则同C++中的命名规则 count=1 echo $count DATE=`date` echo $DATE 8
9
shell变量 Bourne Shell有如下四种变量: 用户自定义变量 位置变量即 命令行参数 预定义变量 环境变量 9
10
1、用户自定义变量 在shell编程中通常使用全大写变量,方便识别 变量的调用:在变量前加$ Linux Shell/bash从右向左赋值
$ COUNT=1 变量的调用:在变量前加$ $ echo $HOME Linux Shell/bash从右向左赋值 $Y=y $ X=$Y $ echo $X y 使用unset命令删除变量的赋值 $ Z=hello $ echo $Z hello $ unset Z 10
11
2、位置变量 $0 与键入的命令行一样,包含脚本文件名 $1,$2,……$9 分别包含第一个到第九个命令行参数 $# 包含命令行参数的个数
$0 与键入的命令行一样,包含脚本文件名 $1,$2,……$9 分别包含第一个到第九个命令行参数 $# 包含命令行参数的个数 包含所有命令行参数:“$1,$2,……$9” $? 包含前一个命令的退出状态 $* 包含所有命令行参数:“$1,$2,……$9” $$ 包含正在执行进程的ID号 11
12
常用shell环境变量 HOME: /etc/passwd文件中列出的用户主目录
IFS:Internal Field Separator, 默认为空格,tab及换行符 PATH :shell搜索路径 PS1,PS2:默认提示符($)及换行提示符(>) TERM:终端类型,常用的有vt100,ansi,vt200,xterm等 12
13
8.3 Linux下shell测试语句
14
shell 程序和语句 shell 程序由零或多条shell语句构成。 shell语句包括三 类:说明性语句、功能性语句和结构性语句。
说明性语句: 以#号开始到该行结束,不被解释执行 功能性语句: 任意的shell命令、用户程序或其它shell程序。 结构性语句: 条件测试语句、多路分支语句、循环语句、循环控制 语句等。 14
15
说明性语句(注释行) 注释行可以出现在程序中的任何位置,既可以单独占用一行, 也可以 接在执行语句的后面. 以#号开始到所在行的行尾部分,都不被解释执 行. 例如: #! /bin/sh # # 本程序说明 command_1 command_ # command_2的语句说明 …… # 下面程序段的说明 command_m command_n # commandn_语句的说明 告诉OS用哪种类型的shell来解释执行该程序 15
16
常用功能性语句(命令) read read从标准输入读入一行, 并赋值给后面的变量,其语法为: . read var
. read var1 var2 var3 把读入行中的第一个单词(word)赋给var1, 第二个单词赋 给var2, ……把其余所有的词赋给最后一个变量. 如果执行read语句时标准输入无数据, 则程序在此停留等 侯, 直到数据的到来或被终止运行。 16
17
应用实例 # example1 for read echo "Input your name: \c" read username
echo "Your name is $username" "I know the date, bye!" #example2 for read echo "Input date with format yyyy mm dd: \c" read year month day echo "Today is $year/$month/$day, right?" echo "Press enter to confirm and continue\c" read answer echo "I know the date, bye!" 17
18
expr 算术运算命令expr主要用于进行简单的整数运算,包括加(+)、减 (-)、乘(\*)、整除(/)和求模(%)等操作。例如:
expr \* 3 27 expr / 2 -1 $ num=9 $ sum=`expr $num \* 6 ` $ echo $sum 54 反斜线去掉*号的元字符含义 反撇号引用命令的运行结果 18
19
test test语句可测试三种对象: 字符串 整数 文件属性 每种测试对象都有若干测试操作符 例如:
字符串 整数 文件属性 每种测试对象都有若干测试操作符 例如: test "$answer" = "yes" 变量answer的值是否为字符串yes test $num –eq 18 变量num的值是否为整数18 test -d tmp 测试tmp是否为一个目录名 19
20
字符串测试 s1 = s2 测试两个字符串的内容是否完全一样 s1 != s2 测试两个字符串的内容是否有差异
-z s1 测试s1 字符串的长度是否为0 -n s1 测试s1 字符串的长度是否不为0 20
21
整数测试 a -eq b 测试a 与b 是否相等 a -ne b 测试a 与b 是否不相等 a -gt b 测试a 是否大于b
a -ge b 测试a 是否大于等于b a -lt b 测试a 是否小于b a -le b 测试a 是否小于等于b 21
22
文件测试 -d name 测试name 是否为一个目录 -f name 测试name 是否为普通文件
-L name 测试name 是否为符号链接 -r name 测试name 文件是否存在且为可读 -w name 测试name 文件是否存在且为可写 -x name 测试name 文件是否存在且为可执行 -s name 测试name 文件是否存在且其长度不为0 f1 -nt f2 测试文件f1 是否比文件f2 更新 f1 -ot f2 测试文件f1 是否比文件f2 更旧 22
23
8.4 Linux下shell控制语句
24
结构性语句 结构性语句主要根据程序的运行状态、输入数据、变 量的取值、控制信号以及运行时间等因素来控制程序的运 行流程。
主要包括:条件测试语句(两路分支)、多路分支语 句、循环语句、循环控制语句和后台执行语句等。 24
25
条件语句 if…then…fi 语法结构: if 表达式 then 命令表 fi
如果表达式为真, 则执行命令表中的命令; 否则退出if语 句, 即执行fi后面的语句。 if和fi是条件语句的语句括号, 必须成对使用; 命令表中的命令可以是一条, 也可以是若干条。 25
26
实例 shell程序prog2.sh(测试命令行参数是否为已存在的文 件或目录)。用法为: ./prog2.sh file 代码如下:
#The statement of if…then…fi (注释语句) if [ -f $1 ] (测试参数是否为文件) 放括号表示test(测试) then echo "File $1 exists" (引用变量值) fi if [ -d $HOME/$1 ] (测试参数是否为目录) echo "File $1 is a directory" (引用变量值) 26
27
执行prog2程序: $ ./prog2.sh prog1.sh File prog1.sh exists
$ ./prog2.sh backup File backup is a directory $0为prog2.sh; $1为backup,是一个已存在的目录. 如果不带参数, 或大于一个参数运行prog2, 例如: $ ./prog2.sh (或 $ ./prog2.sh file1 file2) 会出现什么结果? 27
28
条件语句 if…then…else…fi 注意: 无论表达式是否为真, 都有语句要执行. 语法结构为: if 表达式 then 命令表1
28
29
test命令测试的条件成立时, 命令返回值为真(0),否则 返回值为假(非0).
test $name -eq $1 echo $? 方式1 if [ -f $filename ] then …… fi 方式3 if test -f $filename then …… fi 方式2 至少一个空格 至少一个空格 29
30
例子: shell程序prog3.sh, 用法为: ./prog3.sh file
#The statement of if…then…else…fi if [ -d $1 ] then echo "$1 is a directory" exit (退出当前的shell程序) else if [ -f $1 ] echo "$1 is a common file" echo "unknown" fi 30
31
运行prog3.sh程序: $ ./prog3.sh backup backup is a directory
prog1 is a common file $ ./prog3.sh abc unknown prog3.sh是对prog2.sh的优化, 逻辑结构更加清晰合理! 31
32
命令表以单独的双分号行结束,退出case语句
多路分支语句 case…esac 多路分支语句case用于多重条件测试, 语法结构清晰自然. 其语法为: case 字符串变量 in 模式1) 命令表1 ;; 模式2) 命令表2 …… 模式n) 命令表n esac case语句只能检测字符串变量 各模式中可用文件名元字符,以右括号结束 命令表以单独的双分号行结束,退出case语句 模式 n常写为字符* 表示所有其它模式 最后一个双分号行可以省略 32
33
实例. 程序prog4.sh检查用户输入的文件名, 用法为:
./prog4.sh string_name # The statement of case…esac if [ $# -eq 0 ] #包含命令行参数的个数 then echo "No argument is declared" exit fi case $1 in file1) echo "User selects file1" ;; file2) echo "User selects file2" *) echo "You must select either file1 or file2!" esac 33
34
循环语句 for…do…done 当循环次数已知或确定时, 使用for循环语句来多次执行一条或一组 命令。 循环体由语句括号do和done来限定。格式为: for 变量名 [in 单词表] do 命令表 done 变量依次取单词表中的各个单词, 每取一次单词, 就执行一次循环 体中的命令. 循环次数由单词表中的单词数确定. 命令表中的命令可 以是一条, 也可以是由分号或换行符分开的多条。 如果单词表是命令行上的所有位置参数时, 可以在for语句中省略 “in 单词表” 部分。 34
35
flist的值是ls的执行结果即当前目录下的文件名
实例 程序prog5.sh拷贝当前目录下的所有文件到backup 子目录下. 使用语法为: ./prog5.sh [filename] # The statement of for…do…done if [ ! -d $HOME/backup ] then mkdir $HOME/backup fi flist=`ls` for file in $flist do if [ $# -eq 1 ] if [ $1 = $file ] echo "$file found" ; exit else cp $file $HOME/backup echo "$file copied" done echo ***Backup Completed*** flist的值是ls的执行结果即当前目录下的文件名 命令行上有一个参数时 命令行上不带参数时 35
36
循环语句 while…do…done 语法结构为: while 命令或表达式 do 命令表 done
36
37
# The statement for while if [ $# -eq 2 ] then loop=$2 else loop=5 fi
创建文件程序prog6, 批量生成空白文件,用法为: prog6 file [number] ./a.sh file 6 # The statement for while if [ $# -eq 2 ] then loop=$2 else loop=5 fi i=1 while [ $i -lt $loop ] do > $1$i i=`expr $i + 1` done 根据命令行的第二个参数来确定循环的次数 建立以第一个参数指定的文件名前缀,例如以“file”开头, 变量i的值结尾的空文件名. 参见命令cmd > file 37
38
循环语句 until…do…done 语法结构为: until 命令或表达式 do 命令表 done
until循环与while循环的功能相似, 所不同的是只有当测试的 命令或表达式的值是假时, 才执行循环体中的命令表, 否 则退出循环. 这一点与while命令正好相反. 38
39
循环控制语句 break 和 continue 实例. 程序prog7的用法为: break n 则跳出n层;
continue n则转到最近n层循环语句的下一轮循环上. 实例. 程序prog7的用法为: prog7 整数 整数 整数 … 参数个数不确定, 范围为1~10个, 每个参数都是正整数。 39
40
用2求模, count的值只能是0或1 取所有位置参数 下 轮 循 环 是奇数 偶数放到偶数队列中 if [ $# -eq 0 ] then
echo "Numeric arguments required" exit fi if [ $# -gt ] echo "Only ten arguments allowed" for number do count=`expr $number % 2` if [ $count -eq 1 ] continue else output="$output $number" done echo "Even numbers: $output " 用2求模, count的值只能是0或1 取所有位置参数 下 轮 循 环 是奇数 偶数放到偶数队列中 40
41
8.5 Linux下shell函数
42
shell 函数 shell 函数 在shell程序中, 常常把完成固定功能、且多次使用的一组 命令(语句)封装在一个函数里,每当要使用该功能时只 需调用该函数名即可。 函数在调用前必须先定义,即在顺序上函数说明必须放 在调用程序的前面。 调用程序可传递参数给函数, 函数可用return语句把运行 结果返回给调用程序。 函数只在当前shell中起作用, 不能输出到子Shell中。 42
43
shell 函数 函数定义格式: 方式一: 方式二: function_name ( ) { command1 …… commandn }
function function_name ( ) { command1 …… commandn } 43
44
shell 函数调用 函数调用格式: 方式1: value_name=`function_name [arg1 arg2 … ]` 方式2:
函数的所有标准输出都传递给了主程序的变量 方式1: value_name=`function_name [arg1 arg2 … ]` 获取函数的返回的状态 方式2: function_name [arg1 arg2 … ] echo $? 44
45
实例 check_user( ) #查找已登录的指定用户 { user=`who | grep $1 | wc -l`
if [ $user –eq 0 ] then return #未找到指定用户 else return #找到指定用户 fi } while true # MAIN, Main, main: program begin here do echo "Input username: \c" read uname check_user $uname # 调用函数, 并传递参数uname if [ $? –eq 1 ] # $?为函数返回值 then echo "user $uname online" else echo "user $uname offline" done 45
46
Local variable_name =value
函数变量作用域 全局作用域:在脚本的其他任何地方都能够访问 该变量。 局部作用域:只能在声明变量的作用域内访问。 声明局部变量的格式: Local variable_name =value 46
47
函数变量作用域 Scope() { Local lclvariable =1 Gblvariable = 2
echo “lclavariable in function = $ lclvariable ” echo “Gblvariable in function = $ Gblvariable ” } Scope 47
48
8.6 Linux下shell数组
49
shell 数组 shell只支持一维数组 数组可以使用 “declare –a 数组名”来显示声明, 数组下标的范围没有任何限制 , 同时也不必使用 连续的分量。 数组也可不必显示声明,shell会解析其为数组 49
50
shell 数组 数组定义格式: 方式一: 方式二: array_name[0]=var0
array_name=(var0 var1 ...varN) array_name[0]=var0 array_name[1]=var1 array_name[n]=varN 50
51
shell 数组引用 取得数组的全部元素: echo ${ARRAY_NAME[@]} 取得数组中的元素:
valuen=${ARRAY_NAME[n]} 取得数组元素的个数: 或者 length=${#ARRAY_NAME[*]} 取得数组单个元素的长度: lengthn=${#ARRAY_NAME[n]} 51
52
实例 #!/bin/bash i=0 n=8 while [ "$i" -lt $n ] ; do
echo "Please input strings ... `expr $i + 1`" read array[$i] b=${array[$i]} echo "$b" i=`expr $i + 1` done 从“标准输入”读入n次字符串,每次输入的字符串保存在数组array里 52
Similar presentations