shell是什么
shell是一种脚本语言
可以使用逻辑判断、循环等语法
可以自定义函数
shell是系统命令的集合
shell脚本可以实现自动化运维,能大大增加我们的运维效率
shell脚本结构和执行
开头需要加#!/bin/bash
以#开头的行作为解释说明
脚本的名字以.sh结尾,用于区分这是一个shell脚本
执行方法有两种
chmod +x 1.sh; ./1.sh
bash 1.sh
查看脚本执行过程 bash -x 1.sh
查看脚本是否语法错误 bash -n 1.sh
测试:
[root@wangzb02 ~]# vim 1.sh 创建1.sh脚本,增加内容
#!/bin/bash
touch /tmp/1.txt
chmod 600 /tmp/1.txt
mv /tmp/1.txt /tmp/2.txt
[root@wangzb02 ~]# ./1.sh
-bash: ./1.sh: 权限不够
[root@wangzb02 ~]# chmod 755 1.sh
[root@wangzb02 ~]# bash 1.sh
[root@wangzb02 ~]# bash -x 1.sh
+ touch /tmp/1.txt
+ chmod 600 /tmp/1.txt
+ mv /tmp/1.txt /tmp/2.txt
补充:
以树形查看服务
[root@wangzb02 ~]# yum install -y psmisc
[root@wangzb02 ~]# pstree //可以看到
systemd─┬─NetworkManager─┬─dhclient
│ └─2*[{NetworkManager}]
├─VGAuthService
├─agetty
├─auditd───{auditd}
├─chronyd
├─crond
├─dbus-daemon
├─irqbalance
├─master─┬─pickup
│ └─qmgr
├─nginx───nginx
├─polkitd───6*[{polkitd}]
├─rsyslogd───2*[{rsyslogd}]
├─sshd───sshd───bash───pstree
├─systemd-journal
├─systemd-logind
├─systemd-udevd
├─tuned───4*[{tuned}]
├─vmtoolsd───{vmtoolsd}
└─zabbix_agentd───5*[zabbix_agentd]
date命令
date +%Y-%m-%d, date +%y-%m-%d 年月日
date +%H:%M:%S = date +%T 时间
date +%s 时间戳
date -d @1504620492
date -d "+1day" 一天后
date -d "-1 day" 一天前
date -d "-1 month" 一月前
date -d "-1 min" 一分钟前
date +%w, date +%W 星期
测试:
[root@wangzb02 ~]# date
2019年 03月 06日 星期三 22:45:06 CST
[root@wangzb02 ~]# date +%Y-%m-%d
2019-03-06
[root@wangzb02 ~]# date +%y-%m-%d
19-03-06
[root@wangzb02 ~]# date +%H:%M:%S
22:43:43
[root@wangzb02 ~]# date +%T
22:43:52
[root@wangzb02 ~]# date +%s
1551883442
[root@wangzb02 ~]# date -d @1504620492
2017年 09月 05日 星期二 22:08:12 CST
[root@wangzb02 ~]# date -d "+1day"
2019年 03月 07日 星期四 22:44:24 CST
[root@wangzb02 ~]# date -d "-1 day"
2019年 03月 05日 星期二 22:44:34 CST
[root@wangzb02 ~]# date -d "-1 month"
2019年 02月 06日 星期三 22:44:45 CST
[root@wangzb02 ~]# date +%w
3
[root@wangzb02 ~]# date +%W
09
[root@wangzb02 ~]# date -d @123123123
1973年 11月 26日 星期一 08:52:03 CST
[root@wangzb02 ~]# date -d "-1hour"
2019年 03月 06日 星期三 21:50:30 CST
shell脚本中的变量
当脚本中使用某个字符串较频繁并且字符串长度很长时就应该使用变量代替
使用条件语句时,常使用变量 if [ $a -gt 1 ]; then ... ; fi
引用某个命令的结果时,用变量替代 n=`wc -l 1.txt`
写和用户交互的脚本时,变量也是必不可少的
read -p "Input a number: " n; echo $n 如果没写这个n,可以直接使用$REPLY
[root@wangzb01 ~]# a=`date +%w`
[root@wangzb01 ~]# echo $a
4
[root@wangzb01 ~]# a=$(date +%w)
[root@wangzb01 ~]# echo $a
4
[root@wangzb01 ~]# read -p "请输入一个数字n:" n
请输入一个数字n:10
[root@wangzb01 ~]# echo $n
10
[root@wangzb01 ~]# read -p "请输入一个数字n:"
请输入一个数字n:2312
[root@wangzb01 ~]# echo $REPLY
2312
内置变量 $0, $1, $2… $0表示脚本本身,$1 第一个参数,$2 第二个 .... $#表示参数个数
[root@wangzb01 ~]# vim 1.sh //增加内容:
#!/bin/bash
echo "\$1=$1"
echo "第二个参数是$2"
echo "第三个参数是$3"
echo "本脚本一共有$#个参数"
echo "\$0参数是$0"
[root@wangzb01 ~]# sh 1.sh aa bb cc dd ee
$1=aa
第二个参数是bb
第三个参数是cc
本脚本一共有5个参数
$0参数是1.sh
[root@wangzb01 ~]# sh /root/1.sh aa bb cc dd ee
$1=aa
第二个参数是bb
第三个参数是cc
本脚本一共有5个参数
$0参数是/root/1.sh
数学运算a=1;b=2; c=$(($a+$b))或者$[$a+$b]
说明:
\ :脱义字符
$# :shell的内置变量,表示参数个数
$0 :表示shell脚本本身
$REPLY : shell内置变量
shell中的逻辑判断
格式1:if 条件 ; then 语句; fi
格式2:if 条件; then 语句; else 语句; fi
格式3:if …; then … ;elif …; then …; else …; fi
逻辑判断表达式:if [ $a -gt $b ]; if [ $a -lt 5 ]; if [ $b -eq 10 ]等 -gt (>); -lt(<); -ge(>=); -le(<=);-eq(==); -ne(!=) 注意到处都是空格
可以使用 && || 结合多个条件
if [ $a -gt 5 ] && [ $a -lt 10 ]; then
if [ $b -gt 5 ] || [ $b -lt 3 ]; then
if [ $a -gt 5 ] && [ $a -lt 10 ] == [ $a -gt 5 -a $a -lt 10 ]
if [ $a -gt 5 ] || [ $a -lt 10 ] == [ $a -gt 5 -o $a -lt 10 ]
if 判断文件、目录属性
[ -f file ]判断是否是普通文件,且存在
[ -d file ] 判断是否是目录,且存在
[ -e file ] 判断文件或目录是否存在
[ -r file ] 判断文件是否可读
[ -w file ] 判断文件是否可写
[ -x file ] 判断文件是否可执行
注:root用户对文件的读写比较特殊,即使一个文件没有给root用户读或者写的权限,root用户照样可以读或者写
if判断的一些特殊用法
if [ -z "$a" ] 这个表示当变量a的值为空时会怎么样
if [ -n "$a" ] 表示当变量a的值不为空
if grep -q '123' 1.txt; then 表示如果1.txt中含有'123'的行时会怎么样
if [ ! -e file ]; then 表示文件不存在时会怎么样
if (($a<1)); then …等同于 if [ $a -lt 1 ]; then…
[ ] 中不能使用<,>,==,!=,>=,<=这样的符号
shell中的case判断
格式 case 变量名 in value1)
command
;; value2)
command
;; *)
commond ;;
esac
在case程序中,可以在条件中使用|,表示或的意思, 比如
2|3)
command
;;
案例:
[root@wangzb01 shelltest]# vim case1.sh //增加内容
#!/bin/bash
read -p "Please input a number: " n
if [ -z "$n" ]
then
echo "Please input a number."
exit 1
fi
n1=`echo $n|sed 's/[0-9]//g'`
if [ -n "$n1" ]
then
echo "Please input a number."
exit 1
fi
if [ $n -lt 60 ] && [ $n -ge 0 ]
then
tag=1
elif [ $n -ge 60 ] && [ $n -lt 80 ]
then
tag=2
elif [ $n -ge 80 ] && [ $n -lt 90 ]
then
tag=3
elif [ $n -ge 90 ] && [ $n -le 100 ]
then
tag=4
else
tag=0
fi
case $tag in
1)
echo "not ok"
;;
2)
echo "ok"
;;
3)
echo "ook"
;;
4)
echo "oook"
;;
*)
echo "The number range is 0-100."
;;
esac
输出结果:
[root@wangzb01 shelltest]# sh -x case1.sh
+ read -p 'Please input a number: ' n
Please input a number: 25
+ '[' -z 25 ']'
++ echo 25
++ sed 's/[0-9]//g'
+ n1=
+ '[' -n '' ']'
+ '[' 25 -lt 60 ']'
+ '[' 25 -ge 0 ']'
+ tag=1
+ case $tag in
+ echo 'not ok'
not ok
[root@wangzb01 shelltest]# sh -x case1.sh
+ read -p 'Please input a number: ' n
Please input a number: 500
+ '[' -z 500 ']'
++ sed 's/[0-9]//g'
++ echo 500
+ n1=
+ '[' -n '' ']'
+ '[' 500 -lt 60 ']'
+ '[' 500 -ge 60 ']'
+ '[' 500 -lt 80 ']'
for循环
语法:for 变量名 in 条件; do …; done
案例1
#!/bin/bash
sum=0
for i in `seq 1 100`
do
sum=$[$sum+$i]
echo $i
done
echo $sum
文件列表循环
#!/bin/bash
cd /etc/
for a in `ls /etc/`
do
if [ -d $a ]
then
ls -d $a
fi
done
while循环
语法 while 条件; do … ; done
案例1
#!/bin/bash
while : //冒号 : 表示死循环的意思,或者1,或者 true都是死循环
do
load=`w|head -1|awk -F 'load average: ' '{print $2}'|cut -d. -f1`
if [ $load -gt 10 ]
then
top|mail -s "load is high: $load" asldkfls@11.com
fi
sleep 5 //#休眠5秒,因为检查系统负载,不需要一直去检查,过一会再看
done
执行结果:
[root@wangzb01 shelltest]# sh -x while1.sh
+ :
++ w
++ head -1
++ awk -F 'load average: ' '{print $2}'
++ cut -d. -f1
+ load=0
+ '[' 0 -gt 10 ']'
+ sleep 5
+ :
++ w
++ cut -d. -f1
++ awk -F 'load average: ' '{print $2}'
++ head -1
+ load=0
+ '[' 0 -gt 10 ']'
+ sleep 5
案例2
[root@wangzb01 shelltest]# vim while2.sh
#!/bin/bash
while :
do
read -p "Please input a number: " n
if [ -z "$n" ]
then
echo "you need input sth."
continue //continue 重新回到循环
fi
n1=`echo $n|sed 's/[0-9]//g'`
if [ -n "$n1" ]
then
echo "you just only input numbers."
continue
fi
break //break 退出循环
done
echo $n
执行脚本:
[root@wangzb01 shelltest]# sh -x while2.sh
+ :
+ read -p 'Please input a number: ' n
Please input a number: abc
+ '[' -z abc ']'
++ echo abc
++ sed 's/[0-9]//g'
+ n1=abc
+ '[' -n abc ']'
+ echo 'you just only input numbers.'
you just only input numbers.
+ continue
+ :
+ read -p 'Please input a number: ' n
Please input a number: ad1
+ '[' -z ad1 ']'
++ echo ad1
++ sed 's/[0-9]//g'
+ n1=ad
+ '[' -n ad ']'
+ echo 'you just only input numbers.'
you just only input numbers.
+ continue
+ :
+ read -p 'Please input a number: ' n
Please input a number: 11111
+ '[' -z 11111 ']'
++ echo 11111
++ sed 's/[0-9]//g'
+ n1=
+ '[' -n '' ']'
+ break
+ echo 11111
11111
[root@wangzb01 shelltest]# sh while2.sh
Please input a number: abc
you just only input numbers.
Please input a number: abc123
you just only input numbers.
Please input a number: 111111
111111
break跳出循环
#!/bin/bash
for i in `seq 1 5`
do
echo $i
if [ $i == 3 ]
then
break
fi
echo $i
done
echo aaaaaaa
执行结果:
[root@wangzb01 shelltest]# sh break1.sh
1
1
2
2
3
aaaaaaa
[root@wangzb01 shelltest]# sh -x break1.sh
++ seq 1 5
+ for i in '`seq 1 5`'
+ echo 1
1
+ '[' 1 == 3 ']'
+ echo 1
1
+ for i in '`seq 1 5`'
+ echo 2
2
+ '[' 2 == 3 ']'
+ echo 2
2
+ for i in '`seq 1 5`'
+ echo 3
3
+ '[' 3 == 3 ']'
+ break
+ echo aaaaaaa
aaaaaaa
continue结束本次循环
忽略continue之下的代码,直接进行下一次循环
[root@wangzb01 shelltest]# vim continue.sh
#!/bin/bash
for i in `seq 1 5`
do
echo $i
if [ $i == 3 ]
then
continue
fi
echo $i
done
echo $i
[root@wangzb01 shelltest]# sh continue.sh
1
1
2
2
3
4
4
5
5
5
exit直接退出脚本
#!/bin/bash
for i in `seq 1 5`
do
echo $i
if [ $i == 3 ]
then
exit
fi
echo $i
done
echo aaaaaaa
执行结果:
[root@wangzb01 shelltest]# sh -x exit1.sh
++ seq 1 5
+ for i in '`seq 1 5`'
+ echo 1
1
+ '[' 1 == 3 ']'
+ echo 1
1
+ for i in '`seq 1 5`'
+ echo 2
2
+ '[' 2 == 3 ']'
+ echo 2
2
+ for i in '`seq 1 5`'
+ echo 3
3
+ '[' 3 == 3 ']'
+ exit
[root@wangzb01 shelltest]# cp /etc/passwd ./test
[root@wangzb01 shelltest]# for line in `cat test`;do echo $line ; echo "#####"; done
root:x:0:0:root:/root:/bin/bash
#####
bin:x:1:1:bin:/bin:/sbin/nologin
#####
daemon:x:2:2:daemon:/sbin:/sbin/nologin
#####
adm:x:3:4:adm:/var/adm:/sbin/nologin
#####
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
#####
sync:x:5:0:sync:/sbin:/bin/sync
#####
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
#####
halt:x:7:0:halt:/sbin:/sbin/halt
#####
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
#####
operator:x:11:0:operator:/root:/sbin/nologin
#####
games:x:12:100:games:/usr/games:/sbin/nologin
#####
ftp:x:14:50:FTP
#####
User:/var/ftp:/sbin/nologin
#####
nobody:x:99:99:Nobody:/:/sbin/nologin
#####
systemd-network:x:192:192:systemd
#####
Network
采用for循环到后面输出的行出现问题,原因是行中间有空格。下面可以使用while循环的方式来实现,空格就不会有影响了
[root@wangzb01 shelltest]# cat test | while read line; do echo $line ; echo "######"; doneroot:x:0:0:root:/root:/bin/bash
######
bin:x:1:1:bin:/bin:/sbin/nologin
######
daemon:x:2:2:daemon:/sbin:/sbin/nologin
######
adm:x:3:4:adm:/var/adm:/sbin/nologin
######
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
######
sync:x:5:0:sync:/sbin:/bin/sync
######
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
######
halt:x:7:0:halt:/sbin:/sbin/halt
######
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
######
operator:x:11:0:operator:/root:/sbin/nologin
######
games:x:12:100:games:/usr/games:/sbin/nologin
######
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
######
nobody:x:99:99:Nobody:/:/sbin/nologin
######
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
######
dbus:x:81:81:System message bus:/:/sbin/nologin
######
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
######
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
######
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
shell脚本中的函数
函数就是把一段代码整理到了一个小单元中,并给这个小单元起一个名字,当用到这段代码时直接调用这个小单元的名字即可。
格式:
function f_name()
{
command
}
函数必须要放在最前面
示例1
#!/bin/bash
input() {
echo $1 $2 $# $0
}
input 1 a b
执行结果:
[root@wangzb01 shelltest]# sh function01.sh
1 a 3 function01.sh
[root@wangzb01 shelltest]# sh -x function01.sh
+ input 1 a b
+ echo 1 a 3 function01.sh
1 a 3 function01.sh
示例2
#!/bin/bash
sum() {
s=$[$1+$2]
echo $s
}
sum 1 2
执行结果:
[root@wangzb01 shelltest]# sh function02.sh
3
[root@wangzb01 shelltest]# sh -x function02.sh
+ sum 1 2
+ s=3
+ echo 3
3
示例3
#!/bin/bash
ip()
{
ifconfig |grep -A1 "$1: " |tail -1 |awk '{print $2}'
}
read -p "Please input the eth name: " e
myip=`ip $e`
echo "$e address is $myip"
执行结果:
[root@wangzb01 shelltest]# sh function03.sh
Please input the eth name: ens33
ens33 address is 192.168.153.133
[root@wangzb01 shelltest]# sh -x function03.sh
+ read -p 'Please input the eth name: ' e
Please input the eth name: ens33
++ ip ens33
++ ifconfig
++ tail -1
++ grep -A1 'ens33: '
++ awk '{print $2}'
+ myip=192.168.153.133
+ echo 'ens33 address is 192.168.153.133'
ens33 address is 192.168.153.133
shell中的数组
定义数组 a=(1 2 3 4 5); echo ${a[@]}
echo ${#a[@]} 获取数组的元素个数
echo ${a[2]} 读取第三个元素,数组从0开始
echo ${a[*]} 等同于 ${a[@]} 显示整个数组
案例测试:
[root@wangzb01 shelltest]# a=(1 2 a b c)
[root@wangzb01 shelltest]# echo ${a[@]}
1 2 a b c
[root@wangzb01 shelltest]# echo ${a[1]}
2
[root@wangzb01 shelltest]# echo ${a[2]}
a
[root@wangzb01 shelltest]# echo ${#a[@]}
5
[root@wangzb01 shelltest]# echo ${a[*]}
1 2 a b c
数组赋值
a[1]=100; echo ${a[@]}
a[5]=2; echo ${a[@]} 如果下标不存在则会自动添加一个元素
案例测试:
[root@wangzb01 shelltest]# a[5]=aaa
[root@wangzb01 shelltest]# a[8]=bbb
[root@wangzb01 shelltest]# echo ${a[*]} //此处a[5]、a[6]、a[7]没有赋值,是空值
1 2 a b c aaa bbb
[root@wangzb01 shelltest]# echo ${#a[*]}
7
数组的删除
unset a; unset a[1]
案例测试:
[root@wangzb01 shelltest]# unset a[8]
[root@wangzb01 shelltest]# echo ${a[@]}
1 2 a b c aaa
[root@wangzb01 shelltest]# echo ${#a[@]}
6
数组分片
a=(`seq 1 5`)
echo ${a[@]:0:3} 从第一个元素开始,截取3个
echo ${a[@]:1:4} 从第二个元素开始,截取4个
echo ${a[@]:0-3:2} 从倒数第3个元素开始,截取2个
案例测试:
[root@wangzb01 shelltest]# echo ${a[@]} //查询所有
1 2 a b c aaa
[root@wangzb01 shelltest]# echo ${a[@]:0:2} //从第一个参数开始,取两个参数
1 2
[root@wangzb01 shelltest]# echo ${a[@]:1:5} //从第二个参数开始,取5个参数
2 a b c aaa
[root@wangzb01 shelltest]# echo ${a[@]:0-3:3} //从倒数第三个参数开始,取三个参数
b c aaa
数组替换
echo ${a[@]/3/100}
a=(${a[@]/3/100})
案例测试:
[root@wangzb01 shelltest]# echo ${a[@]/b/100} //将值b替换为100并打印到桌面,此时并没有保存数组替换后的值
1 2 a 100 c aaa
[root@wangzb01 shelltest]# echo ${a[@]} //上一步并未赋值,因此数组没有变化
1 2 a b c aaa
[root@wangzb01 shelltest]# a=(${a[@]/b/100}) //替换重新赋值给a[@]
[root@wangzb01 shelltest]# echo ${a[@]} //打印重新赋值后的数组
1 2 a 100 c aaa