shell 脚本编程

51
College of Information Science and Engineering Shandong Agricultural University SHELL 脚脚脚脚

Upload: elaine

Post on 19-Mar-2016

89 views

Category:

Documents


8 download

DESCRIPTION

College of Information Science and Engineering. SHELL 脚本编程. Shandong Agricultural University. shell 脚本可将多条命令编写到一个文件中,通过运行脚本文件即可完成指定的工作。 常用于系统启动、程序编译等需要重复执行大量命令的场合。能提高用户操作和管理员进行系统管理的效率。一般步骤: 编辑器编写脚本程序 shell 做解释程序,非交互地执行脚本,两种执行方式: 用 sh 命令执行脚本文件 给脚本文件添加执行权限,用 ./ 命令执行. HELLO WORLD!. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: SHELL 脚本编程

College of Information Science and Engineering

Shandong Agricultural University

SHELL脚本编程

Page 2: SHELL 脚本编程

2

shell 脚本可将多条命令编写到一个文件中,通过运行脚本文件即可完成指定的工作。 常用于系统启动、程序编译等需要重复执行大量命令的场合。能提高用户操作和管理员进行系统管理的效率。一般步骤:

1. 编辑器编写脚本程序2. shell 做解释程序,非交互地执行脚本,两种执行方式:

用 sh 命令执行脚本文件 给脚本文件添加执行权限,用 ./ 命令执行

Page 3: SHELL 脚本编程

3

HELLO WORLD!1. vi hello.sh

按 i 进入插入模式 输入 echo “hello world!” 输入 : 切换到命令行模式, wq 保存退出

2. sh hello.sh或者

chmod 755 hello.sh./hello.sh

Page 4: SHELL 脚本编程

4

一.基础知识二.shell 变量三.shell 控制流程语法四.shell 中的常用命令与符号五.脚本实例

SHELL 脚本编程

Page 5: SHELL 脚本编程

5

一、基础知识1. 一般以 .sh 为文件后缀。2. 常见的两种执行方式

文件全路径名要求文件必须有执行权限,如chmod 755 run.sh./run.sh 执行当前目录下的

run.sh 文件 sh 文件全路径名

sh 目录 /run.sh文件开头可指定一个或多个解释脚本程序的 shell,如 #!/bin/bash,注意 /bin 不要漏了“ /”

Page 6: SHELL 脚本编程

6

shell 里的特殊字符 注释符 #

除了 #!/bin/bash 里的 # 特殊 美元符 $

使其后的普通字符作为变量。如: $a 表示变量 a 的值。变量字符长度超过 1 个字符用{} 括起来。

单引号’ 强制取消转义符号作用,被引起的字符全部做普通字符,即全部原样。

echo ‘my $SHELL’ 双引号”

引号内的内容,除 $ 、转义符 \ 、倒引号 ` 这三个保留特殊功能,其他字符均强制做普通字符。

Page 7: SHELL 脚本编程

7

倒引号 `引号内的字符串当做 shell 命令行解释执行,得到的结果取代整个倒引号括起来的部分。

`pwd` 即 pwd 命令的执行结果$LOGNAME 系统变量

Page 8: SHELL 脚本编程

8

练习一下:区别下面几句 echo ‘my home is $HOME’ echo “my home is $HOME” echo `my home is $HOME`

echo “my home is `pwd`” echo ‘my home is `pwd`’

