Shell
shell脚本介绍
- shell是一种脚本语言
- 可以使用逻辑判断、循环等语法
- 可以自定义函数
- shell是系统命令的集合
- shell脚本可以实现自动化运维,能大大增加我们的运维效率
shell脚本结构和执行
开头(首行)需要加:#!/bin/bash
这里是指文件使用的是bash语法,通过/bin/bash
解释器来执行的。
意思是指定命令解释器,由什么解释器来执行这个脚本,例如
bash
[root@shell scripts]> cat hellowald.sh
#!/bin/bash
echo 'hallo world'
以#开头的行作为解释说明,解释器不会去执行它。例如:
# cat hellowald.sh
#!/bin/bash
# this is test script
# Date:2018.07.28
# By hushuaiyang
echo 'hallo world'
脚本的文件名通常以 .sh 结尾,用于区分这个文件是一个 shell 脚本。
# ls
hellowald.sh
执行方法有两种
// 脚本执行前需要给脚本加上可执行权限
# chmod +x helloworld.sh
// 一种执行方法是使用相对路径或者绝对路径去执行
# ./helloworld.sh
hello world
# /root/scripts/hellowald.sh
hallo world
// 另一种方法是使用 bash 或者 sh 命令 来执行指定的脚本
# bash hellowald.sh
hallo world
# sh hellowald.sh
hallo world
// 第二种方法还可以查看脚本执行过程,和检查脚本是否有语法错误
# bash -x hellowald.sh //查看脚本执行的过程,
+ echo 'hallo world' // + 表示这一步所执行的命令,
hallo world // 这个就是命令的输出
// 检查语法错误 ,比如 if 语法不完整
# echo 'if [ 1 ] ; then echo 1;else echo 2;' >> hellowald.sh
# bash -n hellowald.sh
hellowald.sh: line 8: syntax error: unexpected end of file # 第8行有语法错误,未预期的文件结尾
// 如没有错误,就不会输出任何内容
date命令用法
date命令用于设置或者显示日期,在shell脚本里的大部分是对日志进行文件名的更改,和对一些文件做日期上的区分。
默认为显示系统当前时间
# date
2018年10月23日 星期二 17时18分39秒 CST
也可以指定输出格式
# date "+%Y-%m-%d"
2018-10-23
# 固定格式: date "+"
# + 后面跟指定的时间变量
# 常用的时间变量如下
%Y 表示年份,如:2018
%m 表示月份
%d 表示几号
%H 表示小时
%M 表示分钟
%S 表示秒:
%F = %Y-%m-%d
%T = %H:%M:%S
%s 表示时间戳, 1970年1月1日08点00分00秒到当前系统时间的总秒数
%w 表示周几。
%W 表示这一周是这一年的第几周
也可以输出指定的日期时间
// 这个需要用到date命令的 -d 选项
// 将指定的时间戳显示为具体的时间
# date -d @1532794220
Sun Jul 29 00:10:20 CST 2018
// 显示n天后
# date -d "+1 day"
Wed Oct 24 17:26:07 CST 2018
// 显示n天前
# date -d "-1 day"
Mon Oct 22 17:26:51 CST 2018
// 显示n个月前
# date -d "-1 month"
Sun Sep 23 17:27:10 CST 2018
// 显示n个月后
# date -d "+1 month"
Fri Nov 23 17:27:32 CST 2018
// 显示n小时前
# date -d "-1 hours"
Tue Oct 23 16:27:51 CST 2018
// 显示n分钟前
# date -d "-120 min" //120分钟前
Tue Oct 23 15:28:13 CST 2018
显示日历
# cal
October 2018
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
shell脚本中的变量
当脚本中使用某个字符串较频繁并且字符串长度很长时就应该使用变量代替
变量的定义方式
// 一般的变量定义方式: 变量名=值 等号两边不能有空格
// 调用变量的方式: $变量名 ,如果变量名后面还有字符最好加上{} 比如 ${a}bc
// 例如:
# cat 1.sh
#!/bin/bash
c=123
count=10
echo $c
echo $count
echo ${c}ount
# sh 1.sh
123
10
123ount
使用条件语句时,常使用变量
// 例如 :
if [ $a -gt 1 ]
then
echo $a
fi
引用某个命令的结果时,用变量替代
// 例如:
n=`wc -l /etc/profile`
echo $n
写和用户交互的脚本时,变量也是必不可少的
// 例如:
// read -p 可以读取用户在键盘中输入的值,然后赋值给一个变量名,还需要指定输入提示信息。
read -p "Input a number: " n # 如果没写这个n,调用变量时可以直接使用$REPLY 。
echo $n
echo $REPLY
Shell内置变量
# $0 表示脚本本身,也就是脚本文件的文件名
# $1 第一个参数,$2 第二个参数 .... 依次类推
# $# 表示参数个数
# $@ 表示所有参数
// 例如:
# cat 2.sh
#!/bin/bash
echo "$0"
echo "$1"
echo "$2"
echo "$#"
echo "$@"
# sh 2.sh p1 p2 p3 p4
2.sh
p1
p2
4
p1 p2 p3 p4
shell简单数学运算
# cat 2.sh
#!/bin/bash
a=5
b=6
echo "$(($a+$b))"
echo "$[$a*$b]"
echo "$[$a/$b]"
echo "$[$b-$a]"
echo "$[$b%$a]"
// 双括号和方括号的效果类似
# sh 2.sh
11
30
0
1
1
# 算术运算符
+、-、*、/、%、** # 加、减、乘、除、取余
++、-- # 自增,自减 ,用法$[++a] 或者 $[a++],++前置表示先运算再输出,++后置表示先输出再运算
# 比较运算符
<、<=、==、>=、>、!= # 小于、小于等于、相等与、大于等于、大于、不等于
# 逻辑运算符
!:取反 &&:逻辑与 ||:逻辑或 ~:按位取反 |:按位异或 &:按位与 ^:按位或
# 赋值运算符
=、+=、-=、*=、/=、%= # a=1 、a+=1相当于a=a+1,其他的运算符类似
shell脚本中的逻辑判断
// 格式1:if [ 条件 ] ; then 语句; fi
// 说明,条件需要使用方括号 [] 或者 双括号(()) 括起来
// 当使用方括号时,符号两边必须有空格,需要用特殊的判断语法,不能使用比较运算符,
# a=10
# if [ $a -eq 10 ] ; then echo $a; fi
10
// 双括号可以使用比较运算符,但不能使用特殊判断语法
# if (($a==10)) ; then echo $a; fi
10
// 格式2:if [ 条件 ]; then 语句1; else 语句2; fi
// 条件为真执行语句1,不为真就执行语句2
# if [ $a -gt 10 ] ; then echo $a ; else echo "NO"; fi
NO
// 格式3:if [ 条件1 ]; then 语句1 ;elif [ 条件2 ]; then 语句2; else 语句3; fi
// 如果条件1为真,执行语句1;
// 如果条件1不为真,判断条件2 ,条件2为真就执行语句2
// 条件1和条件2都不为真,则执行语句3,
# 可以有N个 elif 条件
// 例:
# cat 3.sh
#!/bin/bash
read -p "Input a: " a
read -p "Input b: " b
if [ $a -eq $b ]
then
echo "$a==$b"
elif [ $a -gt $b ]
then
echo "$a>$b"
else
echo "$a,$b"
fi
# sh 3.sh
Input a: 10
Input b: 10
10==10
# sh 3.sh
Input a: 20
Input b: 10
20>10
# sh 3.sh
Input a: 1
Input b: 2
1,2
// 可以使用 && || 结合多个条件
// [ 条件1 ] && [ 条件2 ] 需要条件1和条件2都为真才为真
// 例:
# cat 4.sh
#!/bin/bash
read -p "Input a: " a
read -p "Input b: " b
if [ $a -eq 10 ] && [ $b -eq $a ]
then
echo "YES"
else
echo "NO"
fi
# sh 4.sh
Input a: 10
Input b: 10
YES
# sh 4.sh
Input a: 10
Input b: 9
NO
# sh 4.sh
Input a: 9
Input b: 10
NO
// [ 条件1 ] || [ 条件2 ] 条件1 和 条件2 只要有一个为真就为真
// 例:
# cat 4.sh
#!/bin/bash
read -p "Input a: " a
read -p "Input b: " b
if [ $a -eq 10 ] || [ $b -eq $a ]
then
echo "YES"
else
echo "NO"
fi
[root@shell ~]> sh 4.sh
Input a: 10
Input b: 9
YES
# sh 4.sh
Input a: 9
Input b: 9
YES
# sh 4.sh
Input a: 9
Input b: 8
NO
// if的比较判断表达式
//数值判断
[ INT1 -eq INT2 ] INT1和INT2两数相等返回为真 , 相当于 =
[ INT1 -ne INT2 ] INT1和INT2两数不等返回为真 ,相当于 !=
[ INT1 -gt INT2 ] INT1大于INT2返回为真 ,相当于 >
[ INT1 -ge INT2 ] INT1大于等于INT2返回为真,相当于 >=
[ INT1 -lt INT2 ] INT1小于INT2返回为真 ,相当于 <
[ INT1 -le INT2 ] INT1小于等于INT2返回为真,相当于 <=
// 字符串判断
[ -z STRING ] 如果STRING的长度为零则返回为真,即空是真
[ -n STRING ] 如果STRING的长度非零则返回为真,即非空是真
[ STRING1 ] 如果字符串不为空则返回为真,与-n类似
[ STRING1 == STRING2 ] 如果两个字符串相同则返回为真
[ STRING1 != STRING2 ] 如果字符串不相同则返回为真
[ STRING1 < STRING2 ] 如果 “STRING1”字典排序在“STRING2”前面则返回为真。
[ STRING1 > STRING2 ] 如果 “STRING1”字典排序在“STRING2”后面则返回为真。
文件目录属性判断
// [ -f file ]判断是否是普通文件,且存在
// 例:
# if [ -f ./3.sh ];then echo 'YES';fi
YES
// [ -d file ] 判断是否是目录,且存在
// 例:
# if [ -d /root ];then echo "YES";fi
YES
// [ -e file ] 判断文件或目录是否存在
// 例:
# if [ -e /rfdsa ] || [ ./1.sh ];then echo "YES";fi
YES
// [ -r file ] 判断文件是否可读 ,可读为真(注:只相对于普通用户来说)
# if [ -r ./3.sh ];then echo "YES";else echo "NO";fi
YES
// [ -w file ] 判断文件是否可写 ,可写为真(注:只相对于普通用户来说)
# if [ -w ./3.sh ];then echo "YES";else echo "NO";fi
YES
// [ -x file ] 判断文件是否可执行,可执行为真 (注:只相对于普通用户来说)
# if [ -x ./3.sh ];then echo "YES";else echo "NO";fi
YES
if特殊用法
// if [ -z "$a" ] 判断变量a是否为空,变量为空时表达式为真
# echo "$b"
# if [ -z $b ];then echo "b is Null";fi
b is Null
// if [ -n "$a" ] 表示当变量a的值不为空,不为空时表达式为真
# if [ -n $a ];then echo $a;fi
1
// if grep -q '123' 1.txt; 判断文件中是否包含指定的字符串,有包含为真
# echo 'abc' > 1.txt
# if grep 'd' 1.txt ;then echo YES;else echo "NO"; fi
NO
// if [ ! -e file ]; 判断用户是否存在, 不存在为真
# if [ ! -e ./fdsa ];then echo NO;fi
NO
case判断
// 格式:
case $a in
value1) # 当a的值是value1时,执行command_1
command1
;; # ;; 两个分号表示一个条件所执行语句的结尾
value2) # 当a的值是value2时,执行command_2
command2
;;
*) # 当a不满足前面任何一个条件时,执行command_3
commond3
;;
esac
// 例:
# cat 5.sh
#!/bin/bash
case $1 in
1)
echo "command_1"
;;
2)
echo "command_2"
;;
3)
echo "command_3"
;;
*)
echo "eommand4"
;;
esac
# vim 5.sh
# sh 5.sh 1
command_1
# sh 5.sh 2
command_2
# sh 5.sh 6
eommand4
# sh 5.sh fdsa
eommand4
// 在case程序中,还可以在条件中使用 | ,表示或的意思, 比如
# cat 5.sh
#!/bin/bash
case $1 in
1|2)
echo "command_1"
;;
*)
echo "eommand4"
;;
esac
# sh 5.sh 1
command_1
# sh 5.sh 2
command_1
for循环
// 语法格式:for 变量名 in 条件; do …; done
// 案例1:久久乘法表
# cat jiujiu.sh
#!/bin/bash
for i in `seq 1 9`
do
for j in `seq 1 $i`
do
echo -ne "$i*$j=$(($i*$j))\t"
done
echo
done
[root@shell scripts]> sh jiujiu.sh
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
4*1=4 4*2=8 4*3=12 4*4=16
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
// 案例2:统计系统所有进程占用内存的总和
# cat 6.sh
#!/bin/bash
sum=0
for mem in `ps -aux | awk '{print $6}' | grep -v "RSS"`
do
sum=$(($sum+$mem))
done
echo $(($sum/1000))MB
# sh 6.sh
140MB
while循环
// 语法格式: while 条件; do … ; done
// 例:
while :;do echo 1;done # 这样写会无限的输出1 // while : 这里的冒号就是为真的意思,无限循环
// 条件表达式,与if的表达式类似
[root@shell etc]> a=0
[root@shell etc]> while (($a<=5)) ;do echo $((a++));done
0
1
2
3
4
5
break退出循环
// break 当达到某个条件时使用break可以退出这个循环,但是循环语句后面的语句还会继续执行
// 例:
[root@shell etc]> a=0
[root@shell etc]> while (($a<=5));do echo $((a++));if [ $a -eq 3 ];then break;fi;done;echo OK
0
1
2
OK
// 上面的语句意思是当 a 等于 3 时就退出循环, 最后还执行了 echo OK
continue跳过本次循环
// continue的作用是跳过本次循环,继续进行下一个循环
// 例:当 a 等于 4 的时候,跳过这一次循环
[root@shell etc]> a=0
[root@shell etc]> while ((++a<=5));do if [ $a -eq 4 ];then continue;fi;echo $a;done
1
2
3
5
exit退出整个脚本
// 当在脚本中执行 exit 命令后就会直接退出整个脚本,不再执行脚本中任何语句
// 例: 当 示例中 i 等于 5 的时候,退出脚本,
# cat 7.sh
#!/bin/bash
for i in `seq 1 10`
do
if [ $i -eq 5 ]
then
exit
fi
echo $i
done
echo 'OK'
# sh 7.sh
1
2
3
4
// 注意最后没有执行 echo 'OK'