shell脚本

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了shell脚本相关的知识,希望对你有一定的参考价值。

Shell脚本

Shell的简介:
Shell是一个命令解释器,它在操作系统的最外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出到屏幕上返回给用户,这种对话方式可以是交互式的也可以是非交互式的。
Shell脚本在运维工作中的作用地位
Shell脚本很擅长处理纯文本类型的数据,而Linux中几乎所有的配置文件、日志文件(如:NFS、rsync、httpd、nginx、lvs等)都是纯文本类型的文件。因此,如果学好shell脚本语言,就可以利用他在Linux系统中发挥巨大作用。
Shell脚本语言的种类
在UNIX和LINUX中主要有两大类shell
1)Bourne shell(包括sh,ksh,bash)
Bourne shell (sh)
Kor n shell (ksh)
Bourne Again shell (bash)
POSIX shell (sh)
2)C shell(包括csh,tcsh)
C shell (csh)
TENEX/TOPS Cshell (tcsh)
Shell脚本语言是弱类型语言,较为通用的shell有标准的Bourne shell(sh)和C shell (csh)。其中Bourne shell(sh)已经被bash shell取代。
查看系统的SHELL:
[[email protected] ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
其他运维人员常用的脚本语言种类:
1) php
PHP是网页程序,也是脚本语言。更专注于web页面的开发,列如:dedecms,discus.也可以处理系统日志,配置文件等。
2) Perl
Perl脚本语言比shell强大的多,2010前很火,语法灵活、复杂,实现方式很多,不易读,团队协作困难。
3)Python
近几年很火,可以做脚本开发,也可以实现web开发。中等以上企业都要求会Python。
Shell与PHP、Perl、Python语言的区别和优势:
Shell的优势在于处理操作系统底层的业务,因为有大量的命令为它做支持,2000多个命令都是shell编程的有力支持,特别是grep,awk,sed等;例如:一键软件安装、优化,监控报警脚本,常规的业务应用,shell开发更简单便捷,符合运维的大原则。
PHP、Python优势在于开发运维工具,web界面的管理工具,以及web业务的开发等。
常见操作系统默认shell
Linux是Bourne Again shell (bash)
Solaris和FreeBSD是Bourne shell (sh)
AIX下是Korn shell (ksh)
HP-UX是POSIX shell (sh)
Shell脚本的建立和执行:
1) 脚本的开头
一个规范的shell脚本的第一行会指出由哪个程序(解释器)来执行脚本中的内容,在Linux bash编程中为:
#!/bin/bash或#!/bin/sh
其中开头的“#!”又称为幻数,在执行bash脚本的时候,内核会根据“#!”后的解释器来确定该有哪个程序解释脚本中的内容。注:这一行必须在每个脚本顶端的第一行,如果不是第一行则是注释。
2) Sh和bash的区别:
Sh是bash的一个软连接,标准写法是#!/bin/bash,但实际上都一样。
[[email protected] ~]# ll /bin/sh
lrwxrwxrwx. 1 root root 4 Aug 31 06:13 /bin/sh -> bash
[[email protected] bin]# bash --version
bash –version(bash的版本信息。)
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>;

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
printf "\033]0;%[email protected]%s:%s\007" "${USER}" "${HOSTNAME%%.*}" "${PWD/#$HOME/~}"
3) 脚本注释:
在Linux中#后面的是注释,加注释既是方便自己也是方便别人,特别是关键位置,加上注释便于阅读脚本。
Shell脚本的执行:
当shell脚本以非交互式(文件方式)运行时,它会先查看环境变量ENV,该变量指定了一个环境文件(通常是.bashrc,.bash_profile,/etc/profile,/etc/bashrc等)然后从该环境变量文件开始执行,当读取ENV文件后,shell才开始执行shell脚本中的内容。
Crond定时任务需要将系统的环境变量重新定义。
Shell脚本的执行通常采用以下的三种方式:
1) bash 脚本名 或 sh 脚本名
2) 全路径/脚本名 或 ./脚本名(相对路径在当前路径下,注:用这种方法文件必须有可执行权限。)
3) Source 脚本名 或 . 脚本名 #注意“.”点号(注;这种方法运行脚本,脚本中的环境变量会影响到系统的环境变量)。
Shell脚本开发基本规范及习惯:
1) 开头指定脚本解释器。
2) 开头加版本版权等信息。
3) 脚本中不用中文注释
4) 脚本以.sh为扩展名
5) 代码书写优秀习惯。
1) 成对的符号内容要一次写出来,防止遗漏。如:”” ‘’ [] {}等
2) {}中括号里两端有空格,书写时可先预留出来再写内容。
3) 流程控制语句一次书写完,在添加内容,如:
If语句格式:
If 条件内容
Then
内容
fi
for循环一次写完
for
do
done
4) 通过缩进让代码易读。
环境变量:
环境变量用于定义shell的运行环境,保证shell命令的正确执行,shell通过环境变量来确定登录用户名、命令路径、终端类型、登陆目录等,所有的环境变量都是系统全局变量,可用于子进程中,这包括编辑器。Shell脚本和各种应用(定时任务特殊需重新定义)。
环境变量可以在命令行中定义,但用户退出时这些变量值也会丢失,因此最好在用户的家目录下的.bash_profile文件中或全局变量/etc/profile,/etc/bashrc文件或者/etc/profile.d/中定义。这样每次用户登录时这些变量值都会被初始化。
传统上,所有的环境变量均为大写。环境变量应用于用户进程前,必须用export命令导出。
环境变量可用在创建他们的shell和从该shell派生的任意子shell或进程中,他们通常被称为全局变量以区别局部变量。
用env可以查看系统定义的环境变量
设置全局环境变量:(命令行定义,用户退出或重启系统则不再生效)
1) export 变量名=value
2) 变量名=value; export 变量名
3) Declare -x 变量名=value
永久生效应将上述内容添加到环境变量的配置文件中。
显示和取消变量:
1)用echo 或 printf $变量名(printf意思:format and print data
[[email protected] ~]# echo $USER
root
[[email protected] ~]# printf "$USER\n"(\n换行的意思)
root
2)用env(printenv)或set显示默认的环境变量。
[[email protected] ~]# env
HOSTNAME=xuexi
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=192.168.0.18 63285 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root
3)用unset 变量名 取消变量值
局部变量:
定义本地变量:
本地变量在用户当前的shell的脚本中使用,例如,本地变量OLDBOY取值为ett098,这个值只在用户当前shell生存期中有意义。如果在shell中启动另一个进程或退出,本地变量OLDBOY值将无效。
1)普通字符串变量定义:
变量名=value
变量名=’value’
变量名=”value”
Shell中变量名的要求:一般是字母,数字,下划线组成。字母开头。
[[email protected] ~]# a=192.168.1.1
[[email protected] ~]# b=‘192.168.1.1‘
[[email protected] ~]# c="192.168.1.1"
[[email protected] ~]# echo "a=$a"
a=192.168.1.1
[[email protected] ~]# echo "b=$b"
b=192.168.1.1
[[email protected] ~]# echo "c=${c}"
c=192.168.1.1
小结:连续普通字符串内容,赋值给变量,内容是什么,变量打印就输出什么。
[[email protected] ~]# a=192.168.1.1-$a
[[email protected] ~]# b=‘192.168.1.1-$a‘
[[email protected] ~]# c="192.168.1.1-$a"
[[email protected] ~]# echo "a=$a"
a=192.168.1.1-192.168.1.1
[[email protected] ~]# echo "b=$b"
b=192.168.1.1-$a
[[email protected] ~]# echo "c=${c}"
c=192.168.1.1-192.168.1.1-192.168.1.1
上述实例中,第一种a变量的方式是直接定义变量内容,内容一般为简单连续的数字、字符串、路径名等。
第二种b变量的方式是通过单引号定义变量,这个方式的特点是:输出变量时引号是什么就输出什么,即使内容中包含变量也会把变量名原样输出,此法适合定义显示纯字符串。
第三种c变量方式是通过双引号定义变量。这个方式的特点:输出变量时双引号里的变量会经过解析后输出该变量内容,而不是把引号中变量名原样输出,适合于字符串中附带有变量的内容的定义。
笔者习惯:数字不加引号,其他默认加双引号。
Grep过滤实例:
[[email protected] ~]# vim a.txt
[[email protected] ~]# O=testchars
[[email protected] ~]# grep $O a.txt
testchars
[[email protected] ~]# grep ‘$O‘ a.txt
[[email protected] ~]# grep "$O" a.txt
testchars
awk过滤实例:
[[email protected] ~]# ETT=123
[[email protected] ~]# awk ‘BEGIN {print "$ETT"}‘
$ETT
[[email protected] ~]# awk ‘BEGIN {print ‘$ETT‘}‘
123
[[email protected] ~]# awk ‘BEGIN {print $ETT}‘

