shell脚本编程

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

转载于:https://my.oschina.net/u/3954059/blog/3018991

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值