标签:网页程序 return语句 tchar 需要 win 控制语句 for语句 tree 方便
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:
[root@xuexi ~]# 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,但实际上都一样。
[root@xuexi ~]# ll /bin/sh
lrwxrwxrwx. 1 root root 4 Aug 31 06:13 /bin/sh -> bash
[root@xuexi 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;%s@%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
[root@xuexi ~]# echo $USER
root
[root@xuexi ~]# printf "$USER\n"(\n换行的意思)
root
2)用env(printenv)或set显示默认的环境变量。
[root@xuexi ~]# 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中变量名的要求:一般是字母,数字,下划线组成。字母开头。
[root@xuexi ~]# a=192.168.1.1
[root@xuexi ~]# b=‘192.168.1.1‘
[root@xuexi ~]# c="192.168.1.1"
[root@xuexi ~]# echo "a=$a"
a=192.168.1.1
[root@xuexi ~]# echo "b=$b"
b=192.168.1.1
[root@xuexi ~]# echo "c=${c}"
c=192.168.1.1
小结:连续普通字符串内容,赋值给变量,内容是什么,变量打印就输出什么。
[root@xuexi ~]# a=192.168.1.1-$a
[root@xuexi ~]# b=‘192.168.1.1-$a‘
[root@xuexi ~]# c="192.168.1.1-$a"
[root@xuexi ~]# echo "a=$a"
a=192.168.1.1-192.168.1.1
[root@xuexi ~]# echo "b=$b"
b=192.168.1.1-$a
[root@xuexi ~]# echo "c=${c}"
c=192.168.1.1-192.168.1.1-192.168.1.1
上述实例中,第一种a变量的方式是直接定义变量内容,内容一般为简单连续的数字、字符串、路径名等。
第二种b变量的方式是通过单引号定义变量,这个方式的特点是:输出变量时引号是什么就输出什么,即使内容中包含变量也会把变量名原样输出,此法适合定义显示纯字符串。
第三种c变量方式是通过双引号定义变量。这个方式的特点:输出变量时双引号里的变量会经过解析后输出该变量内容,而不是把引号中变量名原样输出,适合于字符串中附带有变量的内容的定义。
笔者习惯:数字不加引号,其他默认加双引号。
Grep过滤实例:
[root@xuexi ~]# vim a.txt
[root@xuexi ~]# O=testchars
[root@xuexi ~]# grep $O a.txt
testchars
[root@xuexi ~]# grep ‘$O‘ a.txt
[root@xuexi ~]# grep "$O" a.txt
testchars
awk过滤实例:
[root@xuexi ~]# ETT=123
[root@xuexi ~]# awk ‘BEGIN {print "$ETT"}‘
$ETT
[root@xuexi ~]# awk ‘BEGIN {print ‘$ETT‘}‘
123
[root@xuexi ~]# awk ‘BEGIN {print $ETT}‘
空
[root@xuexi ~]# ETT=‘abc‘(双引号一样)
[root@xuexi ~]# awk ‘BEGIN {print ‘$ETT‘}‘
[root@xuexi ~]# awk ‘BEGIN {print $ETT}‘
[root@xuexi ~]# awk ‘BEGIN {print "$ETT"}‘
$ETT
[root@xuexi ~]# awk ‘BEGIN {print "‘$ETT‘"}‘
abc
[root@xuexi ~]# awk ‘BEGIN {print ‘"$ETT"‘}‘
[root@xuexi ~]#
Sed过滤实例:
[root@xuexi ~]# vim a.txt
[root@xuexi ~]# sed -n ‘/$USER/p‘ a.txt
[root@xuexi ~]# sed -n "/$USER/p" a.txt
root
[root@xuexi ~]# 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(驼峰语法)
把命令作为变量定义方法:实例:
[root@xuexi ~]# CMD=$(date +%F)
[root@xuexi ~]# echo $CMD
2018-01-08
[root@xuexi ~]# CMD=date +%F
[root@xuexi ~]# 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….”注意与$#的区别。
$@这个程序的所有参数“$1””$2””$3”......,这是讲参数传递给其他程序的最佳方式,因为他会保留所有内嵌在每个参数里的任何空白。
$$获取当前shell的进程号(PID).
$!执行上一个指令的PID。
$_在此之前执行的命令或脚本的最后一个参数。
$0实例:
[root@xuexi ~]# cat d.sh
echo $0
[root@xuexi ~]# sh d.sh
d.sh
[root@xuexi ~]# cat d.sh
dirname $0
basename $0
[root@xuexi ~]# sh pwd
/d.sh
/root
d.sh
$n实例:
[root@xuexi ~]# cat d.sh
$1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15
[root@xuexi ~]# sh d.sh {a..z}
a b c d e f g h i j k l m n o
$#实例:
[root@xuexi ~]# cat d.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15}
echo $#
[root@xuexi ~]# sh d.sh {a..z}
a b c d e f g h i j k l m n o
26
[root@xuexi ~]# cat d.sh
[ $# -ne 2 ] && {
echo "muse two"
exit 1(1相当于赋值给$?)
}
echo "ok"
[root@xuexi ~]# sh d.sh qq
muse two
[root@xuexi ~]# 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
实例:
[root@xuexi ~]# 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
[root@xuexi ~]# sh if.sh
-rw-r--r--. 1 root root 43 Dec 7 19:11 /server/scripts/a.txt
内存小于100M发邮件报警实例:
[root@xuexi ~]# 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
实例:
[root@xuexi ~]# 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启动是否正常,启动了给个提示,没启动就用脚本启动实例:
[root@xuexi ~]# 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服务监控:
[root@xuexi ~]# 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:
[root@xuexi ~]# 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服务判断条件:
[root@xuexi ~]# lsof -i :80|wc -l(判断条件大于1即可)
7
[root@xuexi ~]# nmap 192.168.0.40 -p 80|grep open|wc -l(判断条件等于1即可)
1
[root@xuexi ~]# ps -ef|grep httpd|wc -l(判断条件大于2即可)
7
[root@xuexi ~]# curl -I -s 192.168.0.40|head -1|awk ‘{print $2}‘(判断条件等于200即可)
200
[root@xuexi ~]# wget --spider --timeout=3 --tries=2 192.168.0.40 &>/dev/null
[root@xuexi ~]# echo $?(判断条件等于0即可)
0
测试语句:
【语法说明】:
格式一:test<测试表达式>
格式二:[<测试表达式>]
格式三:[[<测试表达式>]]
说明
格式一和格式二是等价的
格式一实例:(可以man test了解详情)
[root@xuexi ~]# test -f file && echo "1" || echo 0
0
[root@xuexi ~]# test -f a.log && echo "1" || echo 0
1
加上!是非的意思;取反:
[root@xuexi ~]# test ! -f a.log && echo "1" || echo 0
0
[root@xuexi ~]# test ! -f file && echo "1" || echo 0
1
格式二实例:
[root@xuexi ~]# [ ! -f file ] && echo "1" || echo 0
1
[root@xuexi ~]# [ -f file ] && echo "1" || echo 0
0
[root@xuexi ~]# [ -f a.log ] && echo "1" || echo 0
1
[root@xuexi ~]# [ ! -f a.log ] && echo "1" || echo 0
0
格式三:实例:
[root@xuexi ~]# [[ ! -f a.log ]] && echo "1" || echo 0
0
[root@xuexi ~]# [[ -f a.log ]] && echo "1" || echo 0
1
[root@xuexi ~]# [[ -f file ]] && echo "1" || echo 0
0
[root@xuexi ~]# [[ ! -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) 字符串比较,比较符号两端最好都有空格,多参考系统脚本。
[root@xuexi ~]# sed -n ‘30,31p‘ /etc/init.d/network
[ "${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服务器是否正常:
Shell函数:
函数的作用:简单的说函数的作用就是把程序里多次调用的相同的代码的部分,定义成一份,然后起个名字,所有的调用都只用这个名字就可以了,修改代码时,只需要改变函数体内的泰马即可。
优势:
1) 把相同的程序段定义成函数,可以较少程序代码量。
2) 增加程序的可读,易读性。
3) 实现程序的功能模块化。
Shell函数语法:
语法格式:
简单的语法:
函数名(){
指令…
Return n
}
规范的语法:
Function 函数名(){
指令…..
Return n
}
Shell的执行方法:
1) 直接执行函数名:
函数名
注意:
a. 执行函数时,不要带小括号。
b. 函数定义及函数体必须在要执行的函数名前面定义,shell的执行从上到下按行执行的。
2) 带参数的函数执行方法:
函数名 参数1 参数2
函数带参数的说明:
1) 在函数体中位置变量($1,$2,$3,$#,$*,$?以及$@)都可以是函数的参数。
2) 父脚本的参数则临时地被函数参数所掩盖或隐藏。
3) $)比较特殊,它仍是父脚本的名称。
4) 当函数完成时,原来的命令行参数会恢复。
5) 在shell函数里面,return命令的功能与工作方式与exit相同,用于跳出函数。
6) 在shell函数里使用exit会终止整个shell脚本。
7) Return语句会返回一个退出值给调用的程序。
Mysql启动脚本实例:
[root@xuexi ~]# 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
当型循环和直到型循环:
ls
seq -w 10
seq -w 10
标签:网页程序 return语句 tchar 需要 win 控制语句 for语句 tree 方便
原文地址:http://blog.51cto.com/qingfeng00/2062262