[[email protected] ~]# ETT=‘abc‘(双引号一样)
[[email protected] ~]# awk ‘BEGIN {print ‘$ETT‘}‘

[[email protected] ~]# awk ‘BEGIN {print $ETT}‘

[[email protected] ~]# awk ‘BEGIN {print "$ETT"}‘
$ETT
[[email protected] ~]# awk ‘BEGIN {print "‘$ETT‘"}‘
abc
[[email protected] ~]# awk ‘BEGIN {print ‘"$ETT"‘}‘

[[email protected] ~]#
Sed过滤实例:
[[email protected] ~]# vim a.txt
[[email protected] ~]# sed -n ‘/$USER/p‘ a.txt
[[email protected] ~]# sed -n "/$USER/p" a.txt
root
[[email protected] ~]# sed -n /$USER/p a.txt
root
自定义普通字符串变量的建议:
1) 内容是纯数字(没空格),定义方式可以不加引号(单或双),例如:
O=123
M=yes
2) 没特殊情况,字符串一般用双引号定义,特别是多个字符串中间有空格时,例如:
U=“This is pen”
Y=” my god”
3) 变量内容需要原样输出时,用(‘’)单引号
P=’U’
变量的命名规范:
1)变量命名要统一,使用全部大写字母,如APACHE_ERRNUM;语义要清晰,能够正确表达变量内容的含义,过长的英文单词可采用前几个字符代替,多个单词连接使用“”号连接,引用时,做好以${APACHE_ERR_NUM }加大括号或“${APACHE_ERR_NUM }”外面加双引号方式引用变量;
2)避免无含义字符或数字
小结:定义变量多模仿系统的定义,规范的定义写法:
1) OLDBOYAge=1
2) oldboy_age=1
3) oldboyAgeSex=1(驼峰语法)
把命令作为变量定义方法:实例:
[[email protected] ~]# CMD=$(date +%F)
[[email protected] ~]# echo $CMD
2018-01-08
[[email protected] ~]# CMD=date +%F
[[email protected] ~]# echo $CMDbr/>2018-01-08
Shell特殊变量
1.位置变量:
$0获取当前执行的shell脚本的文件名,包括脚本路径。
$n获取当前执行的shell脚本的第n个参数值,n=1…9,当n为0时表示脚本的文件名,如果n大于9用大括号括起来${10}.
$#获取当前执行的shell脚本后面传参的参数的总个数。
$?获取执行上一个指令的返回值(0为成功,非0为失败)这个很有用。
$?返回值:0为成功,2为权限被拒,1~125表示运行失败,脚本命令,系统命令错误或参数传递错误,126是找到该命令,但无法执行,127表示找不到命令,>128表示命令被系统强制结束。
$*获取当前shell的所有参数,将所有的命令行参数视为单个字符串,相当于“$1$2$3….”注意与$#的区别。
[email protected]这个程序的所有参数“$1””$2””$3”......,这是讲参数传递给其他程序的最佳方式,因为他会保留所有内嵌在每个参数里的任何空白。
$$获取当前shell的进程号(PID).
$!执行上一个指令的PID。
$_在此之前执行的命令或脚本的最后一个参数。
$0实例:
[[email protected] ~]# cat d.sh
echo $0
[[email protected] ~]# sh d.sh
d.sh
[[email protected] ~]# cat d.sh
dirname $0
basename $0
[[email protected] ~]# sh pwd/d.sh
/root
d.sh
$n实例:
[[email protected] ~]# cat d.sh
$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
[[email protected] ~]# sh d.sh {a..z}
a b c d e f g h i j k l m n o
$#实例:
[[email protected] ~]# cat d.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
echo $#
[[email protected] ~]# sh d.sh {a..z}
a b c d e f g h i j k l m n o
26
[[email protected] ~]# cat d.sh
[ $# -ne 2 ] && {
echo "muse two"
exit 1(1相当于赋值给$?)
}
echo "ok"
[[email protected] ~]# sh d.sh qq
muse two
[[email protected] ~]# sh d.sh qq uuu
ok
注:在脚本调用,一般用exit 0,函数retrun 0.控制命令及脚本的返回值
http://oldboy.blog.51cto.com/2561410/1175971 (linux下set和eval的使用案例)
${value:-word}:如果value未定义,则变量值为word
${value:?”not defined”}:如果变量value为赋值,则会显示-bash:value: not defined
If条件句:
单分支结构:
语法:
If[条件]
Then
指令
fi

