《SHELL编程学习笔记》由会员分享,可在线阅读,更多相关《SHELL编程学习笔记(38页珍藏版)》请在金锄头文库上搜索。
1、 SHELL 编程 学习笔记 deewenic 2011/2/4 该文档为 SHELL 编程视频学习的相关笔记及摘要,分为基础编程和高级编程两部分。 deewenic SHELL 编程学习笔记 2011.2.4 2 目 录 PART 1.基础编程基础编程 . 4 CHAPTER 1:SHELL简介 . 4 1.1 什么是 shell . 4 1.2 存取权限与安全 . 4 1.3 shell 脚本 . 5 1.4 shell 特性 . 6 CHAPTER 2:变量和运算符. 7 2.1 变量 . 7 2.2 引号 . 9 2.3 运算符 . 9 CHAPTER 3:SHELL输入和输出 . 1
2、0 3.1 echo 命令 . 10 3.2 read 命令 . 10 3.3 cat 命令 . 10 3.4 管道 . 10 3.5 tee 命令 . 10 3.6 标准输入、输出和错误 . 11 3.7 文件重定向 . 11 3.8 结合使用标准输出和标准错误 . 11 3.9 合并标准输出和标准错误 . 12 3.10 exec 命令. 12 3.11 文件描述符 . 12 CHAPTER 4:控制流结构 . 12 4.1 if 语句 . 12 4.2 case 语句. 14 4.3 for 语句 . 15 4.4 until 语句 . 15 4.5 while 语句 . 16 4.6
3、break 和 continue 控制 . 16 CHAPTER 5:文本过滤 . 17 5.1 正则表达式 . 17 5.2 find 命令 . 19 5.3 grep 命令 . 20 5.4 awk 命令 . 21 5.5 sed 命令 . 22 5.6 合并与分割 . 22 CHAPTER 6:SHELL函数 . 22 6.1 函数定义. 22 6.2 参数传递. 23 6.3 函数文件. 23 deewenic SHELL 编程学习笔记 2011.2.4 3 6.4 检查载入函数和删除函数 . 24 6.6 函数返回状态值 . 24 CHAPTER 7:脚本参数传递. 24 7.1 s
4、hift 命令. 24 7.2 getopts . 25 PART 2.高级编程高级编程 . 26 CHAPTER 1:深入介绍 . 26 1.1 深入讨论 awk . 26 1.2 深入讨论标准输入() . 30 CHAPTER 2:SHELL工具 . 32 2.1 日志文件. 32 2.2 信号 . 33 2.3 trap 捕捉信号 . 33 2.4 eval 命令 . 35 2.5 logger 命令 . 35 CHAPTER 3:运行级别脚本介绍 . 35 3.1 运行级别. 35 3.2 inittab . 35 3.3 启动应用程序 . 36 CHAPTER 4:几个脚本例子. 3
5、6 4.1 kill_process.sh . 36 4.2 cpdir.sh . 36 deewenic SHELL 编程学习笔记 2011.2.4 4 Part 1.基础基础编程编程 Chapter 1:shell 简介简介 1.1 什么是什么是 shell shell 是核心程序(kernel)之外的指令解析器,是一个程序,同时是一种命令语言和程序设计语言。作为一种命令语言,可以交互式的解析和执行用户输入的命令。 :-$ cat /etc/shells 可以查看系统中拥有哪几种 shell。 :-$ echo $SHELL 可以查看当前运行的 shell。 bash 中要查看某开头的命令
6、,敲两次 tab 键即可查看。例如,要查看 ls 开头的命令可输入 ls 后连敲两次 tab 键,则自动显示出以 ls 开头的命令。 查看命令使用方法可通过“:-$ man 命令”或者“:-$ info 命令”查看。 1.2 存取权限与安全存取权限与安全 文件和目录的权限。 -文件查看长格式命令(ls -l)释义- 文件类型文件类型:-:普通文件 d:目录文件 l:链接文件 b:块设备文件 c:字符设备文件 p:命名管道文件 s:Socket 文件 改变文件权限只有 root 用户和该文件拥有者才能改变,改变权限命令有 chmod 符号模式:chmod who operator permiss
7、ion filename who(u,g,o,a) :u:拥有者;g:拥有者所属组;o:其他用户;a:全部用户 operator(+,-,=) :+:增加权限;-:减去权限;=:设定权限 permission(r,w,x,s,t) :r:读权限;w:写权限;x:执行权限;s:setuid 权限(设定 s 位后,执行权限 x 会变成 s,如有文件 test,若其权限为 rwsr-xr-x,则组用户或其他用户执行该文件时将会有拥有者权限。 如果 test 拥有者是 root用户,那么组用户或其他用户可通过 test 文件运行其他 root 权限命令,所以 s位比较危险) ;t:运行文件时放在缓存(
8、swap 分区)里面运行 绝对模式:chmod mode fielname mode:r-4;w-2;x-1;例:chmod 740 test 改变文件拥有者和所属组:chown 和 chgrp chown -R owner filename # 改变文件拥有者,如果是目录,加上-R 代表递归及deewenic SHELL 编程学习笔记 2011.2.4 5 改目录及目录下的所有文件均改变 chown owner.group filename # 改变文件拥有者及所属组 chown .group filename # 改变文件所属组 chgrp -R filename # 改变文件所属组 um
9、ask 来确定创建文件时的默认权限 如运行 :-$ umask 得到 0022,创建文件时默认属性为 rw-rr-,创建目录时默认属性为 rwxr-xr-x,umask 值与权限对应如表: umask 文件文件 目录目录 0 6 7 1 5 6 2 4 5 3 3 4 4 2 3 5 1 2 6 0 1 7 0 0 改变 umask 值可运行 :-$ umask 数值, 如 :-$ umask 000, 即将 umask 值改为0000,则默认生成文件权限为 666,目录默认权限为 777。 在 etc/profile($HOME/.profile 或$HOME/.bash_profile,$
10、HOME 是针对当前用户做改变,etc/profile 是对全局用户变动)中可以定义 umask 值(tips:在 vi 中的命令模式下可输入 /关键字 并回车查找内容) 。 setuid(suid/guid) :关于 setuid 会用到的情况,比如备份数据库必须使用管理员即 root用户权限,这时可把备份数据库写为 shell 脚本,设定 s 位,那么当其他用户要备份数据库时则可以执行该脚本以临时以 root 用户身份备份数据库,当脚本执行完毕则又回到本来用户身份。这样既能以 root 身份备份数据库又保证了安全性。 符号链接(硬链接/软链接) ln -s source_path targ
11、et_path 1.3 shell 脚本脚本 使用 shell 脚本的原因功能强大,节约时间 shell 脚本基本元素 #!/bin/bash # 第一行,#表示注释 变量 流程控制结构 一个简单脚本示例: #!/bin/bash # 这是一个打印 hello world 的 shell 脚本 printchar=hello world echo $printchar; echo $HOME deewenic SHELL 编程学习笔记 2011.2.4 6 shell 脚本运行方式 chmod u+x helloworld.sh ./helloworld.sh 1.4 shell 特性特性 别
12、名 alias 例:alias copy=cp,alias ll=ls -lah等,将命令定义为自己熟悉的别名。可在$HOME/.bashrc 下定义 管道:把一个命令的输出连接到另外的一个命令的输入,用符号 | ,如 ls | sort。 命令替换 用 (反引号)括起来的命令执行后的结果作为参数或内容,如文件 myfile 里有内容为 parm 和 findfile rootlocalhost:-# cat myfile parm findfile rootlocalhost:-$ ls cat myfile -al -rw-r-r- 1 deewenic deewenic 0 2011-0
13、1-28 14:14 findfile -rw-r-r- 1 deewenic deewenic 0 2011-01-28 14:14 parm 重定向() :与管道相关,可以改变程序运行的输入来源和输出地点。如: sort myfile.txt # 表示 sort 的输入来自 myfile.txt sort myfile_dort.txt # 表示输出到 myfile_dort.txt 后台处理:一个终端可以后台运行多个命令 nohup 命令 & 例,后台压缩打包 :-$ nohup tar -czf enerco.tar.gz enerco & 可通过 :-$ jobs -l 查看后台运行
14、的程序 模式匹配: 显示以 txt 为扩展名的文件或显示以 a 开头的文件, 这种能力就称模式匹配。 如 :-$ ls *.txt 就属于模式匹配 变量 特殊字符 双引号(”) :用来使 shell 无法认出空格、制表符和其他大多数特殊字符。如要创建名为“hello world”的目录,如果不用双引号括起来,则 shell 会认为是两个参数,从而建立成 hello 和 world 两个目录而不是 hello world 目录,所以需用双引号。 单引号() :用来使 shell 无法认出所有特殊字符。 反引号() :用来替换命令。 反斜杠 () : 用来使 shell 无法认出其后的字符, 使其
15、后的字符失去了特殊的含义。如创建名为“test dir”的文件,除可以用双引号和单引号外,也可以用,例:touch test dir。 分号(;) :允许在一行上放多个命令。 &:命令后台执行。 括号(()) :创建成组的命令。 打括号() :创建命令块。 竖杠(|) :管道表示符。 &:表示重定向。 deewenic SHELL 编程学习笔记 2011.2.4 7 * ? ! :表示模式匹配。 $:变量名的开头。 #:表示注释(第一行除外) 。 空格,制表符,换行符:当作空白。 Chapter 2:变量和运算符:变量和运算符 2.1 变量变量 本地变量:在用户现在的 shell 生命期的脚本
16、中使用。 在 shell 中直接定义本地变量,variable=value,如 :-$ LOCALTEST=”test”,则定义了变量 LOCALTEST 值为 test,可用 echo $LOCALTEST 或 echo $LOCALTEST。本地变量可用 set 命令查看,如下: rootlocalhost:-# LOCALTEST=”test” rootlocalhost:-# echo $LOCALTEST test rootlocalhost:-# LOCALTEST=”modify” rootlocalhost:-$ echo $LOCALTEST modify rootlocal
17、host:-# set | grep “LOCALTEST” LOCALTEST=modify 若退出当前 shell,则之前定义的本地变量便消失。 若定义变量前加上 readonly,readonly variable=value,则该变量只读,不可再进行改变。用命令 readonly 可进行只读本地变量的查看。 环境变量:用于所有用户进程(经常称为子进程) 。登录进程为父进程。shell 中执行的用户进程均称为子进程。不像本地变量(只用于现在的 shell) ,环境变量既可用于父进程也可用于所有子进程 (本地变量不可用于所有子进程中) , 包括编辑器、 脚本和应用。 可在$HOME/.ba
18、sh_profile 或者/etc/profile 下设置环境变量,用 export 命令,如 export CHINAITLAB=”shenzhen”。用 env 或者直接 export 命令可查看环境变量。 变量替换:用变量的值替换其名字,即使用变量值。替换表达方式如下 $variable 或 $variable 显示实际值到 variable $variable:-value 如果未设置 variable,则显示其值 value $variable:+value 如果设置了 variable,则显示其值 value,否则,为空 $variable:=value 如果未设置 variabl
19、e,设置其值,并显示 $variable:?value 如果未设置 variable,显示用户定义错误信息 value 变量清除:使用 unset variable 即可清除变量,如 :-$ unset test(readonly 变量不可用 unset 清除) 。 位置变量:存放程序参数的变量,位置变量表示为$0,$1 $9 $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 脚本名字 value1 value2 value3 value4 value5 value6 value7 value8 value9 如有 shell 脚本文件 parm.sh 功能为查找文件名为参数所给的文
20、件,参数为 1 个,则会deewenic SHELL 编程学习笔记 2011.2.4 8 使用到$1,脚本如下: #!/bin/bash #parm.sh find /home/deewenic -name $1 -print 执行结果如下: rootlocalhost:-# ./parm.sh parm /home/deewenic/parm 标准变量:bash 默认建立了一些标准环境变量,可在/etc/profile 中定义。 EXINIT:vi 相关,初始化时的一些参数 HOME:当前用户主目录 IFS:字符间的分隔域,默认是空格或者 tab 键,可自定义 LOGNAME:当前用户名 M
21、AIL: MAILCHECK:检查邮件的频率,单位为秒 MAILPATH: TERM:终端类型 PATH:可执行文件去寻找的路径 TZ:表示时区 PS1:表示终端输入提示符,即输入命令行前面的rootlocalhost:-#这一串字符,root 用户为#,普通用户为$ PS2: PWD:表示当前目录 SHELL:当前运行的 shell MANPATH:帮助文档存放目录 TERMINFO:终端配置信息 特殊变量 $#(传递到脚本的参数个数) $*(以一个单子符串显示所有向脚本传递的参数。与位置变量不同,此选项参数可以超过 9 个) $(脚本运行的当前进程 ID 号) $!(后台运行的最后一个进程
22、的进程 ID 号) $(与$*相同,但是使用时加引号,并在引号中返回每个参数) $-(显示 shell 使用的当前选项,与 set 命令功能相同) $?(显示最后命令的退出状态。0 表示没有错误,其他任何值表明有错误) 影响变量的命令 declare:设置或显示变量 -f 只显示函数名 -r 创建只读变量(declare 和 typeset) -x 创建转出变量 -i 创建整数变量 使用+替代-,可以颠倒选项的含义 export:用于创建传给子 shell 的变量即环境变量 - 表明选项结束,所有后续参数都是实参 -f 表明在“名-值”对中的名字是函数名 deewenic SHELL 编程学习
23、笔记 2011.2.4 9 -n 把全局变量转换成局部变量,即命令的变量不再传给 shell -p 显示全局变量列表 readonly:用于显示或设置只读变量 - 表明选项结束 -f 创建只读变量 set:设置或重设各种 shell shift n:用于移动位置变量,调整位置变量,使$3 的值赋予$2,$2 的值赋予$1,$0 不受影响,不带 n 参数即只 shift 默认为 shift 1。 typeset:用于显示或设置变量,是 declare 的同义词 unset:用于取消变量的定义 - 表明选项结束 -f 删除只读变量, 但不能取消从shell环境中删除指定的变量和函数。 如PATH,
24、PS1,PS2,PPID,UID,EUID 等的设置 2.2 引号引号 引用的必要性: 变量和替换操作, 在脚本中执行变量替换时最容易犯的一个错误就是引用错误。 双引号:使用双引号可引用除字符 $ 、 、 外的任意字符或字符串。 单引号: 与双引号类似, 不同的是 shell 会忽略任何引用值, 即如果屏蔽了其特殊含义,会将引号里的所有字符,包括引号都作为一个字符串。 反引号:设置系统命令的输出到变量。shell 将反引号中的内容作为一个系统命令,并执行其内容。 反斜杠: 如果一个字符有特殊含义, 反斜杠防止 shell 误解其含义, 即屏蔽其特殊含义。下述字符包含有特殊意义:& * + $
25、“ | ? 2.3 运算符运算符 运算符是对计算机发的指令。运算对象包括:数字、字符(字面值) ;变量;表达式。 表达式:运算符和运算对象的组合体。 运算符类型 按位运算符:(反) (右移) &(与) |(或) (异或)以$ 的表示形式告诉 shell 对方括号中的表达式求值,如 :-$ echo $2+8 逻辑运算符:&(逻辑与) |(逻辑或) = != 赋值运算符:= += -+ *= /= %= &= = |= = 使用 let var1=var2+var3 来表示 var1 等于 var2 和 var3 之和而不是直接var1=var2+var3,因为不用 let 的话表示 var1
26、的值就为 var2+var3 这个字符串 表达式替换 $ 和 $( ):习惯使用 $ ,所有 shell 的求值都是用整数完成 $ base#n 可以接受不同基数的数字,n 表示基数即进制数从 2 到 36 的任何基数。如 echo $ 10#2+1 表示 2 进制的 10+1,则结果为 3 deewenic SHELL 编程学习笔记 2011.2.4 10 Chapter 3:shell 输入和输出输入和输出 3.1 echo 命令命令 echo:可以显示文本行或变量,或者把字符串输入到文件 echo option string -e:解析转义字符 -n:回车不换行,linux 系统默认回车
27、换行 转义符(c,f,t,n) 3.2 read 命令命令 read:可以从键盘或文件的某一行文本中读入信息,并将其赋给一个变量 read variable1 variable 如果只指定了一个变量,那么 read 将会把所有的输入赋给该变量,直至遇到第一个文件结束符或回车; 如果给出了多个变量, 它们按顺序分别被赋予不同的变量。 Shell将用空格作为变量之间的分隔符。 3.3 cat 命令命令 cat:一个简单而通用的命令,可以用来显示文件内容、创建文件,还可以用它来显示控制字符 cat options filename1 filename2 -v:显示控制字符 使用 cat 命令时要注意
28、,它不会在文件分页处停下来;它会一下显示完整个文件。如果希望每次显示一页, 可以使用 more 命令或把 cat 命令的输出通过管道传递到另外一个具有分页功能的命令(more,less)中。 3.4 管道管道 可以通过管道把一个命令的输出传递给另一个命令作为输入,管道用竖杠(|)表示。 格式:命令 1 | 命令 2 3.5 tee 命令命令 tee 命令把输出的一个副本输送到标准输出中,另一个副本拷贝到相应的文件中。 tee -a filename -a:若已存在 filename 文件,则追加内容。不带-a 参数则覆盖原有内容。 在看到输出的同时,也将其存入一个文件 一般用于管道之后 dee
29、wenic SHELL 编程学习笔记 2011.2.4 11 3.6 标准输入、输出和错误标准输入、输出和错误 在 shell 中执行命令时,每个进程都和三个打开的文件相联系,并使用文件描述符来引用这些文件。由于文件描述符不容以记忆,shell 同时也给除了相应的文件名。 文件 文件描述符 输入文件标准输入 0(缺省是键盘,也可以是文件或其他命令的输出) 输出文件标准输出 1(缺省是屏幕,也可以是文件) 错误输出文件标准错误 2(缺省是屏幕,也可以是文件) 系统中实际上有 12 个文件描述符,可以任意使用文件描述符 3 到 9. 3.7 文件重定向文件重定向 改变程序的输入来源和输出地点 co
30、mmand filename 把标准输出重定向到一个新文件中 command filename 把标准输出重定向到一个文件中(追加) command 1 filename 把标准输出重定向到一个文件中 command filename 2 &1 把标准输出和标准错误一起重定向到一个文件中 command 2 filename 把标准错误重定向到一个文件中 command 2 filename 把标准输出重定向到一个文件中(追加) command filename 2 &1 把标准输出和标准错误一起重定向到一个文件中(追加) command filename2 command 命令以 filen
31、ame 文件作为标准输入,以filename2 文件作为标准输出 command filename command 命令以 filename 文件作为标准输入 command delimiter 从标准输入中读入,直至遇到 delimiter 分界符 command &m 把标准输出重定向到文件描述符 m 中 command /dev/null来忽略显示错误信息提示。 3.8 结合使用标准输出和标准错误结合使用标准输出和标准错误 例: rootlocalhost:-# cat account_new.txt account_old.txt 1accounts.out 2accounts.err
32、 deewenic SHELL 编程学习笔记 2011.2.4 12 rootlocalhost:-# cat accounts.out janny annie john rootlocalhost:-# cat accounts.err cat:account_old.txt:No such file or directory 3.9 合并标准输出和标准错误合并标准输出和标准错误 合并标准输出和标准错误的时候,切记 shell 是从左至右分析相应的命令 grep “standard” standard.txtgrep.out 2&1 不管找没找到或者有错误信息都输出到grep.out 3.1
33、0 exec 命令命令 exec 可以用来替代当前 shell。换句话说,即并没有启动子 shell,使用这一命令时任何现有环境都将会被清除,并重新启动一个 shell。 exec command 其中的 command 通常是一个 shell 脚本 对文件描述符进行操作的时候(也只有在这时) ,它不会覆盖当前的 shell 3.11 文件描述符文件描述符 3 到 9 的文件描述符可供使用 exec 与文件描述符的结合 #!/bin/bash #file_desc exec 3&0 0name.txt # 打开文件描述符 3 read line1 read line2 exec 0&2 fi
34、# 结束 if 示例脚本 ifelif: #!/bin/bash #ifelif echo -n “Enter your name:” read NAME if -z $NAME | “$NAME” = “” ; then echo “You did not enter a name.” elif “$NAME” = “root” ; then echo “Hello root.” elif “$NAME” = “chinaitlab” ; then echo “Hello chinaitlab” else echo “You are not root or chinaitlab, but h
35、i, $NAME.” deewenic SHELL 编程学习笔记 2011.2.4 14 fi 4.2 case 语句语句 语句格式: case value in mode1) #每一模式必须以右括号结束 command1 ; #执行至; mode2) command2 ; esac PS:case 取值后面必须为单词 in,每一模式必须以右括号结束。取值可以为变量或常熟。匹配发现取值 为某一模式后,其间所有命令开始执行至;。模式匹配符*表示任意字符,?表示任意单字符,.表示类或范围中任意字符。 示例脚本 caseselect: #!/bin/bash #case select echo -n
36、 Enter a number from 1 to 3: read ANS case $ANS in 1) echo You select 1. ; 2) echo You select 2. ; 3) echo You select 3. ; y|Y) echo You select $ANS ; *) echo basename $0:This is not between 1 and 3 &2 exit; ; esac deewenic SHELL 编程学习笔记 2011.2.4 15 4.3 for 语句语句 语句格式: for valuename in list do command
37、1 command2 done 示例脚本 forlist1: #!/bin/bash #forlist1 for loop in 1 2 3 4 5 #列表中值依次赋给 loop do echo -n $loop #打印 loop 的值 done echo 示例脚本 forlist2: #!/bin/bash #forlist2 for loop in Orange red blue grey #此处由引号括上因此列表中只有一个值 do echo $loop done 示例脚本 forlist2_1: #!/bin/bash #forlist2 for loop in cat myfile #
38、将命令结果作为列表值 do echo $loop done 4.4 until 语句语句 语句格式: until condition do command1 command2 . done PS:条件可为任意测试条件,测试发生在循环末尾,因此循环至少执行一次。 deewenic SHELL 编程学习笔记 2011.2.4 16 4.5 while 语句语句 语句格式: while command do command1 command2 . done PS:在 while 和 do 之间虽然通常只使用一个命令,但可以放几个命令,命令通常用作测试条件。 示例脚本 whileread: #!/bi
39、n/bash #whileread echo “Press +D to quit input.” while echo -n “Input your favourite film:”; read FILM do echo “Yeah, $FILM is a good film!” done 示例脚本 whilereadline: #!/bin/bash #whileread while read LINE do echo $LINE done myfile #从文件读入数据,注意是在 done 语句行后读入而不是在 while 语句行读入 4.6 break 和和 continue 控制控制
40、break n 退出循环 如果是在一个嵌入循环里,可以指定 n 来跳出的循环个数。 continue 跳过循环步 PS:continue 命令类似于 break 命令,只有一点重要差别,它不会跳出循环,只是跳过这个循环步 示例脚本 breakout: #!/bin/bash #breakout while : #冒号:表示永远为真 do echo -n Enter any number 1.5: read ANS deewenic SHELL 编程学习笔记 2011.2.4 17 case $ANS in 1|2|3|4|5) echo You enter a number between 1
41、 and 5. ; *) echo Wrong number, bye. break #输错则跳出循环 ; esac done 示例脚本 breakout_1: #!/bin/bash #breakout while : do echo -n Enter any number 1.5: read ANS case $ANS in 1|2|3|4|5) echo You enter a number between 1 and 5. ; *) echo Wrong number, continue(y/n)?: read IS_CONTINUE case $IS_CONTINUE in y|ye
42、s|Y|Yes|YES) continue ; *) break ; esac esac done Chapter 5:文本过滤:文本过滤 5.1 正则表达式正则表达式 一种用来描述文本模式的特殊语法,又普通字符(例如字符 a 到 z)以及特殊字符(称为元字符,如/、*、?等)组成。文本过滤工具在某种模式下都支持正则表达式。 基本元字符集及其含义 deewenic SHELL 编程学习笔记 2011.2.4 18 字符 含义 只匹配行首 $ 只匹配行尾 * 匹配 0 个或多个此单字符 只匹配内字符。可以是一个单字符,也可以是字符序列。可以使用-表示内字符序列范围,如用1-5代替12345。 只
43、用来屏蔽一个元字符的特殊含义。 . 只匹配任意单字符。 patternn 只用来匹配前面 pattern 出现次数。n 为次数。 patternn, 含义同上,但次数最少为 n。 patternn,m 含义同上,但 pattern 出现次数在 n 与 m 之间。 行尾以$匹配字符串或字符 $与正相反,它在行尾匹配字符串或字符,$符号放在匹配单词后。 trouble$-匹配以单词 trouble 结尾的所有字符 $-匹配空行 .$-匹配包含一个字符的行 用*匹配单字符或其重复序列 匹配任意字符零次或多次重复表达 10133*1 匹配 101331 10133921 10133As1 用屏蔽一个特
44、殊字符 特殊字符 “,|,*,+等 *.pas 正则表达式中匹配以*.pas 结尾的所有字符或文件 用匹配一个范围或集合 逗号将括弧内要匹配的不同字符串分开 用“-”表示一个字符串范围,表明字符串范围从“-”左边字符开始,到“-”右边字符结束。 0123456789或0-9:假定要匹配任意一个数字 a-z:任意小写字母 A-Za-z:任意大、小写字母 A-Za-z0-9:匹配任意字母或数字 S,s:匹配大、小写 s 用匹配模式结果出现的次数 A2B:A 出现 2 次,AAB A4,B:A 最少出现 4 次,AAAAB,AAAAAB. A2,4B:出现次数范围 2-4 次,AAB,AAAB,AA
45、AAB deewenic SHELL 编程学习笔记 2011.2.4 19 0-93.0-93.0-93.0-93:匹配 IP 地址 5.2 find 命令命令 查找具有某些特征文件的命令, 可遍历当前目录甚至于整个文件系统来查找某些文件或目录 遍历大的文件系统时,一般放在后台执行 find 命令的一般形式: find pathname -options -print -exec -ok pathname find 命令所查找的目录路径。例如用.来表示当前目录,用/来表示系统根目录 -print find 命令将匹配的文件输出到标准输出 -exec find 命令对匹配的文件执行该参数所给出的
46、 shell 命令,相应命令的形式为 command ;,注意和;之间的空格 -ok 和-exec 的作用相同, 只不过以一种更为安全的模式来执行该参数所给出的shell 命令,在执行每一个命令之前,都会给出提示,让用户来确定是否执行 -name 按照文件名查找文件 -perm 按照文件权限来查找文件 -user 按照文件属主来查找文件 -group 按照文件所属的组来查找文件 -mtime -n +n 按照文件的更改时间来查找文件,-n 表示文件更改时间距现在 n天以内,+n 表示文件更改时间距现在 n 天以前。find 命令还有-atime 和-ctime选项,但它们都和-mtime 选项
47、相似 -size nc查找文件长度为 n 块的文件,带有 c 时表示文件长度以字节计 -nogroup 查找无有效所属组的文件, 即该文件所属的组在/etc/groups 中不存在 -nouser 查找无有效属主的文件,即该文件的属主在/etc/passwd 中不存在 -newer file1 !file2 查找更改时间比文件 file1 新但比文件 file2 旧的文件 -type 查找某一类型的文件,诸如: b 块设备目录 d 目录 c 字符设备文件 p 管道文件 l 符号链接文件 f 普通文件 man find find 命令举例 使用 name 选项 可以使用某种文件名模式来匹配文件,
48、 记住要用引号将文件名模式引起来 find -name “*.txt” print find ./ -name “*.txt” print find ./ -name “A-Z*” print find /etc -name “host*” print 使用 perm 选项 find . -perm 755 print deewenic SHELL 编程学习笔记 2011.2.4 20 使用 user 和 nouser 选项 find pwd -user root print find pwd -nouser print 使用 group 和 nogroup 选项 find ./ -group
49、 itlab print find ./ -nogroup print 按照更改时间查找文件 find /var -mtime -5 print find /var/ -mtime +3 print 查找比某个文件新或旧的文件 find pwd -newer “myfile” ! -newer “myfile123” print 使用 type 选项 find /etc -type d print find /etc -type l print 使用 size 选项 find . -size +1000000c -print #c 表示字符即字节数,+表示大于 find . -size +10
50、 -print #大于 10 块 使用 depth 选项 使用 find 命令查找时,可能希望先匹配所有的文件,再在子目录中查找 find / -name “CON.FILE” -depth print 用 exec 或 ok 来执行 shell 命令 find . -type f -exec ls -l ; find . -name “*.log” -mtime +5 -ok rm ; xargs 在使用 find 命令的-exec 选项处理匹配到的文件时,find 命令将所有匹配到的文件一起传递给 exec。不过有些系统对能够传递给 exec 的命令长度有限制,这样在 find 命令运行几
51、分钟后,就会出现溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。这就是 xargs 命令的用处所在,特别是与 find 命令一起使用。exec 会发起多个进程,而 xarges 不会多个,只有一个 find ./ -perm -7 -print | xargs chmod o-w find ./ -type f -print | xargs file 5.3 grep 命令命令 grep 是 UNIX 和 LINUX 中使用最广泛的命令之一,用于对文本文件进行模式查找 grep 三种变形 grep:标准 grep 命令 egrep:扩展 grep,支持基本及扩展的正则表达式 fgrep
52、:快速 grep grep 一般格式为: grep 选项 基本正则表达式文件 字符串参数最好采用双括号,一是以防被误解为 shell 命令,而是可以用来查找多个单词组成的字符串 deewenic SHELL 编程学习笔记 2011.2.4 21 grep 命令选项: -c 只输出匹配行的计数 -i 不区分大小写(只适用于单字符) -h 查询多文件时不显示文件名 -H 显示文件名 -l 查询多文件时只输出包含匹配字符的文件名 -n 显示匹配行及行号 -s 不显示不存在或无匹配文本的错误信息 -v 显示不包含文本的所有行 grep 命令举例 grep “jenny” *.txt grep “sor
53、t it” * grep -c “2004” myfile grep -n “2004” myfile grep -i “Jul” myfile grep -v “2004:22” myfile grep “2004:22:50-9” myfile grep “210” myfile grep “H*P” myfile grep “5-86-90-3” myfile grep “42” myfile grep “42,” myfile grep “42,4” myfile grep “$” myfile grep “?” myfile grep “d” lsout.txt grep “d” l
54、sout.txt grep 命令类名 类 等价的正则表达式 :upper: A-Z :alnum: 0-9a-zA-Z :lower: a-z :space: 空格或 tab 键 :digit: 0-9 :alpha: a-zA-Z grep “5:digit:digit:” myfile 5.4 awk 命令命令 可从文件或字符串中基于指定规则浏览和抽取信息。是一种自解释的编程语言。 awk 三种调用方式 命令行方式: awk -F filed-spearator command input-files #默认空格是分割符 awk 脚本: 所有 awk 命令插入一个文件,并使 awk 程序可
55、执行,然后用 awk 命令解释器作为脚本的首行,以便通过键入脚本名称来调用它。 awk 命令插入一个单独文件: awk -f awk-script-file input-files awk 脚本由各种操作和模式组成 deewenic SHELL 编程学习笔记 2011.2.4 22 模式和动作 模式部分决定动作语句何时触发及触发事件。 (BEGIN,END) 动作对数据进行处理,放在大括号内指明。 (print) 分割符、域和记录 awk 执行时, 其浏览域标记为$1,$2.$n。 这种方法称为域标识。 $0 为所有域。 注意执行时不要混淆符号$和 shell 提示符$,它们是不同的。 awk
56、 命令举例 awk print $0 score.txt | tee score.out awk print $1“t”$4 score.txt awk BEGIN print “Name Mathsn-”print $1“t”$4 END print “end-of-report” score.txt | more 5.5 sed 命令命令 5.6 合并与分割合并与分割 sort uniq join cut paste split Chapter 6:shell 函数函数 6.1 函数定义函数定义 shell 允许将一组命令集或语句形成一个可用块,这些块称为 shell 函数 定义函数的格式
57、为: 函数名 () 命令 1 . function 函数名 () . 函数可以放在同一个文件中作为一段代码,也可以放在只包含函数的单独文件中。 #!/bin/bash #hellofun deewenic SHELL 编程学习笔记 2011.2.4 23 function hello () echo “Hello, today is date” return 1 函数调用 #!/bin/bash #hellofun function hello () echo Hello, today is date return 0 echo Now going to the function hellof
58、un. hello echo Back from the function 6.2 参数传递参数传递 向函数传递参数就像在脚本中使用位置变量$1,$2.$9。 #!/bin/bash func function hello () echo “Hello, $1 today is date” echo “Now going to the function hello” hello chinaitlab echo “Back from the function” 6.3 函数文件函数文件 示例脚本 func: #!/bin/bash #func #Source function . hellofu
59、n #注意.后面有空格 echo “Now going to the function hello” hello echo “back from the function” 引用函数文件 hellofun: #!/bin/bash hellofun function hello () deewenic SHELL 编程学习笔记 2011.2.4 24 echo “Hello, today is date” return 0 6.4 检查载入函数和删除函数检查载入函数和删除函数 set:查看载入函数 unset:删除函数 例: #!/bin/bash #func #Source function
60、 . hellofun set #查看函数 unset hello #删除函数,因此下面的函数调用会报错 echo “Now going to the function hello” hello echo “back from the function” 6.6 函数返回状态值函数返回状态值 一般返回 0 为正确执行,返回 1 为执行有错,返回值不能作为变量 在函数调用后可以用 echo $?查看返回值 Chapter 7:脚本参数传递:脚本参数传递 7.1 shift 命令命令 每次将参数位置向左偏移 n 位 #!/bin/bash #opt2 usage() echo “usage:bas
61、ename $0 filenames” totalline=0if $# -lt 2 ; then #注意 if 后面、 后面和 前面均有空格,以下相同。 usage #$#为参数个数 fi while $0 -ne 0 do deewenic SHELL 编程学习笔记 2011.2.4 25 line=cat $1|wc -l #查看第一个参数指定的文件并找出行数赋给$line echo $1:$line #打印出该文件名及其行数 totalline=$ $totalline+$line shift #参数位置左移 1 位 done echo - echo total:$totalline
62、7.2 getopts 获得多个命令行参数 #!/bin/bash ALL=false HELP=false FILE=false VERBOS=false while getopts ahfvc: OPTION #如果 c 后面有:,则说明:前面的参数必须是带有值的参数 do case $OPTION in a) ALL=true echo “ALL IS $ALL” ; h) HELP=true echo “HELP is $HELP” ; f) FILE=true echo “FILE is $FILE” ; v) VERBOSE=true echo “VERBOSE is $VERBO
63、SE” ; c) c=$OPTARG #将 c 后面参数的值赋给 c echo “c value is $c” ; ?) #?是通配,包括不在参数列的值以及不符合参数规则的值,如 c 未给值 echo “basename $0 -a h f v -c value file” ; esac done deewenic SHELL 编程学习笔记 2011.2.4 26 通过 shift 以及 getopts 可以使用多于 9 个的参数 Part 2.高级编程高级编程 Chapter 1:深入介绍:深入介绍 1.1 深入讨论深入讨论 awk 条件操作符 操作符 描述 = 大于等于 = 小于等于 =
64、等于 != 不等于 匹配正则表达式 ! 不匹配正则表达式 逻辑操作符 操作符 描述 & and | or ! not 示例脚本 awkif.sh #!/bin/bash #awkif echo “210-219 网段的访问量是:awk if ($1/210-9/) print $0 www.log|wc -l” echo “非 210-219 网段的访问量是:awk if ($1!/210-9/) print $0 www.log|wc -l” echo “2004 年 07 月 07 日的访问量是:awk if ($4/07/Jul/2004/) print $0 www.log|wc -l
65、” echo “2004 年 07 月 07 日的访问量是:awk if ($4/07/Jul/2004/) print $0 www.log|awk if ($7=”/htm/free_call.php”) print $0 |wc -l” awk 内置变量 ARGC 命令行参数个数 ARGV 命令行参数排列 ENVIRON 支持队列中系统环境变量的使用 FILENAME awk 浏览的文件名 deewenic SHELL 编程学习笔记 2011.2.4 27 FNR 浏览文件的记录数 FS 设置输入分隔符,等价于命令行-F 选项 NF 浏览记录的域个数 NR 已读的记录数 OFS 输出域分
66、隔符 ORS 输出记录分隔符 RS 控制记录分隔符 命令示例: 比如有文件 grade.txt 如下: 85#senior 87#junior 75#senior 75#junior 86#junior 执行:awk -F # print NF,NR,$0 grade.txt # 以 #作为分隔符并打印出域个数、已读记录数和整条记录 结果如下: 2 1 85#senior #域个数为 2,已读记录为 1,整条记录,以下同理 2 2 87#junior 2 3 75#senior 2 4 75#junior 2 5 86#junior 执行:awk -F # print NF,NR,ENVIRO
67、NUSER,$0 grade.txt 结果如下: 2 1 deewenic 85#senior 2 2 deewenic 87#junior 2 3 deewenic 75#senior 2 4 deewenic 75#junior 2 5 deewenic 86#junior 执行:awk -F # print ARGC,ARGV0,ARGV1 grade.txt2 awk grade.txt 2 awk grade.txt #命令行参数个数为 2,第一个参数为 awk,第二个为 grade.txt 2 awk grade.txt 2 awk grade.txt 2 awk grade.tx
68、t 2 awk grade.txt 字符串函数 gsub(r,s) 在整个$0 中用 s 替代 r gsub(r,s,t) 在整个 t 中用 s 替代 r index(s,t) 返回 s 中字符串 t 的第一位置 length(s) 返回 s 长度 match(s,r) 测试 s 是否包含匹配 r 的字符串 deewenic SHELL 编程学习笔记 2011.2.4 28 split(s,a,fs) 用 fs 将 s 分成序列 a sprint(fmt,exp) 返回经 fmt 格式化后的 exp sub(r,s) 用$0 中最左边最长的字串代替 s substr(s,p) 返回字符串 s
69、中从 p 开始的部分 substr(s,p,n) 返回字符串 s 中从 p 开始长度为 n 的部分后缀 命令示例: 执行:awk -F # if (gsub(#,|) print $0 grade.txt 结果如下: 85|senior 87|junior 75|senior 75|junior 86|junior 执行:awk -F # if (gsub(s,S,$2) print $2 grade.txt #用 S 替 域 换 1 中的 s,并打印出来 结果如下: Senior Senior 执行:awk -F # print (index($2,e) grade.txt 结果如下: 2
70、#字母 e 在域 2 中在第二位, 在字符串 即 senior 中第二的位置 0 2 0 0 转义字符 b 退格键 t tab 键 f 走纸换页 ddd 八进制值 n 新行 c 任意其他特殊字符,例如为反斜线符号 r 回车键 命令示例: 执行:awk -F # print (index($2,e),n,$2 grade.txt 结果如下: 2 senior 0 junior 2 deewenic SHELL 编程学习笔记 2011.2.4 29 senior 0 junior 0 junior printf 修饰符 %c ASCII 字符 %d 整数 %f 浮点数,例如(123.44) %e
71、浮点数,科学计数法 %g awk 决定使用哪种浮点数转换 e 或者 f %o 八进制数 %s 字符串 %x 十六进制数 命令示例: 执行:awk -F # printf %ct%dn,$1,$1 grade.txt 结果如下: U 85 W 87 K 75 K 75 V 86 awk 数组 awk BEGIN print split(as#qw#1234,array2,#) #用#进行分隔得到数组 array2 结果为: 3 awk BEGIN split(as#qw#1234,array2,#); print array21 #按#分隔为数组并打印下标为 1 的元素 结果为: as awk
72、BEGIN split(as#qw#1234,array2,#);print array21,t,array22,t,array23 结果为: as qw 1234 示例脚本 awk_array.sh #!/bin/awk -f #awk_array.sh BEGIN FS=# score0-60=0 score60-70=0 score70-80=0 score80-90=0 deewenic SHELL 编程学习笔记 2011.2.4 30 score90-100=0 studentjunior=0 studentsenior=0 if ($160) score0-60+ if ($1=6
73、0) score60-70+ if ($1=70) score70-80+ if ($1=80) score80-90+ if ($1=90) score90-100+ for (senior_junior in student) if ($2=senior_junior) studentsenior_junior+ END for (number in score) print The score, number, has, scorenumber, students for (senior_junior in student) print The class has, studentsen
74、ior_junior, senior_junior, students 执行./awk_array.sh grade.tx,结果如下: The score 0-60 has 2 students The score 60-70 has 3 students The score 70-80 has 1 students The score 80-90 has 1 students The score 90-100 has 3 students The class has 5 senior students The class has 5 junior students 1.2 深入讨论标准输入(
75、深入讨论标准输入() 示例脚本 menu.sh 如下 #!/bin/bash deewenic SHELL 编程学习笔记 2011.2.4 31 loopvar=2 # # main menu # # main_menu() echo echo dis_mainmenu=CREATE MINISITE IN GGYYLAB curdate=date +%Y-%m-%d %T cat $todaylog # # command block sleep 4 # #输出日志到日志文件 log_time_format=date +%Y-%m-%d %T echo $log_time_format 命令
76、结束 $todaylog 示例脚本 kill_process.sh 创建以进程号为标识的日志文件: #!/bin/bash #kill_process.sh #获取当前进程号 current_PID=$ #获得特定进程的进程号并重定向到一个临时文件中 ps -aux|grep /usr/sbin|grep -v grep|awk print $2./$current_PID.txt #命令 始 块开 #for pid in cat ./$current_PID.txt #do # #echo Kill -9 $pid #kill -9 #pid # #done deewenic SHELL 编
77、程学习笔记 2011.2.4 33 #命令块结束 #删除临时文件 #rm -f ./$current_PID.txt 2.2 信号信号 信号就是系统向脚本或命令发出的消息,告知它们某个事件的发生 kill -l 例出所有的信号 kill 发送信号给进程 信号 信号名 含义 1 SIGHUP 挂起或父进程被杀死 2 SIGINT 来自键盘的终端信号,通常是 3 SIGQUIT 从键盘退出 9 SIGKILL 无条件终止 11 SIGSEGV 段(内存)冲突 15 SIGTERM 软件终止(缺省杀死进程) 信号 0 为“退出 shell”信号。为了发出信号,只要从命令行键入 exit,或在一个进程
78、命令行中使用即可。 2.3 trap 捕捉信号捕捉信号 信号可以被应用程序或脚本捕获,并依据该信号(1、2、3 和 15)采取相应的行动。一些信号不能被捕获。例如,如果一个命令收到了信号 9,就无法再捕捉其他信号。 捕捉到一个信号后,它可能会采取下面三种操作之一: 1. 不采取任何行 ,由系 行 理。 动 统来进 处 2. 捕获该信号,但忽略它。 3. 捕获该信号,并采取相应的行动。 trap 可以使你在脚本中捕获信号。 命令形式为: trap name signal(s) 其中,name 是捕捉到信号以后所采用的一系列操作。实际中,name 一般是一个专门用来处理所捕捉的信号的函数。name
79、 需要用双引号(”)引起来。signal 就是待捕捉的信号。 最常见的行动包括: 1. 清除临时文件。 2. 忽略该信号。 (trap “” 2 3) 3. 询问用户是否终止该脚本的运行。 示例脚本 trap1.sh: #!/bin/bash #trap1.sh trap exitprocess 2LOOP=0 function exitprocess() deewenic SHELL 编程学习笔记 2011.2.4 34 echo echo You just hit , at number $LOOP echo I will now exit. exit 1 while : do LOOP=
80、$LOOP+1 echo $LOOP done 执行./trap1.sh 后,会显示 LOOP 值,用或者在另一终端结束运行该脚本的进 程号即发送信号 2:kill -2 2373,显示如下: You just hit , at number 7328 I will now exit. 示例脚本 trap2.sh: #!/bin/bash #trap2.sh LOOP=0 trap exitprocess 2 HOLD1=/tmp/hold1.$ HOLD2=/tmp/hold2.$ function exitprocess() echo -e nRecived Interrupt. echo
81、 -n Do you really wish to exit?(Y/N) read ANS case $ANS in Y|y) rm_tmp_file ; N|n) ; *) exitprocess ; esac function rm_tmp_file() echo detected . Now cleaning up .wait. rm /tmp/*.$ 2/dev/null exit 1 deewenic SHELL 编程学习笔记 2011.2.4 35 while : do LOOP=$LOOP+1 echo $LOOP df$HOLD1 ps -xa$HOLD2 sleep 1 do
82、ne 执行该脚本后,发送信号 2 或者会提示是否退出。 2.4 eval 命令命令 eval 命令将会首先扫描命令行进行所有的置换,然后在执行该命令。该命令适用于那些一次扫描无法实现其功能的变量。 MYFILE=”cat myfile”; eval $MYFILE 2.5 logger 命令命令 logger 命令向/var/log/message 文件发送消息 logger 命令的一般形式为: looger -p -i message -p:为优先级,这里只涉及到提示用户注意的优先级,这也是缺省值 -i:在每个消息中记录发送消息的进程号 Chapter 3:运行级别脚本介绍:运行级别脚本介绍
83、 3.1 运行级别运行级别 运行级别目录:/etc/rcN.d N 表示 06 当前运行级别,用命令 :$ runlevel 查看 运行级别目录文件格式:SXXscript,KXXscript script 表示脚本的名字 S 表示在该运行级别下面该脚本运行的服务是被启动的,K 反之,表示是停止的 XX 为数字表示启动顺序,数值越小越先启动,且必须前面的服务启动后后面的服务才可启动 3.2 inittab 运行级别控制文件:/etc/inittab id:5:initdefault: #5 为当前设置的默认运行级别 修改 inittab 文件 deewenic SHELL 编程学习笔记 201
84、1.2.4 36 3.3 启动应用程序启动应用程序 启动脚本分析(start|stop|restart) cat /etc/init.d/crond 启动脚本 service scriptname start|stop|restart|status. #service 命令启动脚本 scriptname 如: service crond start 可以把自己写的运行脚本放在/etc/init.d 下面,再在相应运行级别下面创建该脚本的超链接(S 打头便是启动) ,这样在相关运行级别启动时,脚本或服务便能启动 Chapter 4:几个脚本例子:几个脚本例子 4.1 kill_process.s
85、h #!/bin/bash #kill_process.sh #获取当前进程号 current_PID=$ #获得特定进程的进程号并重定向到一个临时文件中 ps -aux|grep /usr/sbin/httpd|grep -v grep|awk print $2./$current_PID.txt #grep -v 是过滤掉相应内容 #命令块开始 for pid in cat ./$current_PID.txt do echo Kill -9 $pid kill -9 $pid done #命令块结束 #删除临时文件 rm -f ./$current_PID.txt #该脚本的作用是杀死所
86、有 httpd(或可替换为其它类型)进程,释放资源 4.2 cpdir.sh #!/bin/bash #cpdir.sh #此脚本用于将源目录下的子目录全部复制到目的目录中,不复制源目录中的文件,确保目的目录中的子目录是空目录。 deewenic SHELL 编程学习笔记 2011.2.4 37 #脚本用法函数 usage() echo cpdir.sh 源目录 目的目录 #判断是否为两个参数,否则提示脚本用法 if $# -ne 2 then usage exit 0 fi srcdir=$1 desdir=$2 #判断源目录$srcdir是否为目录,否则提示错误信息和用法 if ! -d
87、$srcdir then usage echo 错误:源目录$srcdir不是目录 exit fi #判断目的目录$desdir是否为目录,否则提示错误信息和用法 if ! -d $desdir then usage echo 错误:目的目录$desdir不是目录 exit fi processid=$ #查找源目录下所有的子目录,输出并保存到/tmp/srcdir_进程号.txt 文件中 echo 源目录下$srcdir所有的子目录 echo - #查找源目录下所有文件类型为 d 即目录类型的文件并通过 tee 打印到屏幕同时输出到文件中 find $srcdir/* -type d|/us
88、r/bin/tee /tmp/srcdir_tmp_$processid.txt #只要以源目录开头的转换成目的目录 deewenic SHELL 编程学习笔记 2011.2.4 38 sed s/$srcdir/$desdir/g /tmp/srcdir_tmp_$processid.txt /tmp/srcdir_$processid.txt #在目的目录下建立空目录 rm -rf $desdir/* for subdir in cat /tmp/srcdir_$processid.txt do mkdir $subdir done echo echo 目标目录下$desdir所有的子目录
89、 echo - find $desdir/* -type d|/usr/bin/tee /tmp/desdir_$processid.txt #比较在目的目录下建立空子目录后的差异 echo echo 比较目标目录和源目录的差异 echo - diff /tmp/desdir_$processid.txt /tmp/srcdir_$processid.txt rm -f /tmp/srcdir_$processid.txt rm -f /tmp/desdir_$processid.txt rm -f /tmp/srcdir_tmp_$processid.txt #该脚本的作用是可以值拷贝目录树而不会拷贝目录下的文件