分享

shell编程-高级

 看风景D人 2014-09-10
第一章  深入讨论

内容:
深入讨论awk ;
深入讨论 标准输入 <<  ;


第二章  shell 工具

内容:
日志文件;
信号;
trap捕捉信号;
eval ;
logger


第三章  运行级别脚本介绍

内容:
运行级别;
inittab
启动应用程序


第四章  几个脚本例子

内容:
kill_processes.sh
cpdir.sh
menu.sh


1.1 深入讨论 awk
① 记录和域, 模式和动作, 正则表达式和元字符
② 条件操作运算符
③ awk 内置变量
④ NF, NR 和 FILENAME
⑤ awk操作符
⑥ 内置的字符串函数
(7) 字符串屏蔽序列
(8) awk输出函数printf
(9) awk数组

1.1 深入讨论 awk
① 条件操作符 (awkif.sh)
<
>=
<=
==
!=
~                    匹配正则表达式
!~                   不匹配正则表达式

② 逻辑操作符
&&                           and
||                                 or
!                                  not

示例:
#!/bin/bash
#awkif
echo  "210-219网段的访问量是: `awk  '{if ($1~/^21[0-9]/)  print  $0}'  www.log | wc  -l`"
echo  "非210-219网段的访问量是: `awk  '{if ($1!~/^21[0-9]/)  print  $0}'  www.log | wc  -l`"
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 `"

//注: ~ 表示匹配 ;    print  $0 表示打印出整条记录
\[   左中括号是元字符, 因此需以反斜杠进行转意;
\/   斜杠是元字符, 因此也需用反斜杠进行转意;

1.1 深入讨论 awk
① awk内置变量 (awkvar.sh)
ARGC                   命令行参数个数
ARGV                   命令行参数排列
ENVIRON             支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                        浏览文件的记录数
FS                           设置输入域分隔符, 等价于命令行-F选项
NF                           浏览记录的域个数
NR                           已读的记录数
OFS                         输出域分隔符
ORS                         输出记录分隔符
RS                            控制记录分隔符

示例:
awk   -F  '#'   '{print   NF,NR,$0}'    grade.txt

awk   -F  '#'   '{print   NF,NR,ENVIRON["USER"],$0,FILENAME,ARGC,ARGV[0]}'    grade.txt  
                                                                                        //环境变量是以数组的方式存放的

1.1 深入讨论 awk
① 字符串函数  (内置函数)
gsub(r,s)                  在整个$0中用s替代r
gsub(r,s,t)                在整个t中用s替代r      (t可以是一个域/一条记录/一个字符串)
index(t,s)                 返回s在字符串t中的第一个位置
length(s)                  返回s长度
match(s,r)                测试s是否包含匹配r的字符串
split(s,a,fs)               用fs上将s分成序列a    (fs为域分隔符,序列a 即数组a)
sprint(fmt,exp)         返回经fmt格式化后的exp
sub(r,s)                      用$0中最左边最长的子串代替s
substr(s,p)                 返回字符串s中从p开始的之后部分
substr(s,p,n)              返回字符串s中从p开始长度为n的之后部分

示例:
awk   -F   '#'    '{if  (gsub("#","||"))  print  $0}'    grade.txt

awk   -F   '#'    '{if  (gsub("s","S",$2))  print  $2}'    grade.txt

awk   -F   '#'    '{print  (index($2,"s"))}'    grade.txt


1.1 深入讨论 awk
① 转义字符
\b                  退格键
\t                    tab键
\f                    走纸换页
\ddd               八进制
\n                    新行  (换行)
\c                     任意其它特殊字符,例如\\为反斜线符号
\r                      回车键

示例:

awk   -F   '#'    '{print  (index($2,"s")),"\t",$2}'    grade.txt


1.1 深入讨论 awk
① printf修饰符
%c                          ASCII字符
%d                          整数
%f                           浮点数,例如(123.44)
%e                           浮点数,科学计数法
%f                            新行  (换行)
%g                           awk决定使用哪种浮点数转换e或者f
%o                           八进制
%s                            字符串
%x                            十六进制数

示例:
awk    -F   '#'   '{printf   "%c\n",$1}'    grade.txt

awk    -F   '#'   '{printf   "%c\t%d\n",$1,$1}'    grade.txt


1.1 深入讨论 awk
① awk 数组

② awk   'BEGIN  {print  split("as#qw#1234",array2,"#")}'               //3  表示数组有3个元素

③ 举例说明 (awk_array.sh)

示例:
awk   'BEGIN  {split("as#qw#1234",array2,"#"); print  array2[1]}'       //awk中的下标是从1开始的

awk   'BEGIN  {split("as#qw#1234",array2,"#"); print  array2[1],"\t",array2[2],"\t",array2[3]}'  


举例说明 (awk_array.sh)
#!/bin/awk   -f
#awk_array.sh
BEGIN{
FS="#"                                //一个内置变量, 它表示分隔符
score["0-60"]=0
score["60-70"]=0
score["70-80"]=0
score["80-90"]=0
score["90-100"]=0
student["junior"]=0
student["senior"]=0
}
{
{if ($1<60)
score["0-60"]++
}
{if ($1<70 && $1>=60)
score["60-70"]++
}
{if ($1<80 && $1>=70)
score["70-80"]++
}
{if ($1<90 && $1>=80)
score["80-90"]++
}
{if ($1<=100 && $1>=90)
score["90-100"]++
}
}
{
for (senior_junior in student)                      //依次读出student数组中的元素 赋值给变量senior_junior
{if ($2==senior_junior)
student[senior_junior]++
}
}
END{
{for (number in score)  print "The score", number, "has", score[number], "students"}
{for (senior_junior in student) print "The class has", student[senior_junior], senior_junior, "students"}
}

注:   ./awk_array.sh    grade.txt

man awk   查看一下


1.2 深入讨论 <<

示例:
#!/bin/bash
loop_var=2
#main menu
main_menu( )
{
echo                 //echo两个空行
echo
dis_mainmenu="CREAT  MINISITE  IN  CHINAITLAB.COM"
curdate=`date  "+%Y-%m-%d  %T"`
cat <<mayday                                        //进入标准输入部分
                              DATE : $curdate
                              ================================================
                                  $dis_mainmenu
           ================================================
                                      **      1)ADD  MINISITE  ACCOUNT                             ** 
**       2)ADD  DOMAIN   IN CHINAITLAB.COM        **
**       3)ADD  DATABASE  IN  MYSQL                        **
**       4)ADD  VIRTUAL   HOST  IN  APACHE            **
  **       5)BACKUP  MINISITE                                           **
                                     **       6)DELETE  MINISITE                                             **
  **       7)EXIT                                                                       **
                              ================================================
mayday
}

while [  $loop_var  -gt  0 ]
do
main_menu
echo    -n   " Please  choose  [1-7]:"              //-n 意思是不用回车换行
read  main_choice
  case  $main_choice   in 
7)
  exit
    ;;
*)
 clear
 continue
     ;;
esac
done

----------------------------------------------------------

第二章  shell 工具

内容:
日志文件;
信号;
trap捕捉信号;
eval ;
logger


2.1 日志文件
① 创建日志文件的重要性;
② 以时间为标识的日志文件;
③ 以进程号为标识的临时文件

示例:
#!/bin/bash
#datelog.sh
#当前的日期
current_date=`date   "+%Y%m%d"`     
                                //当前日期的格式,%Y 表示4位的年份 %m 2位的月份 %d当前日期
#今天的日志文件名
todaylog="log/${current_date}.log"
#如果日志文件不存在, 创建一个
if [  !   -f   $todaylog  ]
then
                      touch  $todaylog
fi
#输出日志到日志文件
log_time_format=`date   "+%Y-%m-%d  %T"`    // %T 表示 小时:分:秒都打印出来, 以冒号分割 
echo   "${log_time_format}   命令开始"  >>$todaylog
#
# command  blocks
sleep  4
#
#输出日志到日志文件
log_time_format=`date   "+%Y-%m-%d  %T"`
echo  "${log_time_format}  命令结束"  >>$todaylog


注: man  date   查看一下

示例2:
#!/bin/bash
#kill_process.sh
#取得当前进程号
current_PID=$$                      //$$ 一个特殊的变量, 表示当前进程号
#获得特定进程的进程号并重定向到一个临时文件中
ps  -aux | grep  "/usr/sbin/httpd" | grep  -v  "grep" | awk  '{print   $2}' > /tmp/${current_PID}.txt
                                               //grep  -v  "grep"  表示过滤掉grep
#命令块开始
for  pid  in  `cat  /tmp/${current_PID}.txt`
do
{
echo   "kill   -9   $pid"
kill   -9   $pid
}
done
#命令块结束
#删除临时文件
echo    "rm   -f   /tmp/${current_PID}.txt"
rm   -f   /tmp/${current_PID}.txt


2.2 信号
① 信号就是系统向脚本或命令发出的消息, 告知它们某个事件的发生;
②  kill  -l     //列出所有的信号
③ kill 发送信号给进程.

2.2 信号 (续)
1              SIGHUP              挂起或父进程被杀死  (使子进程挂起后杀死子进程, 
                                             或杀下父进程是子进程号的子进程)
2              SIGINT                来自键盘的中断信号, 通常是CTRL+C
3              SIGQUIT              从键盘退出
9              SIGKILL               无条件终止
11            SIGSEGV             段(内存)冲突
15            SIGTERM             软件终止(缺省杀进程)

注: 信号0为"退出shell"信号. 为了发出信号0, 只要从命令行键入exit, 
或在一个进程或命令行中使用<CTRL+D>即可. 

示例:
kill    -s   SIGKILL     7686
kill    -9     7686

2.3  trap 捕捉信号
① 信号可以被应用程序或脚本捕捉, 并依据该信号(1,2,3和15)采取相应的行动.
一些信号不能被捕捉. 例如, 如果一个命令收到了信号9, 就无法再捕捉其它信号.
(9 是由系统来直接进行处理的一个信号)
② 捕捉到一个信号后, 它可能会采取下面三种操作之一:
1) 不采取任何行动, 由系统来进行处理;
2) 捕获该信号, 但忽略它;
3) 捕获该信号, 并采取相应的行动.


2.3  trap 捕捉信号
① trap 可以使你在脚本中捕捉信号. 命令形式为:
trap    name    signal(s)

其中, name 是捕捉到信号以后所采取的一系列操作.
实际中, name 一般是一个专门用来处理所捕捉信号的函数.
name 需要用双引号(" ")引起来.
signal 就是待捕捉的信号.   (信号可以是多个信号, 由空格来分割)

最常见的行动包括:
1) 清除临时文件;
2) 忽略该信号; (trap  ""  2  3)
3) 询问用户是否终止该脚本的运行.

举例 (trap1.sh,  trap2.sh)

#!/bin/bash
#trap1.sh
trap   'exitprocess'    2
LOOP=0
function  exitprocess( )
{
echo   "You  just  hit  <CTRL+C>, at  number  $LOOP"
echo   "I  will  now  exit"
exit   1
}
while :            //这个循环总是为真
do
               LOOP=$[$LOOP+1]
               echo   $LOOP
               sleep  1
done


示例2:
#!/bin/bash
#trap2.sh
LOOP=0
trap   'exitprocess'    2
HOLD1=/tmp/hold1.$$
HOLD2=/tmp/hold2.$$
function   exitprocess( )
{
echo  -e  "\nRecived  Interrupt ..."
echo  -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  "<CTRL-C>  detected ... Now  cleaning  up  ...wait"
rm  /tmp/*.$$  2>/dev/null
exit  1
}
while :
do
LOOP=$[$LOOP+1]
echo  $LOOP
df>>$HOLD1
ps  -xa  >>$HOLD2
sleep  1
done


2.4  eval 命令
① eval 命令将会首先扫描命令行进行所有的置换, 然后再执行该命令.
该命令适用于那些一次扫描无法实现其功能的变量.
② MYFILE="cat  myfile";      `eval   $MYFILE`

eval   `cat  myfile`


2.4  logger
① logger 命令向 /var/log/message文件发送消息; (写消息进去)
② logger 命令的一般形式为:
logger   -p   -i   message
-p : 为优先级, 这里只涉及到提示用户注意的优先级, 这也是缺省值.
-i  : 在每个消息中记录发送消息的进程号

示例:
cat    /var/log/messages    记录一些非常重要的日志;

系统进程 syslogd  负责把系统信息输出到响应的文件中;

logger  -p   1   -i     "chinaitlab   shenzhen"
cat    /var/log/messages

---------------------------------------------------------------------------

第三章   运行级别脚本介绍

内容:
① 运行级别
② inittab
③ 启动应用程序


3.1 运行级别
① 运行级别目录 (/etc/rcN.d)
② 当前运行级别(runlevel)
③ 运行级别目录文件格式 (进入目录/etc/rcN.d 后, 可以看到)
(SXXscript, KXXscript)
SXXscript : S开头表示在此优先级下面, 这个脚本的服务是在运行着的;
 KXXscript: K开头表示在此优先级下面, 这个脚本的服务是被停止的.

注: 都是一些超链接文件.
S00--S99 : 按照阿拉伯数字的大小, 从小到大一次启动.
服务启动的相互依赖性, 被依赖的服务(数字小的服务)必须先启动.


3.2 inittab
① 运行级别控制文件 (/etc/inittab)      cat 查看一下.
② 修改inittab文件

示例:
# Thing  to run in every  runlevel
ud::once:/sbin/update
checkdisk:3:once:/sbin/checkdisk.sh  > /dev/console  2> &1


3.2 启动应用程序
① 启动脚本分析 (start | stop | restart)
cat   /etc/init.d/crond
② 启动脚本
service  server  start | stop | restart | ...         //server  是脚本的名字;  start | stop | restart | 是参数,1,2,3
script_name  start | stop | restart

例: vi   /etc/rc3.d/S90crond

示例:
service   crond  stop
service   crond   restart
service   crond   status

注: 运行脚本通常放在 /etc/init.d 目录下面

---------------------------------------------------------------------------

第四章  几个脚本的例子

① kill_processes.sh
② cpdir.sh
③ menu.sh

示例1:
#!/bin/bash
#kill_process.sh
#取得当前进程号
current_PID=$$                      //$$ 一个特殊的变量, 表示当前进程号
#获得特定进程的进程号并重定向到一个临时文件中
ps  -aux | grep  "/usr/sbin/httpd" | grep  -v  "grep" | awk  '{print   $2}' > /tmp/${current_PID}.txt
                                               //grep  -v  "grep"  表示过滤掉grep
#命令块开始
for  pid  in  `cat  /tmp/${current_PID}.txt`
do
{
echo   "kill   -9   $pid"
kill   -9   $pid
}
done
#命令块结束
#删除临时文件
echo    "rm   -f   /tmp/${current_PID}.txt"
rm   -f   /tmp/${current_PID}.txt


示例2:
#!/bin/bash
#cpdir.sh
#此脚本用于将源目录下的子目录全部复制到目的目录中,不复制源目录中的文件,
#确保目的目录中的子目录是空目录.

#脚本用法函数
usage( )
{
echo  "cpdir.sh  源目录  目的目录"
}

#判断是否为两个参数, 否则提示脚本 用法
if  [ $#  -ne  2 ]
then
{
usage
exit  0
}
fi

srcdir=$1
desdir=$2
#判断源目录${srcdir}是否为目录, 否则提示错误信息和用法
if  [ !  -d  $srcdir ]
then
{
usage
echo  "错误: 源目录${srcdir}不是目录"
exit
}
fi

#判断目的目录${desdir}是否为目录, 否则提示错误信息和用法
if  [ !  -d  $desdir ]
then
{
usage
echo  "错误: 目的目录${desdir}不是目录"
exit
}
fi

processid=$$;

#查找源目录下所有的子目录, 输出并保存到 /tmp/srcdir_进程号.txt文件中
echo  "源目录下${srcdir}所有的子目录"
echo  "-------------------------------------"
find  $srcdir/*   -type   d | /usr/bin/tee   /tmp/srcdir_tmp_${processid}.txt
#替换
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}所有的子目录"
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



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多