If[条件]
指令
fi
实例:
[[email protected] ~]# cat if.sh
#!/bin/bash
file="a.txt"
dir="/server/scripts"
#no1
if [ ! -d $dir ]
then
mkdir -p $dir
fi
#no2
if [ ! -f $file ]
then
touch $dir/$file
fi
ls -l $dir/$file
[[email protected] ~]# sh if.sh
-rw-r--r--. 1 root root 43 Dec 7 19:11 /server/scripts/a.txt
内存小于100M发邮件报警实例:
[[email protected] ~]# cat cache.sh
#!/bin/bash
cache=free -m|awk ‘NR==3 {print $NF}‘
if [ $cache -lt 900 ]
then
echo "cache <900"|mail -s "cache" root
fi
多分支结构:
If 条件
Then
指令
elif 条件
then
指令
else
指令
if
实例:
[[email protected] ~]# cat bijiao.sh
#!/bin/bash
expr $1 + 0 &>/dev/null
value=$?
expr $2 + 0 &>/dev/null
value1=$?
if [ $value -ne 0 -o $value1 -ne 0 ]
then
echo "Please re-enter"
exit 1
fi
if [ $1 -eq $2 ]
then
echo "$1 = $2"
elif [ $1 -lt $2 ]
then
echo "$1 < $2"
else
echo "$1 > $2"
fi
exit 0
检测mysql启动是否正常,启动了给个提示,没启动就用脚本启动实例:
[[email protected] ~]# cat listen.sh
#!/bin/bash
Port=lsof -i :3306|grep mysql|wc -l
if [ $Port -eq 1 ]
then
echo "MySQL is running"
else
/etc/init.d/mysqld start
fi
远程:http://oldboy.blog.51cto.com/2561410/942530
WEB服务监控:
[[email protected] ~]# cat web.sh
#!/bin/bash
Port=lsof -i :80|grep httpd|wc -l
if [ $Port -ne 6 ]
then
/etc/init.d/httpd start
else
echo "Httpd is running"
fi
方法2:
[[email protected] ~]# cat web1.sh
#!/bin/bash
value=curl -I 127.0.0.1|awk ‘NR==1‘|awk ‘{print $(NF-1)}‘ &>/dev/null
if [ $value -ne 200 ]
then
/tec/init.d/httpd start
else
echo "Httpd is running"
fi
web服务判断条件:
[[email protected] ~]# lsof -i :80|wc -l(判断条件大于1即可)
7
[[email protected] ~]# nmap 192.168.0.40 -p 80|grep open|wc -l(判断条件等于1即可)
1
[[email protected] ~]# ps -ef|grep httpd|wc -l(判断条件大于2即可)
7
[[email protected] ~]# curl -I -s 192.168.0.40|head -1|awk ‘{print $2}‘(判断条件等于200即可)
200
[[email protected] ~]# wget --spider --timeout=3 --tries=2 192.168.0.40 &>/dev/null
[[email protected] ~]# echo $?(判断条件等于0即可)
0
测试语句:
【语法说明】:
格式一:test<测试表达式>
格式二:[<测试表达式>]
格式三:[[<测试表达式>]]
说明
格式一和格式二是等价的

