什么是shell脚本,首先它是一个脚本,并不能作为正式的编程语言,说白了就是shell脚本就是一些命令的集合。
凡是自定义的脚本建议放到/usr/local/sbin/目录下,这样的好处是方便管理和维护,且利于以后交接给接替你的管理员。
shell脚本的结构
#cat first.sh
#! /bin/bash
## This is my first shell script.
date
echo "Hello world!"
脚本要以#! /bin/bash开头,代表的意思:该文件是使用的是bash语法,如果不使用该行也是可以的,但是如果把这个脚本放到一个默认shell并非bash的系统里,那么这个脚本很有可能是不能成功执行的。
还可以适当在脚本中使用#写一些脚本相关的注释内容,如作者、创建日期或者版本等。这些并不是shell脚本一定要的,只是为了统一管理,规范化。
shell脚本的几种执行方式
- fork:直接使用绝对路径来执行脚本,这种方式会启动一个子shell来执行脚本。
- source filename:在当前shell环境下,读取并执行filename中的命令。注:该命令可用命令“.”来替代,如:source .bash_rc 与 . .bash_rc 是等效的。
- exec 绝对路径:exec使用shell脚本的绝对路径在当前shell(shell会被重置到初始环境)下执行脚本,脚本执行完后会退出该shell。
- ./script启动一个子shell来执行脚本。
- sh|bash filename启动一个子shell读取并执行filename中的命令。
- 子shell的变量结果不会被带回父shell,所以要想通过脚本设置当前shell的环境变量时,要用source命令。
shell脚本执行方式 |
是否需要执行权限 |
原因 |
exec |
需要执行权限 |
由脚本主动调用shell来执行命令 |
fork或./ |
||
source或. |
无需执行权限 |
由shell主动读取脚本并执行 |
bash或sh |
使用sh命令执行一个脚本时,可以使用-x参数查看这个脚本的执行过程,在进行脚本调试时,有利于发现问题。
# sh -x first.sh
+ date
Fri Jan 822:28:23 CST 2016
+ echo ‘Hello world!‘
Hello world!
shell自定义变量
在shell脚本中定义变量,可以方便我们很方便的编辑、修改脚本,且使脚本变得简洁。
格式:变量名=值
shell数学运算
在shell中进行数学运算时,需要使用$[]括起来。
乘法运算:
# a=8;b=3;echo "$a*$b=$[$a*$b]"
8*3=24
除法运算
# a=8;b=3;echo "$a/$b=$[$a/$b]"
8/3=2
- 默认shell是不支持小数的。如果需要小数,则需要调用bc(linux 系统中的计算器)“yum –y install bc”
- bc不会进行四舍五入。
如果想要保留2位小树,可以这样实现。
# echo "scale=2;8/3"|bc
2.66
shell用户交互
shell脚本可以实现让用户输入一些字符串(read命令)或者让用户去选择(select语句)的行为。
read命令
# cat read.sh
#! /bin/bash
## Using ‘read‘ in shell script.
read -p "Please input a number: " x
read -p "Please input another number: " y
sum=$[$x+$y]
echo "The sum of the two numbers is: $sum"
read命令类似与visualbasic的input函数,作用是产生一个“输入行”,将用户输入的字符串赋值给read命令语句后的变量。
# sh read.sh
Please input a number: 2
Please input another number: 10
The sum of the two numbers is: 12
select语句
select 循环提供了一个简单的方法来创建一个编号的菜单,用户可从中选择。它是有用的,当你需要从列表中选择,要求用户选择一个或多个项目。
select 表达式是一种bash的扩展应用,动作包括:
l 自动用1,2,3,4列出菜单(没有echo指令,自动显示菜单)
l 自动read输入选择(没有 read指令,自动输入)
l 赋值给变量(没有赋值指令,自动输入数字后,赋值字符串给变量)
语法格式:
selectvariable in value1 value2 value3 …
do
command
done
例子:
# cat sel.sh
#! /bin/bash
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "FreeBSD" "Other"
do
break
done
echo "You have selected $var"
# sh sel.sh
What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 2
You have selected Gnu Hurd
- select本身就是一个循环,break就是当选择后,就跳出循环。
- 当变量内容含有空格时,应该将其用""括起来。
select一般和case语句结合使用,以上面一个例子为例,将它优化下:
# cat sel.sh
#! /bin/bash
echo "What is your favourite OS?"
select var in "Linux" "Gnu Hurd" "FreeBSD" "Other"
do
case $var in
Linux)
break;;
"Gnu Hurd")
break;;
"Free BSD")
break;;
Other)
break;;
*)
echo "Please enter anumber:(1-4)";;
esac
done
echo "You have selected $var"
- select虽然循环却在第一次选择之后不再显示菜单,只循环输入。
# sh sel.sh
What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 6
Please enter a number:(1-4)
#? 8
Please enter a number:(1-4)
#? 3
You have selected Free BSD
Shell脚本预设变量
# cat option.sh
#! /bin/bash
sum=$[$1+$2]
echo "$0$1"+"$2"="$sum"
# sh option.sh 2 3
option.sh 2+3=5
$0是脚本本身的名字,$1是执行脚本时跟的第一个参数,$2是执行时跟的第二个参数,$3是…当然一个shell脚本的预设变量是没有限制的。
if语句
if语句是逻辑判断语句。
if几种语法格式:
1) if 判断语句;then command;fi
2) if 判断语句;then command;else command;fi
3) if 判断语句
then
command
fi
4) if 判断语句
then
command
elif 判断语句
then
command
else
command
fi
例子
# cat if1.sh
#! /bin/bash
read -p "Please input your score: " a
if ((a<60)); then
echo "You didn‘tpass the exam."
Fi
if判断语句的相关内容
在进行数值关系运算时,除了可以使用(())的形式外,还可以使用[],但不能使用>,<,=,!=这些符号,要使用-lt(小于),-gt(大于),-le(大于等于),-ge(大于等于),-eq(等于),-ne(不等于)。
- 再使用[]时要注意空格。
例子
# cat if1.sh
#! /bin/bash
read -p "Please input your score: " a
if [ $a –lt60 ]; then
echo "You didn‘t pass theexam."
Fi
在判断语句中可以使用&&(并且)、||(或者)、!(非)
# a=10; if [ $a -lt 1 ] || [ $a -gt 5 ]; then echo OK; fi
OK
# a=5; if [ $a -gt 1 ] && [ $a -lt 10 ]; then echo OK; fi
OK
和文件相关的判断参数
- -e :判断文件或目录是否存在
- -d :判断是不是目录,并是否存在
- -f :判断是否是普通文件,并是否存在
- -r :判断文档是否有读权限
- -w :判断是否有写权限
- -x :判断是否可执行
例子:
# if [ -x/bin/bash ]; then echo ok; fi
ok
# if [ ! –x/bin/bash ];then chmod +x /bin/bash;fi
和变量相关的判断参数
- -n:判断变量是否不为空
- -z:判断变量是否为空
- ==或=:判断变量的值是否为指定值
- !=:判断变量的值是否非指定值
例子:
# a=;if [ -n "$a" ]; then echo "a is not null";else echo "a is null"; fi
# a=;if [ -z $a ]; then echo "a is null"; fi
a is null
判断条件也可以是一条命令
例子:
# if grep -q ‘^mysql:‘ /etc/passwd;then echo"user mysql exitst.";fi
user mysqlexitst.
- grep –q的作用是,过滤但不输出。
case选择语句
语法格式:
case 变量 in
value1 |value2)
command
;;
value3)
command
;;
value4)
command
;;
*)
command
;;
esac
- 上面的结构中,不限制 value 的个数,可以使用|匹配多个值,*则代表除了上面的 value 外的其他值。
例子:
# cat case.sh
#! /bin/bash
read -p "Input a number: " n
a=$[$n%2]
case $a in
1)
echo "The number isodd."
;;
0)
echo "The number iseven."
;;
*)
echo "It‘s not anumber!"
;;
esac
这是一个判断奇偶数的脚本,%在shell中是作为取余的符号。
for循环语句
for 变量名 in 循环的条件; do
command
done
这里的“循环的条件”可以写成一组字符串或者数字(用 1 个或者多个空格隔开), 也可以是一条命令的执行结果,注意要使用反单引号``.
# for i in 1 2 3 a b; do echo $i; done
1
2
3
A
B
# for i in `seq 1 5`; do echo $i;done
1
2
3
4
5
- seq命令:用于产生从某个数到另外一个数之间的所有整数
# seq 1 5
1
2
3
4
5
while循环语句
while循环语句常常用来编写死循环的脚本,用于监控某项服务。
语句格式:
while 循环条件;do
command
done
例子:
# cat while.sh
#! /bin/bash
a=5
while [ $a -ge 1 ]; do
echo $a
a=$[$a-1]
done
把循环条件用一个:(冒号)替代,这样可以做到死循环
# cat load.sh
#!/bin/bash
shu=1
while : ; do
load=`uptime|awk ‘{print$(NF-2)}‘|cut -d. -f1`
if [ $load -gt 10 ]&& [ $shu -le 4 ] ;then
echo "system load is high."|mail -s"system load" [email protected]
shu=$[$shu+1]
sleep 30
elif [ $shu -gt 4 ];then
shu=1
sleep 3600
else
shu=1
sleep 30
fi
done
这是一个监控系统负载的脚本。没30秒检测一次系统负载,如果负载值高于10时,向[email protected]发一封告警邮件,如果连续4次负载高于10时,则休眠1小时再继续执行脚本,以避免频繁发送邮件,对管理员造成骚扰(告警收敛)。
break、continue、exit
break:退出本层循环
continue:跳过接下来的语句,直接进入下一次循环
exit:退出当前shell
#!/bin/bash
for i in `seq 1 5`;do
echo $i
if [ $i== 3 ];then break ;fi
echo $i
done
echo aaaaaaa
# sh break.sh
1
1
2
2
3
aaaaaaa
#!/bin/bash
for i in `seq 1 5`;do
echo $i
if [ $i== 3 ];then continue ;fi
echo $i
done
echo aaaaaaa
# sh continue.sh
1
1
2
2
3
4
4
5
5
aaaaaaa
#!/bin/bash
for i in `seq 1 5`;do
echo $i
if [ $i== 3 ];then exit ;fi
echo $i
done
echo aaaaaaa
# sh exit.sh
1
1
2
2
3
shell函数
函数就是把一段代码整理到一个小单元中,并给这个小单元起一个名,当用到这段代码时,直接调用这个小单元的名字即可。
函数格式:
function_name() {
command
}
函数应定义在shell脚本的开头
# cat sum.sh
#! /bin/bash
sum() {
echo$1"+"$2"="$[$1+$2]
}
sum 3 4
# sh sum.sh
3+4=7
获取网卡名对应的IP:
# cat ip.sh
#!/bin/bash
ip() {
ifconfig |grep -A1"$1 " |tail -1 |awk ‘{print $2}‘|awk -F‘:‘ ‘{print $2}‘
}
read -p "Please input the eth name: " e
myip=`ip $e`
echo "$e address is $myip"
# sh ip.sh
Please input the eth name: lo
lo address is 127.0.0.1
shell数组
定义元素:
name[下标]=value
ü 下标从0开始
定义数组:
name=(value1value2 value3 …)
删除数组:
unset name
删除元素:
unset name[下标]
打印数组的所有元素:
echo${name[*]}或echo ${name[@]}
- 与打印变量不同,打印数值时需要使用${}将数组扩起来
打印数组:
echo${name[下标]}
打印第2个元素: echo ${a[1]}
打印数组的元素个数:
Echo${#name[@]} 或者 echo ${#a[*]}
数组分片:
echo${name[*]:下标x:下标y}
- 限制数组的打印范围,打印下标x到下标y之间的元素
数组替换:
echo ${name[@]/value1/value2}
- 更改数组的输出,将value1替换为value2
- name=(${name[@]}/value1/value2)也可以通过这种形式进行赋值