` 用于括起来 shell 命令 ‘ 用于原样显示

Page 9: SHELL 脚本编程

9

二、 shell 变量变量使用的基本知识三种变量1.环境变量2.shell 系统变量3.普通变量

Page 10: SHELL 脚本编程

10

常用的变量操作命令export 用于定义或修改环境变量。普通变量可以不用声明就可使用。

$ export TEST=“Test...” # 定义一个新环境变量。 $ export TEST=$TEST:“ add1”# 向环境变量

TEST 中加入新值。 $ unset TEST # 删除变量 $ readonly TEST # 将环境变量

TEST 设为只读,只读的变量不能被删除。

Page 11: SHELL 脚本编程

11

使用变量的格式要求

a=morningecho “good ${a}!”unset a

注意赋值不要有空格使用变量时,变量名前必须加 $ 符号,变量名最好用 {} 括起 。灵活用 echo 输出提示信息,方便调试脚本。

local 变量名 变量默认是全局作用,加 local 会限制为局部

Page 12: SHELL 脚本编程

12

多种变量赋值方式① 直接赋值

a=78② 将一个命令执行的输出赋给指定的变量

a=`date`③ 从标准输入设备读入用户输入的值

read a read 变量 1 [ 变量 2 …]

从键盘上读取多个变量的值时,用户输入数据以空格或者Tab 键作为分隔。

如果输入的数据个数不够,则从左到右对应赋值,没有输入的变量为空; 如果输入的数据个数超了,则从左到右对应赋值,最后一个变量被赋予剩余的所有数据。

Page 13: SHELL 脚本编程

13

1. 环境变量简单说就是计算机系统大环境下的变量

如: windows 系统中,为什么【开始 | 运行】输入 notepad 能启动记事本?记事本程序在 system32文件中,而该目录在系统环境变量 path中有记录;

如: java开发时, msdos窗口中如何可以在任何目录下都能执行 javac 命令?将 javac所在目录写入系统环境变量 path里。

Page 14: SHELL 脚本编程

14

Linux 常用的环境变量有PATH , HOME , SHELL 等等。

【查看环境变量】: env 命令显示所有已定义的环境变量    $ env  HOSTNAME=terry.mykms.org   PVM_RSH=/usr/bin/rsh   SHELL=/bin/bash   TERM=xterm  HISTSIZE=1000   ...   set 命令显示所有本地定义的 Shell 普通变量

Page 15: SHELL 脚本编程

15

【修改环境变量】两种方式:

① 在命令行用 export 命令修改,只在本次登录的shell 内有效。设置好的环境变量可以在当前用户运行的所有程序中使用。

② 在配置文件中修改环境变量的默认值,新登陆仍可有效。

Page 16: SHELL 脚本编程

16

修改 PATH 环境变量的例子修改 PATH 环境变量,使脚本不用加路径,直接输入文件名字即可执行。1 )命令行修改环境变量以下在用户 user主目录下操作:

① mkdir shdir && cd shdir② vi hello③ chmod 755 hello④ cd ~⑤ export PATH=$PATH:$HOME/shdir⑥ 在任何目录下,输入 hello即可执行该文件。

本方式下环境变量如果修改错了, exit 退出后重新登陆即可恢复系统默认的值。

Page 17: SHELL 脚本编程

17

2)配置文件中修改环境变量 注意,修改环境变量前最好先备份一下旧的:

export tem=$PATHecho $tem >>pathbake

需要知道环境变量与哪些配置文件有关:不同发行版会有不同,但命名还是有通性的:find / -name “*profile”find / -name “*bashrc”

Page 18: SHELL 脚本编程

18

ubuntu 下用户登录 Linux涉及的几个重要配置文件有: /etc/bash.bashrc:为每一个运行 bash shell的用户执行此文件 . 每当bash shell被打开 , 该文件被读取。

/etc/profile :为所有用户设置环境信息 , 系统第一次登录时该文件被执行 . ~ /.profile :用户使用该文件设置专用于自己使用的信息,用户登录时该文件仅执行一次 ! 默认情况下该文件设置一些环境变量,执行用户的 .bashrc文件。 ~ /.bashrc:专用于用户的 bash shell 的 bash信息 , 当用户登录时以及每次打开新的 shell 时 , 该该文件被读取。一般仅修改普通用户环境变量配置文件,避免修改系统的环境定义文件,如命令别名可修改 ~ /.bashrc :环境变量可修改~ /.profile :

Page 19: SHELL 脚本编程

19

2)配置文件中修改环境变量以下在用户 user主目录下操作:① vi .profile

在文件末尾添加一行export PATH=$PATH:$HOME/shdiresc返回命令模式, :wq保存退出。

② 用 source命令使配置文件立即有效source .profile

③ 现在,在任何目录下即可执行 shdir目录下的所有可执行文件了。

Page 20: SHELL 脚本编程

20

试一试:在上述文件最后都加入一句: echo “文件名”;操作方式如 echo “echo “****enter /etc/profile”” >> /etc/profile。多次 exit退出登录, su切换身份,重启,登录看看效果。

Page 21: SHELL 脚本编程

21

2.SHELL 的系统变量常用于 SHELL参数检测的有$# 命令行参数个数$* “参数 1 参数 2…”形式保存的所有参数$@ “参数 1”“参数 2”…形式保存的所有参数$n 第 n 个参数$? 前一个命令或函数的返回码$0 当前程序名$$ 本程序的 PID$! 上一个命令的 PID

Page 22: SHELL 脚本编程

22

使用 shell预定义变量的脚本举例

Page 23: SHELL 脚本编程

23

3. 用户变量 变量名:由用户定义,名字由字母、下划线组成,

第 1 个字符不能是数。 变量声明:

可以不声明直接赋值,默认赋值是字符串的。 声明数字或数组需加 declare ,如:

declare –i a=8 等号两边不要空格declare –i b=8declare –i cc=${a}*${b} 变量 c 若不定义会得不到数值 64echo $c

Page 24: SHELL 脚本编程

24

三、控制流程1.如何进行条件判断2.分支、循环控制结构举例3.函数

Page 25: SHELL 脚本编程

25

1. 如何进行条件判断 条件测试命令 test

test -参数 n1 # 一元判断test n1 -参数 n2# 二元比较注意参数与判断的变量间要空格;

条件测试式[ -参数 n1 ] # 一元判断[ n1 -参数 n2 ] # 二元比较中括号与参数间要有空格

真返回 0 ,假返回 1

①整数比较test 1 –lt 4 # 判断 1<4echo $? # 结果为 0

整数判断相关参数:-eq 等于-ne 不等于-lt 小于-le 小于等于-gt 大于-ge 大于等于

Page 26: SHELL 脚本编程

26

③判断文件判断mydoc是否是目录[ -d mydoc ]-f 存在且是普通文件-d 存在且是目录-s 存在且字节数大于 0-r 存在且可读-w 存在且可写-x 存在且可执行……

②字符串[ $a=“hello” ][ –z $a ] 字符串长度是否为 0 = 等于 != 不等于 > 按字符编码表排序,前面的是否在后面字符的前面 -z 字符串长 =0,空字串 -n 字符串长 >0,非空字串④逻辑操作[ $a=“hello” –a –n $a ]echo $? 显示上一步结果

-a 逻辑与-o 逻辑或! 逻辑非

Page 27: SHELL 脚本编程

27

shell 脚本编程中的中括号 区别 test、 [ 、 [[

test、 [ 是 bash命令。 [[ 是 bash程序语言中的关键字。[[ 中使用 && 和 ||逻辑符号,可以使用通配符 ( 使用通配符时字符串不要引号);

如a=helloecho $a判断 a 是否等于 hello且非空,可写成下面三种形式(注意等号两边要空格 , 变量 a不要忘记 $ 符号) : test $a = “hello” –a –n $a [ $a = “hello” –a –n $a ] [[ $a = “hello” && –n $a ]] [[ $a = he* && –n $a ]]

type [ [[ test得到这样的输出 [ is a shell builtin [[ is a shell keyword test is a shell builtin

Page 28: SHELL 脚本编程

28

一些有用的计算命令 后面例子涉及的命令

seq 命令:产生 1-9 的数字序列; expr 命令:将其后的串解释为表达式并计算其值,运算符前后需有空格;用于整数值运算。 $[] 将中括号内的表达式作为数学运算先计算结果再输出。 let 表示强制进行数学运算,以为系统默认“+”等运算符是作为字符串处理的。

let “a+=1" a=$[$a+1]a=`expr $a + 1`# 加号两边要有空格前两种方式在 bash 下有效,在 sh 下会出错。

bc :计算器,可以用于数制转换。从效率来说 let==$(()) > expr > bc ${}: 不只可做变量符号,还可用于字符串截取;

Page 29: SHELL 脚本编程

29

2. 控制结构举例1 )分支结构if

if [ $# -eq 0 ]then

echo “ 输入了 0 个参数”elif [ $# -lt 1 ]then echo “ 输入了多个参数”else echo “ 输入了 1 个参数”fi

Page 30: SHELL 脚本编程

30

case

case $# in 0) echo “ 输入了 0 个参数” ;;

1) echo “ 输入了 1 个参数” echo “参数是 $1”;;

*) echo “ 输入了多个参数” ;; esac

分支可以有多条语句,每条语句单独一行,最后以两个分号结尾。

Page 31: SHELL 脚本编程

31

2 )循环结构 for 例子——输出 100 内 10 的倍数

for i in `seq 1 9`do

echo `expr $i \* 10`done

改为输出 a 到 b 序列数各数的 10倍数:read a bfor i in `seq $a $b`

do 要写在上一行,前面需加分号;倒引号里的字符串中乘号前要加转义符,与数字间要有空格。

Page 32: SHELL 脚本编程

32

输出 shell 程序参数的小例子:echo “a example output shell’s params”case $# in 0)echo “none param”;;

1)echo “one param”echo “param is $1”;;

*)echo “more than one param”;;esacif [ $# -gt 1 ] ;then

echo “******out put all params******”for i in $* ;do

echo $i;done

elseecho “*****none to output******”

fi

注意此处 i in $* 中的i 前不能加 $ 符号。

Page 33: SHELL 脚本编程

33

while 例子——求 1 到 100 的和i=1sum=0while [ $i –le 100 ] ; do let sum+=$i

let i+=1doneecho “sum 1 to 100 is $sum ”

还可写做: sum=$[$sum+$i] i=$[$i+1]或sum=`expr $sum + $i`i=`expr $i + 1`

Page 34: SHELL 脚本编程

34

命令结果重定向1 stdout 标准输出2 stderr 标准错误

命令 >file输出重定向到文件 file ,终端上只能看到标准错误。 命令 2>file错误重定向到文件 file ,终端上只能看到标准输

出 .

Page 35: SHELL 脚本编程

35

屏蔽命令的任何输出cp /etc/my.conf >/dev/null 2>&1

这是一个错误命令,执行结果是什么功能都不实现,且没有任何信息或错误提示输出。cp 命令没有目标文件 ,应该输出错误。 2>&1 表示错误重定向指向标准输出。>/dev/null又使标准输出重定向到空设备,最后就是没有任何输出信息。

Page 36: SHELL 脚本编程

36

* 有趣的 IO Redirection 覆盖还是不覆盖 1 ) command >file 2>file2 ) command >file 2>&1

1 )的写法 ,stdout和 stderr都直接送到 file中 , 会出现两个同抢占 file的管道, file会被打开两次 ,stdout和stderr输出的信息会互相覆盖。

2 )的写法将 stdout直接送向 file, stderr继承 1 的管道后 , 再被送往 file,此时 ,file 只被打开了一次 , 也只使用了一个管道 FD1,它包括了 stdout和 stderr的内容。 从 IO效率上 , 后面一条的命令效率要高 , 所以在编写shell脚本的时候 , 常用 command > file 2>&1 这样的写法。

重定向导致文件被清空$ cat file显示 hello$ cat file > file$ cat file > file 会先清空重定向文件 file,所以最后 cat显示的file就成空了。

Page 37: SHELL 脚本编程

37

*shell函数sORc(){

if [ $1 = “s” ]then

echo “start successfully”elif [ $1 = “c” ]then

echo “close successfully” fi}#- - - - - - - - - - - - - - - - - - - - - - - - -if [ $# -eq 0 ]then echo “please input a params” echo “s to start, c to close”else if [ $1 = “q” ]

then echo “exit”

elsesORc $1

fifi

Page 38: SHELL 脚本编程

38

阅读 csdn博客实例:由于在工作中需要一次性关闭 linux的 opt目录下安装的多个 tomcat,因此有了写一个脚本统一关闭开启这个目录下所

有 tomcat。 Tomcat安装目录: opt/tomcat/tomcat_8080; /opt/tomcat/tomcat_9080 。

思路:循环调用 tomcat自身 bin目录下的startup.sh、 shutdown.sh,开启或是关闭 tomcat。

脚本代码:#! /bin/shp=(4080 7080) #定义批量处理端口此处是函数定义(见下页)if [ $# -eq 0 ] then echo "请输入执行参数 " echo " -s 启动所有 /opt/tomcat/下的 tomcat" echo " -c 关闭所有 /opt/tomcat/下的 tomcat" else #echo "start repari .." startOrCloseTomcat $1fi

Page 39: SHELL 脚本编程

39

# 开启或关闭 tomcat服务器startOrCloseTomcat(){ if [ $1 = -s ] ; then

foreachStartup elif [ $1 = -c ] then foreachShutdown else echo "参数不正确!请重新输入! " exit #退出该函数 fi }

# 循环开启 tomcatforeachStartup(){ for port in ${p[@]} dos_res=`/opt/tomcat/*tomcat*$port/

bin/startup.sh` echo "$port-tomcat已经开启 !" done}# 循环关闭 tomcatforeachShutdown(){ for port in ${p[@]} do

s_res=`/opt/tomcat/*tomcat*$port/bin/shutdown.sh`

echo "$port-tomcat已经关闭 !" done}

Page 40: SHELL 脚本编程

40

四、脚本实例① 编写一个名为 iffile 程序,它执行时判断 /bin 目录下 date 文件是否存在?② 编写一个名为 greet 的问候程序,它执行时能根据系统当前的时间向用户输出问候信息。设从半夜到中午为早晨,中午到下午六点为下午,下午六点到半夜为晚上。③ 编写一个名为 ifuser 的程序,它执行时带用户名作为命令行参数,判断该用户是否已经在系统中登录,并给出相关信息。④ 编写一个名为 menu 的程序,实现简单的弹出式菜单功能,用户能根据显示的菜单项从键盘选择执行对应的命令。⑤ 编写一个名为 chname 的程序,实现批量修改当前目录下的文件扩展名,如 .txt 文件更名为 .doc 文件。⑥ 编写一个名为 chuser 的程序,执行中每隔 5 分钟检查指定的用户是否登录系统,用户名从命令行输入;如果指定的用户已经登录,则显示相关信息。

Page 41: SHELL 脚本编程

41

#! /bin/sh -fname=/bin/dateif (test –f “$fname”) then

echo “exist”fi

说明:在 shell 程序中经常需要判断所处理的文件是否存在。本程序采用 if 语句的简单格式测试 date 文件,如果存在,则显示相关信息,否则退出 if 语句。

①判断 /bin 目录下 date 文件是否存在

Page 42: SHELL 脚本编程

42

提示(获取当前的小时数) date|cut –c n- (n 的数值为多少,自己试试 ) date +%H更多 date说明见本页备注

#! /bin/sh -hour=`date +%H`if test “$hour” –ge 0 –a “$hour” –le 11;

thenecho “Good morning!”

elif test “$hour” –ge 12 –a “$hour” –le 17; then

echo “Good afternoon!”else

echo “Good evening!”fi

②根据系统当前的时间向用户输出问候信息

Page 43: SHELL 脚本编程

43

who 查看已登陆的用户 grep 在指定内容中搜索包含匹配字符串的内容

–q 禁止显示搜索到的信息 #! /bin/sh -

if test $# -ne 1 thenecho "Incorrect number of arguments" echo "Usage: ifuser username"else user=$1 if who | grep –q $user ; then echo $1 "user is logged on." exit 0 else echo $1 "user is not logged on." exit 1 fifi

说明见本页备注

③判断用户是否已经在系统中登录

Page 44: SHELL 脚本编程

44

④简单的菜单功能 #! /bin/sh -

clearecho " -----------------MENU------------------"echoecho " 1.Find files modified in last 24 hours"echo " 2.The free disk space"echo " 3.Space consumed by this user"echo " 4.Exit"echo echo -n " Select:“

read choicecase $choice in1)find $HOME -mtime -1 -print;;2)df;;3)du -s $HOME;;4)exit;;*)echo "Invalid option"esac

说明见本页备注

Page 45: SHELL 脚本编程

45

在 Linux 系统中不支持mv *.txt *.doc 这样的更名命令形式,如果需要将文件成批地更名需要写一个 shell 脚本文件。 basename 命令从随后的字符串剥去指定的串,如

basename hello.sh .sh结果为 hello #! /bin/sh -

for file in *.txtdo

leftname=`basename $file .txt`mv $file $leftname.doc

donefor语句的参数列表中使用了“ *”通配符。

⑤将当前目录下所有的 .txt 文件更名

Page 46: SHELL 脚本编程

46

一个无限循环,每五分钟可用 sleep 300 who|grep 利用重定向到 /dev/null屏蔽执行命令过程输出到显示屏的信息 #! /bin/sh –

if test $# -ne 1then

echo “Usage: chuser username”else

user=”$1”until who |grep “$user”>/dev/nulldo

sleep 300doneecho “$user has logged on!”

fi 说明见本页备注

⑥每隔 5 分钟检查指定的用户是否登录系统

Page 47: SHELL 脚本编程

47

作业题编写一个脚本文件 checkuser ,运行时带一个用户名做参数,执行脚本时检查是否有该用户。要求: 1 )命令行的用户名参数不能是数字,不能为空,不符合要求时要能给错误提示

; 2 )有或没有该用户都要给出提示。关键代码提示: a=`cut -d: -f1 /etc/passwd | grep -c “^$1$”`

if [ $a -gt 0 ] 利用 bc计算器判断参数是否是数

b=$(echo $1|bc 2>/dev/null) if [[ $b != $1 ]] 若参数是纯数字字符串,被转换为数后的 $b会与原参数相同。否则,会被转换为 0 。即转换后和转换前不同就可以判断不是数。注意字符串运算符 != 前后空格。

可拓展学习的 4 个 linux筛选数据常用工具: cut, grep, awk, sed

Page 48: SHELL 脚本编程

作 业1.命令脚本综合题。2.课件最后的作业题。* 要求用 VI 编辑器写脚本,重点记录下编辑过程中用到的删除、复制等操作。

Page 49: SHELL 脚本编程

49

更多练习1. 练习 vi 编辑器的使用并熟练掌握它。2. 简要说明 shell 的功能,常用的 shell 有哪些?3. 查看系统 PATH 环境变量,了解可执行文件的路径信息4. 如何实现用系统当前日期和时间作为第一级提示符?5. 如何实现用 alias 命令将 cp 命令设置别名为 copy?6. 简要说明 shell 程序的结构。7. 简要说明运行 shell 脚本程序的几种方法。8. 如果你希望编写的脚本程序在任何一个目录下都能直接执行(输入程序名后回车),则应该如何处理?

Page 50: SHELL 脚本编程

50

1. 变量的赋值方式有几种?各用在哪些场合?2. 写出几个与命令行参数有关的变量并简要说明如何在脚本中引用。3. 以下 shell 脚本文件存在什么错误?

echo what month is this?read $monthecho $ month is as good a month as any.

4. 编写一个 shell 程序,它输出一个 1 到 10之间的平方和立方对照表。5. 编写一个名为 reverse 的 shell 程序,将输入的若干个命令行参数以逆序输出。

用其它循环语句编程实现本题的功能。

Page 51: SHELL 脚本编程

51

1. 编写一个 shell 脚本程序,它能根据输入的命令行参数采取不同的动作:如果是目录,则列出该目录中的文件;如果是可执行的文件,则用 shell 执行之;如果是可读的文件,则分屏显示其内容。2. 编写一个求平方和求立方的函数,在 shell 程序中调用它实现第十四题的功能。3. 编写一个弹出式菜单的 shell 程序并实现其简单的菜单功能: ************************************************* MENU *

* 1.copy 2.rename ** 3.remove 4.find ** 5.exit * ************************************************即用户按下数字 1 ,则提示用户输入源和目的文件名后执行复制;输入数字 2 ,则提示用户输入要更名的文件或目录名后执行更名操作;输入数字 3 和 4 分别执行删除和查找操作;输入数字 5 ,则退出该菜单 shell 程序的执行。