格式一实例:(可以man test了解详情)
[[email protected] ~]# test -f file && echo "1" || echo 0
0
[[email protected] ~]# test -f a.log && echo "1" || echo 0
1
加上!是非的意思;取反:
[[email protected] ~]# test ! -f a.log && echo "1" || echo 0
0
[[email protected] ~]# test ! -f file && echo "1" || echo 0
1
格式二实例:
[[email protected] ~]# [ ! -f file ] && echo "1" || echo 0
1
[[email protected] ~]# [ -f file ] && echo "1" || echo 0
0
[[email protected] ~]# [ -f a.log ] && echo "1" || echo 0
1
[[email protected] ~]# [ ! -f a.log ] && echo "1" || echo 0
0
格式三:实例:
[[email protected] ~]# [[ ! -f a.log ]] && echo "1" || echo 0
0
[[email protected] ~]# [[ -f a.log ]] && echo "1" || echo 0
1
[[email protected] ~]# [[ -f file ]] && echo "1" || echo 0
0
[[email protected] ~]# [[ ! -f file ]] && echo "1" || echo 0
1
文件测试操作符:
常用文件测试操作符:
-f 文件 file 若文件存在且为普通文件则真。
-d 文件 directory 若文件存在且为目录文件则真。
-s 文件 size 若文件存在且不为空(文件大小非0)则真。
-e 文件 exist 若文件存在并且是普通文件则真,要区别-f
-r 文件 read 若文件存在且可读则真
-w 文件 write 若文件存在且可写则真
-x 文件 excute 若文件存在且可执行则真
-L 文件 link 若文件存在且为链接文件则真
f1 -nt f2 newer than 若文件f1比文件f2新则真
f1 -ot f2 older than 若文件f1比文件f2旧则真
字符串测试操作符:
字符串测试操作符的作用:比较两个字符串是否相同、字符串长度是否为零,字符串是否被为NULL(注:bash区分零长度字符串和空字符串)等。
“=”比较两个字符串是否相同,与==等价,如if [ “$a”=”$b” ],其中$a这样的变量最好用””号括起来,因为如果中间有空格,*等符号就可能出错了,当然更好的方法是[ “${a}”=”${b}” ].“!=”取反的意思。
常用字符串测试操作符:
-z“字符串” 若串长度为0则真,-z可以理解为zero
-n“字符串” 若串长度不为0则真,-z可以理解为no zero
“串1”=“串2” 若字符串1等于字符串2则真,可用“==”代替“=”
“串1”!=“串2” 若字符串1不等于字符串2则真,不可用“!==”代替“!=”
字符串测试操作提示符提示:
1)-n比较字符串长度是否不为零,如果不为零则为真,如:[ -n “$myvar” ]
2) -z比较字符串是否等于零,如果等于零则为真,如:[ -z “$myvar” ]
特别注意,对于以上表格中的字符串测试操作符号,如:[ -n “$myvar” ],要把字符串用“”引起来。
4) 字符串比较,比较符号两端最好都有空格,多参考系统脚本。
[[email protected] ~]# sed -n ‘30,31p‘ /etc/init.d/network

