一、Shell 测试运算和流程控制语句
二、监控disk、cpu和处理qmail邮件队列
三、 Shell 脚本是什么
 
 
一、Shell 测试运算和流程控制语句
basename dirname 可以截取文件名和路径.
${varible##*string} 从左向右截取最后一个string后的字符串
${varible#*string}从左向右截取第一个string后的字符串
${varible%%string*}从右向左截取最后一个string后的字符串
${varible%string*}从右向左截取第一个string后的字符串

[bo@localhost ~]$ dirname /home/bo/erro.html
/home/bo
[bo@localhost ~]$ basename /home/bo/erro.html
erro.html
[bo@localhost ~]$

[bo@localhost ~]$ test_cut=/home/bo/error.html
[bo@localhost ~]$ echo ${test_cut##*/}
error.html
[bo@localhost ~]$ echo ${test_cut#*/}
home/bo/error.html
[bo@localhost ~]$ echo ${test_cut%/*}
/home/bo
[bo@localhost ~]$

学习Shell 前的“热身运动”
 

预定义变量和环境变量相类似,也是在shell一开始时就定义了的变量,所不同的是,用户只能根据shell的定义来使用这些变量,而不能重定义它。所有预定义变量都是由$符和另一个符号组成的,常用的shell预定义变量有:

  $#:位置参数的数量

  $*:所有位置参数的内容

  $?:命令执行后返回的状态

  $$:当前进程的进程号

  $!:后台运行的最后一个进程号

  $0:当前执行的进程名

  其中,“$?”用于检查上一个命令执行是否正确(在Linux中,命令退出状态为0表示该命令正确执行,任何非0值表示命令出错)。

  “$$”变量最常见的用途是用作临时文件的名字以保证临时文件不会重复。

hadoop@puppet-client:/tmp> sh tesh.sh aaa bbb 333 444
"$#:" 4
"$*:" aaa bbb 333 444
"$?:" 0
"$$:" 9110
"$!:"
"$0:" tesh.sh
"$@:" aaa bbb 333 444
hadoop@puppet-client:/tmp>

hadoop@puppet-client:/tmp> cat te.sh
echo '"$#:"' $#
echo '"$*:"' $*
echo '"$?:"' $?
echo '"$$:"' $$
echo '"$!:"' $!
echo '"$0:"' $0
echo '"$@:"' $@
hadoop@puppet-client:/tmp>

 

 

测试运算
数值测试运算
-eq 判断两个数字是否相等,相等返回“0”,不相等返回“1”
-ge 判断第一个数字是否大于等于第二个数字,大于等于返回0,小于返回“1”
-gt 判断第一个数字是否大于第二个数字,大于返回“0”,不大于返回“1”
-le 判断第一个数字是否小于等于第二个数字,小于等于返回“0”,大于返回“1”
-lt 判断第一个数字是否小于第二个数字,小于返回“0”,不小于返回“1”
-ne 判断两个数不相等,不相等返回“0” ,相等返回“1”
字符串运算测试
string1 = string2   如果两个字符串相等则返回true, 否则返回false。
string1 != string2  如果两个字符串不相等则返回true, 否则返回false。
string1 > string2   如果string 1 大于 string2, 则返回true ,否则返回false。
string1 < string2   如果string 1小于string 2 , 则返回true,否则返回false。
-n string:  如果字符中长度大于0,则返回true , 否则返回false; 通常可以省略-n 
-z string:  如果字符串的长度等于0,则返回true, 否则返回false。

文件测试运算
-d filename  判断filename 是否为目录,是则返回0,否则返回1
-f filename  判断filename 是否为文件,是则返回0,否则返回1
-r filename  判断filename 是否可读, 是则返回0,否则返回1
-w filename  判断filename 是否可写, 是则返回0,否则返回1
-x filename  判断filename 是否可执行, 是则返回0,否则返回1
-L filename  判断filename 是否是一个符号链接文件, 是则返回0,否则返回1
-s filename  判断filename 的长度是否大于0, 是则返回0,否则返回1
-u filename  判断filename 是否有suid位设置, 是则返回0,否则返回1
 
-e        文件存在
-a        文件存在
        这个选项的效果与-e相同.但是它已经被弃用了,并且不鼓励使用
-f        file是一个regular文件(不是目录或者设备文件)
-s        文件长度不为0
-d        文件是个目录
-b        文件是个块设备(软盘,cdrom等等)
-c        文件是个字符设备(键盘,modem,声卡等等)
-p        文件是个管道
-h        文件是个符号链接
-L        文件是个符号链接
-S        文件是个socket
-t        关联到一个终端设备的文件描述符
        这个选项一般都用来检测是否在一个给定脚本中的stdin[-t0]或[-t1]是一个终端
-r        文件具有读权限(对于用户运行这个test)
-w        文件具有写权限(对于用户运行这个test)
-x        文件具有执行权限(对于用户运行这个test)
-g        set-group-id(sgid)标志到文件或目录上
        如果一个目录具有sgid标志,那么一个被创建在这个目录里的文件,这个目录属于创建
        这个目录的用户组,并不一定与创建这个文件的用户的组相同.对于workgroup的目录
        共享来说,这非常有用.见<<UNIX环境高级编程中文版>>第58页.
-u        set-user-id(suid)标志到文件上
        如果运行一个具有root权限的文件,那么运行进程将取得root权限,即使你是一个普通
        用户.[1]这对于需要存取系统硬件的执行操作(比如pppd和cdrecord)非常有用.如果
        没有suid标志的话,那么普通用户(没有root权限)将无法运行这种程序.
        见<<UNIX环境高级编程中文版>>第58页.
           -rwsr-xr-t    1 root       178236 Oct  2  2000 /usr/sbin/pppd
        对于设置了suid的文件,在它的权限标志中有"s".
-k        设置粘贴位,见<<UNIX环境高级编程中文版>>第65页.
        对于"sticky bit",save-text-mode标志是一个文件权限的特殊类型.如果设置了这
        个标志,那么这个文件将被保存在交换区,为了达到快速存取的目的.如果设置在目录
        中,它将限制写权限.对于设置了sticky bit位的文件或目录,权限标志中有"t".
           drwxrwxrwt    7 root         1024 May 19 21:26 tmp/
        如果一个用户并不时具有stick bit位的目录的拥有者,但是具有写权限,那么用户只
        能在这个目录下删除自己所拥有的文件.这将防止用户在一个公开的目录中不慎覆盖
        或者删除别人的文件,比如/tmp(当然root或者是目录的所有者可以随便删除或重命名
        其中的文件).
-O        你是文件的所有者.
-G        文件的group-id和你的相同.
-N        从文件最后被阅读到现在,是否被修改.
以上内容有转载,如有不妥请及时联系马上删除。

复合测试运算
逻辑操作包括与、或,分别用“-a” 和 “-o”来表示。

流程控制语句
1、顺序执行语句:只要把语句按照逻辑顺序写好,Shell脚本解释器就会顺序地执行这些语句。
2、条件选择语句
if then  语句
if 条件表达式
then
   语句1
fi

if 条件表达式; then
   语句1
fi
 

if then  else 语句
if 条件表达式; then
   语句1
else
   语句2
fi
 

if 语句的嵌套语法是:
if  条件表达式1; then
语句1
else
  if 条件表达式2; then
     语句2
  else
     语句3
  fi
fi
 

if elif 语句

if [ $SYSTEM = "Linux" ] ; then
  echo "Linux"
elif [ $SYSTEM = "FreeBSD" ] ; then
  echo "FreeBSD"
elif [ $SYSTEM = "Solaris" ] ; then
  echo "Solaris"
else
  echo "What?"
fi

USER=`who |awk '{ print $1 }'`
if [ $USER = "root" ] ; then
  echo "root"
elif [ $USER = "cacti" ] ; then
  echo "cacti"
elif [ $USER = "nagios" ] ; then
  echo "nagios"
elif [ $USER = "mysql" ] ; then
fi
 

case 语句 就是一个变量的值与期望的值进行匹配
case $1 in
匹配值1)
   语句1
   语句2
   …………
   …………
   ;;
匹配值2)
   语句3
   语句
   …………
   …………
   ;;
匹配值3)
   语句5
   语句6
   …………
   …………
   ;;
esac
 
 

Shell 脚本中的循环语句包括:for 循环、while循环、until循环
for i  in k  g h
do
 echo ok

done

while true
do
 echo ok
done
 
until aa > /dev/null
do
 echo ok
done
 

函数
hello () {
 echo ok
}

function hello () {
 echo hello
}
 
 
 
 

二、监控disk、cpu和处理qmail邮件队列

刚刚开始写一些简单脚本,还是觉得不能得心应手,不过总算写完成了。
面试的时候让写监控disk、cpu使用情况超过90% 后,报警给管理员,当时没有写的很准确,回来了就写了一下。如下:有问题请各位网友指出
2..1
实现硬盘监控。
root@watchout2 ~]# vi watch.sh
#!/bin/bash
for i in `df -k |awk '{print $5}' |grep -v ^[a-z] |awk -F"%" '{print $1}'`
do
if [ $i -ge 90 ]; then
/bin/mail -s "$HOSTNAME `date +%Y-%m-%d-%H-%M----%w`Filesystem over" [email]bo@future.com[/email] < /fileawk -- -f [email]source@watchout.com[/email]
#/bin/mail -s "fileawk over" [email]bo@future.com[/email] < /fileawk -- -f [email]source@watchout.com[/email]
#cat /fileawk | /bin/mail -s "$HOSTNAME$ Filesystem over" [email]bo@future.com[/email] -- -f [email]source@watchout.com[/email]
else
echo `date` Filesystem up to snuff  >> /var/log/filesystem.log
fi
done
 
root@watchout2 ~]# cat /fileawk
192.168.1.238 文件系统使用超过了90% 。
 
注:
     1、这个for的赋值采用的方法有所不同,但效果一样。
for disk in `df -h|awk '{print $5}'|sed 's/%//g'|grep -v "U"`
     2、date +%Y-%m-%d-%H-%M----%w可阅读性不强,可换成
date +%Y%m%d-%R 

 

 
2..2 实现对CPU的监控
#!/bin/bash
logdir=/var/log
logfile=$logdir/cpucheck.log
if [ -f $logfile ]
then
echo "logfile is exist !"
else
touch $logfile
fi
for cpucheck in `sar -u 2 2 |awk '{print $NF}'|sed '1,3d'|sed 's/\([0-9]*\)\..*/\1/g'`
do
if [ $cpucheck -le 10 ]; then
/bin/mail -s "$HOSTNAME `date` cpu USE 90%" bo@future.com < /fileawk -- -f [email]source@watchout.com[/email]
echo cpu Use 90% send post to admin.
else
echo "cpu up to snuff" >> $logfile
echo cpu up to snuff!
fi
done
 
注:
对sar 理解不深,有错误之处请指出,谢谢!
 
2..3 服务器上有两块网块,一块配有电信网关eth0,另一块配有网通的网关eth1,正常的用eth1,网通出现问题时,自动切换到电信。
root:/root>cat gateWin.sh
#!/bin/bash
win=`ping -c 10 192.168.1.138 |grep From |wc -l`
winstatu=`ping -c 10 192.168.1.138 |grep From |awk '{print $1}'|tail -n 1`
if [ "$winstatu" = From -a "$win" -gt 7 ]; then
echo "`date +%y-%m-%d-%R`  network error " >> /var/log/gate.log
#echo "NETWORKING=yes" > /etc/sysconfig/network
#echo "HOSTNAME=dns.secure.net" >> /etc/sysconfig/network
#echo "GATEWAY=11.23.55.77" >> /etc/sysconfig/network
#/bin/mail -s
else
echo "`date +%y-%m-%d-%R` network good" >> /var/log/gate.log
fi
 
 
2..4 qmail 配置过程参考http://www.qmailrocks.org/install_rh.htm
 
         webmail 用的是igenus
      
       1、手工删除队列
 
       使用qmailctl  queue 查看邮件队列,如下信息
      [root@test-linux queue]# qmailctl queue
messages in queue: 174
messages in queue but not yet preprocessed: 0
4 Feb 2009 22:52:30 GMT  #363764  1722  <>
        remote  so@succine.com
5 Feb 2009 16:07:21 GMT  #366929  3162  <>
        remote  courtneyjane@nc.rr.com
5 Feb 2009 11:00:30 GMT  #369885  2429  <>
        remote  michaelerkens@ampen.de
5 Feb 2009 08:29:29 GMT  #366931  18577  <>
        remote  harrell7q@bergencountycontractors.com
4 Feb 2009 23:14:45 GMT  #364400  1737  <>
        remote  plvijayan@successreviews.net
4 Feb 2009 22:52:01 GMT  #363767  1779  <>
        remote  successwebsite.com87ways_order@successwebsite.com
 
#363764   #366929  ……以及都是邮件存在的唯一ID  可以在邮件队列目录下找到这个ID的文件
       
可以使用find  /var/qmail/queue/ -name 363764 -exec rm {} \;  删除队列中某一封邮件
 
如何一次性删除所有邮件队列,我是采用了下面的方法写一个小脚本
 
#!/bin/bash
qmailctl stop
ID=`qmailctl queue |grep "#" |awk '{ print $6 }' |sed s/#//`
for i in $ID
do
#qmailctl stop
find  /var/qmail/queue/ -name $i -exec rm {} \;
#qmailctl start
done
qmailctl start
 
          2、安装qmail-remove程序删除
       
          下载安装qmail-remove源码包,安装源码包的三部曲。
 
          
有一个疑问是上面的红色字体是否代表投递邮件的大小?
 
 
2..5 当文件修改时自动邮件到指定的帐户
#!/bin/bash
# . name  change.sh
# function if change zhou send mail !
while ls > /dev/null
do
    YuanLaiTime=`stat zhou |grep Modify |awk '{print $3}' |awk -F "." '{print $1}' |sed s/://g`
     sleep 30
     ChangeTime=`stat zhou |grep Modify |awk '{print $3}' |awk -F "." '{print $1}' |sed s/://g`
     if [  $YuanLaiTime  -ne $ChangeTime ]; then
     echo Error >> /tmp/fileEr.log
    /bin/mail -s "file change " bo@kuailel23.com < /tmp/fileEr.log -- -f ce@watchout.com
     else
     echo OK >> /tmp/fileOK.log
     fi
done
 
 
2..6 ping
#!/bin/bash
# function check DNS . name is ping.sh .
 tim=`date +%Y%m%d-%H`
 oldtim=`date -d '-60 day' +%Y%m%d-%H`
 touch  /fgn/ping/ping.$tim.txt
 cd /fgn/ping
if [ -f ping.$tim.txt ];
then
        for i in 1.2.2.6 2.3.1.0
        do
          # touch  /tmp/ping/ping.$tim.txt
          date +%Y%m%d-%H%M%S >> /fgn/ping/ping.$tim.txt
          ping $i -c 10 >> /fgn/ping/ping.$tim.txt
        done
        rm -f /fgn/ping/ping.$oldtim.txt
fi

三、Shell 脚本是什么

Shell 脚本是什么?
      shell 脚本是一个包含命令序列的文本文件。当运行文件(或脚本)时,把执行该文件中包含的命令。术语 shell 仅指与 Linux 内核通信所使用的特定命令行用户界面。目前有多个不同的 shell ,其中包括 C shell (csh) 、 Korn shell (ksh) 、 Bourne shell (sh) 和 Bourne-Again shell (bash) 。 shell 本身就是一个从文件或终端读取命令、解释这些命令并通常执行其他命令的命令。 Bourne-Again shell 合并了上述其他 shell 的特性,本文就使用该脚本进行演示。
脚本文件中的第一行可用于指定使用哪个 shell 来运行该脚本。以下是所有脚本示例中包含的第一行的含义:
#!/bin/bash


本文来自ChinaUnix博客,如果查看原文请点:

http://blog.chinaunix.net/u2/60453/showart_480841.html
 
POSIX标准
什么是POSIX标准[可查阅开放系统标准](Open System Standards)。其作用就是为应用软件在不同的平台之间移植提供与unix 类似的标准。