Check that networking is up.

[ "${NETWORKING}" = "no" ] && exit 6
整数二元比较操作符:
在[]中使用的比较符 在(())和[[]]中使用的比较符 说明
-eq = equal的缩写,相等
-ne != not equal的缩写,不相等
-gt > 大于 greater than
-ge >= 大于等于greater equal
-lt < 小于类似less than
-le <= 小于等于less equal
逻辑操作符:
在[]中使用的逻辑操作符 在[[]]中使用的逻辑操作符 说明
-a && and 与,两端都为真,则真
-o || or 或,两端有一个为真则真
! ! not 非,相反则为真。
监控web服务器是否正常:

  1. 端口:
    本地:ss,netstat,lsof
    远程:telnet,nmap,nc
  2. 本地进程数:
  3. Header(http code)curl -I 返回值200就OK.
  4. URL(wget,curl),模拟用户的方式。
  5. PHP,Java写监控的程序,模拟用户的方式
    最常用是端口和URL或监控程序的结合。
    Apache的启动脚本(简单的)
    [[email protected] ~]# cat start_apache.sh
    #!/bin/bash
    . /etc/init.d/functions
    a=$1
    b=$2
    apache=/etc/init.d/httpd
    if [ -n "$b" ]
    then
    echo "USAGE:$0 {start|stop|restart}"
    exit 1
    fi
    if [ "$a" = "start" ]
    then
    then
    $apache $a &>/dev/null
    action "starting apache" /bin/true
    elif [ "$a" = "stop" ]
    then
    $apache $a &>/dev/null
    action "stopping apache" /bin/true
    elif [ "$a" = "restart" ]
    then
    $apache graceful &>/dev/null
    action "restarting nginx" /bin/true
    else
    echo "USAGE:$0 {start|stop|restart}"
    fi
    exit 0

Shell函数:
函数的作用:简单的说函数的作用就是把程序里多次调用的相同的代码的部分,定义成一份,然后起个名字,所有的调用都只用这个名字就可以了,修改代码时,只需要改变函数体内的泰马即可。
优势:
1) 把相同的程序段定义成函数,可以较少程序代码量。
2) 增加程序的可读,易读性。
3) 实现程序的功能模块化。
Shell函数语法:
语法格式:
简单的语法:
函数名(){
指令…
Return n
}
规范的语法:
Function 函数名(){
指令…..
Return n
}
Shell的执行方法:
1) 直接执行函数名:
函数名
注意:
a. 执行函数时,不要带小括号。
b. 函数定义及函数体必须在要执行的函数名前面定义,shell的执行从上到下按行执行的。
2) 带参数的函数执行方法:
函数名 参数1 参数2
函数带参数的说明:
1) 在函数体中位置变量($1,$2,$3,$#,$*,$?以及[email protected])都可以是函数的参数。
2) 父脚本的参数则临时地被函数参数所掩盖或隐藏。
3) $)比较特殊,它仍是父脚本的名称。
4) 当函数完成时,原来的命令行参数会恢复。
5) 在shell函数里面,return命令的功能与工作方式与exit相同,用于跳出函数。
6) 在shell函数里使用exit会终止整个shell脚本。
7) Return语句会返回一个退出值给调用的程序。
Mysql启动脚本实例:
[[email protected] ~]# cat startmysql.sh
#!/bin/bash
function mysql(){
/bin/sh /application/mysql/bin/mysqld_safe
}
function stopmysql1(){
/application/mysql/bin/mysqladmin -u root shutdown &>/dev/null
if [ $? -eq 0 ]
then
action "stopping mysql" /bin/true
else
action "stopping mysql" /bin/false
fi
}
. /etc/init.d/functions
if [ "$1" = "start" ]
then
mysql &>/dev/null &
if [ $? -eq 0 ]
then
action "starting mysql" /bin/true
else
action "starting mysql" /bin/false
fi
elif [ "$1" = "stop" ]
then
stopmysql1
elif [ "$1" = "restart" ]
then
stopmysql1 &>/dev/null
if [ $? -eq 0 ]
then
action "stopping mysql" /bin/true
else
action "stopping mysql" /bin/false
fi
mysql &>/dev/null &
if [ $? -eq 0 ]
then
action "starting mysql" /bin/true
else
action "starting mysql" /bin/false
fi
else
echo "usage:{start|restart|stop}"
fi
当型循环和直到型循环:

  1. while条件句语法:
    while 条件
    do
    指令…
    Done
  2. until 条件句语法:(使用不多,了解,直到循环)
    until 条件
    do
    指令…
    done
    防止脚本执行中断的方法:
    1) 执行脚本 &(后台运行脚本)
    2) Screen命令
    3) Nohup 脚本路径/脚本名 &
    进程管理命令:
    Bg:后台运行 fg:挂起程序 jobs:显示后台程序 kill/killall/pkill:杀死进程 crontab:设置定时 ps:查看进程 pstree:显示进程状态树 top:显示进程(动态) nice:改变优先权 nohup:用户退出系统之后继续工作 pgrep:查找匹配条件的进程 strace:跟踪一个进程的系统调用情况 ltrace:跟踪程序调用库函数的情况 vmstat:报告虚拟内存统计信息
    While循环实例:计算100内之和:
    [[email protected] ~]# cat while1.sh
    #!/bin/bash
    i=1
    sum=0
    while [ $i -le 100 ]
    do
    sum=$(expr $sum + $i)
    let i++
    done
    echo "$sum"
    while循环小结:
    1) while循环的特长是执行守护进程以及我们希望循环不退出持续执行,用于频率小于1分钟循环处理(crond),其他的while循环几乎都可以被我们即将要讲for循环代替。
    2) case语句可以替换if语句,一般在系统启动脚本传入少量固定规则字符串,用case,其他判断多用if.
    3) 一句话,if,for语句最常用,其次while(守护进程),case(服务启动脚本)。
    For循环结构:
    1.for循环结构语法:
    For 变量名 in 变量取值列表
    Do
    指令
    done
    2.C语言型for循环结构语法:
    For((exo1;exp2;exp3))
    do
    指令
    done
    用for循环实现将文件名中的oldboy全部改成linux,并且扩展名改成大写,for循环的循环体不能出现oldboy字样。实例:
    [[email protected] ~]# ls /oldboy/
    oldboy_10.html oldboy_2.html oldboy_4.html oldboy_6.html oldboy_8.html
    oldboy_1.html oldboy_3.html oldboy_5.html oldboy_7.html oldboy_9.html
    [[email protected] ~]# vim for2.sh
    [[email protected] ~]# sh for2.sh
    [[email protected] ~]# ls /oldboy/
    linux_10.HTML linux_2.HTML linux_4.HTML linux_6.HTML linux_8.HTML
    linux_1.HTML linux_3.HTML linux_5.HTML linux_7.HTML linux_9.HTML
    [[email protected] ~]# cat for2.sh
    #!/bin/bash
    cd /oldboy/
    for i in ls
    do
    mv $i $(echo $i|sed ‘s#oldboy(.)html#linux\1HTML#g‘)
    done
    批量创建10个系统账户并设置密码(密码不態相同。)
    [[email protected] ~]# cat for.sh
    #!/bin/bash
    for i in seq -w 10
    do
    useradd oldboy$i&&\
    echo "root$i"|passwd --stdin oldboy$i
    done
    批量创建10个系统账户并设置密码(密码不態相同且是随机数。)
    [[email protected] ~]# cat for.sh
    #!/bin/bash
    . /etc/init.d/functions
    for i in seq -w 10
    do
    passwd=$(echo "$RANDOM"|md5sum|cut -c 1-8)
    useradd oldboy$i&&\
    echo "passwd"|passwd --stdin oldboy$i &>/dev/null &&\
    action "chenggong" /bin/true
    echo -e "oldboy$i\t $passwd" >>/oldboy/a.txt
    done
    break continue exit对比;
    命令 说明
    Break n n 表示跳出循环的层数,如果省略n表示跳出整个循环。
    Continue n n表示退出到第n层继续循环,如果省略n表示跳过本次循环,忽略本次循环剩余代码,进入循环的下一次循环。
    Exit n 退出当前shell程序,n表示返回值,n也可以省略,再下一个shell里通过$?接收这个n值。
    Return n 用于在函数里,作为函数的返回值,用于判断函数执行是否正确。
    Shell数组介绍
    平时的定义a=1,b=2,c=3,变量如果多了,再一个一个定义很费劲,并且取变量的也费劲。
    简单的说,数组就是相同数据类型的元素按一定顺序排列的集合。
    数组就是把有限类型相同的变量用一个名字命名,然后用编号区分他们的变量的集合,这个名字成为数组名,编号成为数组下标。组成数组的各个变量成为数组的分量,也称为数组的元素,有时也称为下标变量。
    数组的定义与增删改查:
    格式1:
    Array=(value1 value2 value3)
    1) 数组的定义
    [[email protected] ~]# array=(1 2 3)
    2) 获取数组的长度
    [[email protected] ~]# echo ${#array[@]}
    3
    [[email protected] ~]# echo ${#array[
    ]}
    3
    3) 打印数组的元素
    [[email protected] ~]# echo ${array[0]}
    1
    [[email protected] ~]# echo ${array[1]}
    2
    [[email protected] ~]# echo ${array[2]}
    3
    用for循环打印出字符数小于6的单词实例:
    I am oldboy teacher welcome to oldboy training class
    方法1:
    [[email protected] ~]# sh for4.sh
    I
    am
    to
    class
    [[email protected] ~]# cat for4.sh
    #!/bin/bash
    array=(I am oldboy teacher welcome to oldboy training class)
    for i in $(echo ${array[@]})
    do
    if [ ${#i} -lt 6 ]
    then
    echo "$i"
    fi
    done
    方法2:
    [[email protected] ~]# sh for4.sh
    I
    am
    to
    class
    [[email protected] ~]# cat for4.sh
    #!/bin/bash
    for i in I am oldboy teacher welcome to oldboy training class
    do
    if [ ${#i} -lt 6 ]
    then
    echo "$i"
    fi
    done
    监控web站点目录(/var/html/www)下所有文件是否被恶意篡改(内容被改了),如果有就打印所改动的文件名(发邮件,定时任务每三分钟执行一次。实例:)
    [[email protected] ~]# cat file_md5.sh 创建文件对比的信息库
    find /var/html/bbs/ -type f|xargs md5sum >/oldboy/md5sum.db
    find /var/html/bbs/ -type f >/oldboy/a.log
    [[email protected] ~]# cat web6.sh
    #!/bin/bash
    n=$(cat /oldboy/a.log|wc -l)(源目录文件的行数)
    while true
    do
    Md5=$(md5sum -c /oldboy/md5sum.db 2>>/dev/null|grep -i fail|wc -l)(md5对比错误的行数)
    find /var/html/bbs/ -type f >/oldboy/new-a.log(随时查看源文件的行数)
    log=/oldboy/check.log
    if [ $Md5 -ne 0 ] || [ $(cat /oldboy/new-a.log|wc -l) -ne $n ]
    then
    echo "$(md5sum -c /oldboy/md5sum.db 2>>/dev/null|grep -i fail)" >$log
    diff /oldboy/a.log /oldboy/new-a.log >>$log
    mail -s "file is cuangai $(date)" [email protected] <$log
    fi
    sleep 3
    done
    shell脚本小结:
    1) 重视书写习惯,开发规范和开发制度,尽量减少脚本调试的难度,提升开发效率。
    2) 基本语法要熟悉,才能利用好调试。
    3) 思路要清晰,复杂的脚本要简单化分段实现。
    Shell脚本调试技巧:
    1.使用dos2unix命令处理来自windows下开发的脚本。
    第一步.没有安装先安装yum install -y dos2unix
    第二步[[email protected] ~]# cat -v mysql1.sh检测
    第三步:[[email protected] ~]# dos2unix mysql1.sh 用dos2unix命令格式化
    dos2unix: converting file mysql1.sh to UNIX format ...
    2 使用echo 命令调试
  3. 使用bash命令参数调试:
    -n:不会执行改脚本,进查询脚本语法是否有问题,并给出错v误提示。
    -v: 在执行脚本时,先将脚本的内容输出到屏幕上然后执行脚本,如果有错误,也会给出提示。
    -x : 将执行的脚本内容及输出显示到屏幕上,这个是调试很有用的参数
    4.set脚本调试工具:
    使用bash -x 会把整个脚本执行一遍并检测一般,set可以分段检测,只检测你想检测的那一段。
    #!/bin/bash
    set -x
    for n in {1..9}
    do
    for m in {1..9}
    do
    if [ $m -le $n ]
    then
    echo -ne "${m}x${n}=$(( $m * $n ))\t"
    fi
    set +x
    [[email protected] ~]# sh koujue.sh
    • for n in ‘{1..9}‘
    • for m in ‘{1..9}‘
    • ‘[‘ 1 -le 1 ‘]‘
    • echo -ne ‘1x1=1\t‘
      1x1=1 + set +x

以上是关于shell脚本的主要内容,如果未能解决你的问题,请参考以下文章

用于确保在任何给定时间仅运行一个 shell 脚本的 shell 片段 [重复]

常用python日期日志获取内容循环的代码片段

shell脚本引用expect

Shell脚本切割日志

Eclipse 中的通用代码片段或模板

Python如何调用别人写好的脚本