avatar

4.Shell 编程总结

Shell 编程总结

第1章 基础知识

1.linux下默认的shell是?

1
bash

2.shell脚本书写规范?

1.shell脚本存放统一的目录 /server/scripts

2.脚本名字的结尾使用.sh

3.脚本的开头 必须有解释器 #!/bin/bash

4.脚本内有作者信息 脚本信息

1
2
3
4
5
#Date: 20111111
#Author: wufei
#Blog: #博客
#Descriptsion: #描述
#Version: 1.0 #版本

5.每段代码块有注释(尽量使用英文)

6.标点符号 (语法尽量一次性书写完毕

7.成对的符号 一次性书写完毕

3.执行脚本的三种方法?

1
2
3
4
5
6
7
8
9
10
#方法1:直接使用解释器执行
[root@backup /server/scripts]# bash hello.sh
hello world!
#方法2: 全路径方式执行 需要执行权限
# chmod +x hello.sh
[root@backup ~]# . /server/scripts/hello.sh
hello world!
#方法3 source .执行脚本 子shell中的内容调用到父shell中执行
[root@backup /server/scripts]# source hello.sh
hello world!

4.变量可分为两类?

变量可分为两类:环境变量(全局变量)和普通变量(局部变量)

全局变量(环境变量) 针对系统所有用户生效

局部变量(普通变量) 针对当前登录用户生效

5.如何显示默认的环境变量**

1.使用echo命令查看单个环境变量。例如: echo $PATH

2.使用env查看所有环境变量。例如: env

3.使用set查看所有本地定义的环境变量。

6.如何设置环境变量与局部变量

1.在/etc/profile文件中添加变量【对所有用户生效(永久的)】,注意:修改文件后要想马上生效还要运行# source /etc/profile不然只能在下次重进此用户时生效。

2.在用户目录下的.bash_profile文件中增加变量【对单一用户生效(永久的)】

3.直接运行export命令定义变量【只对当前shell(BASH)有效(临时的)】

7.定义变量内容,不加引号、单引号、双引号、反引号结果有什么不同?应该怎么用?

不加引号:直接定义变量的内容,一般用于连续的数字、字符串、路径名等

单引号:所见即所得,引号内是什么就输出什么

双引号:输出变量内容时引号的变量及命令会经过解析后再输出内容

反引号:一般用于引用命令,执行的时候命令会被执行,相当于S0,赋值和输出都要用引号将命令引起来

8.以下参数含义

参数 含义
$0 获取当前执行的shell脚本的文件名,如果包含路径,则包括脚本路径
$n 获取当前执行脚本的第n个参数值,参数从$1开始 $9 以后需要加{}
$# 获取当前执行的脚本后面接的参数的总个数
$* 脚本所有传参的参数,加双引号将所有参数视为一个整体
$@ 脚本所有传参的参数,加双引号将所有参数视为不通的独立字符串
$? 上一个指令的状态返回值(0为成功,非0失败)
$$ 当前执行脚本的PID进程号
$! 上一个在后台工作的进程的PID
$_ 获取在此之前的命令或脚本的最后一个参数

9.echo参数含义

参数 含义
-n 不换行输出内容
-e 解析转义字符
转义字符
\n 换行
\r 回车
\t 制表符(tab)
\b 退格
\v 纵向制表符

10.变量传参的三种方式?

1.直接传参

2.赋值传参

3.read传参

11.统计字符串长度?

1
2
3
4
5
6
7
8
9
10
# echo $test
I am oldboy
# echo ${#test} #变量前加#可以打印变量的长度
11
# echo $test|wc -L
11
# expr length "$test"
11
# echo $test|awk '{print length}'
11

12.输出字符串长度小于3的单词

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
[root@backup /server/scripts]# cat for.sh 
#!/bin/bash
for i in I am lizhenya teacher I am 18
do
[ ${#i} -lt 3 ] && echo $i
done
[root@backup /server/scripts]# sh for.sh
I
am
I
am
18

[root@backup /server/scripts]# echo "I am lizhenya teacher I am 18"|xargs -n1|awk '{if(length<3)print}'
I
am
I
am
18

[root@backup /server/scripts]# echo "I am lizhenya teacher I am 18"|xargs -n1|awk '{for(i=1;i<=NF;i++)if(length<3)print}'
I
am
I
am
18

13.变量子串的删除和替换

1
2
3
4
5
6
7
8
9
#截取从第二个字符之后的内容,不包含第二个字符
[root@backup /server/scripts]# echo $test
I am oldboy
[root@backup /server/scripts]#
[root@backup /server/scripts]# echo ${test:2}
am oldboy
#从第二个字符开始截取之后的二个字符
[root@backup /server/scripts]# echo ${test:2:2}
am

14.写出下面特殊变量扩展的意义

1
2
3
4
5
6
${oldboy}	   #返回变量$oldboy的内容
${#oldboy} #返回变量$oldboy的内容的字符长度
${url#*.} #从.开始删除前面的内容输出
${url##*.} #从.开始删除最后一个.后面的内容输出
${url%.*} #删除最后一个.后面的内容输出
${url%%.*} #删除第一个.后面的内容输出

15.常见的Shell算术运算符

算术运算符 意义(*表示常用)
+ 、- 加(或正号)、减(或负号)*
*、/、% 乘法、除法、取余 *
** 冥运算 *
++ 、– 增加、减少,可前置也可放在变量的结尾 *
!、&&、|| 非(取反)、相当于and 、相当于or *
< 、<= 、> 、>= 比较符号(小于、小于等于、大于、大于等于)
== 、!= 、= 比较符号 (相等、不相等、对于字符串=也可表示相当于)*
<< 、>> 向左移位、向右移位
~ 、| 、& 、^ 按位取反、按位异或、按位于、按位或
= 、+=、-= 、*= 、%= 赋值运算符,例如 a+=1 相当于 a=a+1 , a-=1 相当于 a=a-1 *

16.常见的运算命令

运算操作符号与运算命令 意义
(()) 用于整数的运算、效率很高
let 用于证书运算,类似于(())
expr 可用于整数运算,还有其他功能
bc Linux下的计算程序、可用于整数及小数运算
$[] 用于整数运算
awk awk既可用于整数运算,也可用于小数运算
declare 定义变量值和属性,-i参数可用于定义整形变量,做运算

17.常用的条件表达式

语法 意义
test -f file 表示如果file文件存在,则为真(0),否则为假(非0)
test -z 表示如果字符串长度是为0,则表达式成立
[ -e file ] 文件存在则为真
[ -f file ] 是否存在并且为普通文件
[ -d file ] 是否为目录
[ -r file ] 是否可读
[ -w file ] 是否可写
[ -x file ] 是否可执行

18.数值表达式

[ 整数1 比较符 整数2 ]

在[]以及test 中使用的比较符号 在(())和[[]] 中使用的比较符号 说明
-eq == 或 = 等于
-ne != 不等于
-gt > 大于
-ge >= 大于等于
-lt < 小于
-le <= 小于等于

19.循环控制及状态返回值参数

参数 含义
exit 退出脚本
return 退出函数
local 局部变量
breadk 跳出循环体
continue 跳过本次循环,进行下一次循环

第2章 脚本案例

1.查看磁盘/当前使用状态,如果使用率超过80%则把结果输出

1
2
3
4
#!/bin/sh
usedisk=`df -h|awk 'NR==2{print $(NF-1)}'`
[ ${usedisk%\%} -gt 80 ] && echo "send mail 当前使用为$usedisk" || echo "磁盘使用正常,当前使用率为$usedisk"
[ `df -h|awk -F "[ %]+" 'NR==2{print $(NF-1)}'` -gt 5 ] && echo "send mail" || echo "磁盘使用正常"

统计磁盘使用率 如果磁盘使用率大于 5% 则发邮件报警 当前使用率为? 小于5% 则提示磁盘使用正常 当前使用率为?

1
2
3
4
5
6
7
8
[root@backup /server/scripts]# cat disk.sh 
#!/bin/sh
usedisk=`df -h|awk 'NR==2{print $(NF-1)}'`
[ ${usedisk%\%} -gt 80 ] && echo "send mail 当前使用为$usedisk" || echo "磁盘使用正常,当前使用率为$usedisk"
[ `df -h|awk -F "[ %]+" 'NR==2{print $(NF-1)}'` -gt 5 ] && echo "send mail" || echo "磁盘使用正常"
[root@backup /server/scripts]# sh disk.sh
磁盘使用正常,当前使用率为4%
磁盘使用正常

2.加大文件描述符

1
echo '*                -       nofile          65535'>>/etc/security/limits.conf

3.使用脚本 统计系统的 主机名 IP地址 虚拟平台 版本号 磁盘使用率 内存使用率 外网IP地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@backup /server/scripts]# cat os.sh 
#!/bin/bash
eth0=$(ip a|awk 'BEGIN{FS="[ /]+"}/eth0$/{print $3}')
eth1=$(ip a|awk 'BEGIN{FS="[ /]+"}/eth1$/{print $3}')
net_IP=$(curl -s ifconfig.me) # 或者 curl icanhazip.com
VMW=$(hostnamectl | awk '/Virtuali/{print $NF}')
version=$(awk '{print $1,$(NF-1)}' /etc/redhat-release)
disk=$(df|awk 'NR==2{print $(NF-1)}')
mem="$(free|awk 'NR==2{print $3/$2*100}')%"
echo "内网IP为:${eth0}"
echo "外网IP为:${eth1}"
echo "公网IP为:${net_IP}"
echo "虚拟平台为:${VMW}"
echo "操作系统为:${version}"
echo "磁盘使用率为:${disk}"
echo "内存使用率为:${mem}"
[root@backup /server/scripts]# sh os.sh
内网IP为:10.0.1.41
外网IP为:172.16.1.41
公网IP为:113.88.12.225
虚拟平台为:vmware
操作系统为:CentOS 7.4.1708
磁盘使用率为:4%
内存使用率为:10.2867%

4.反向破解 RANDOM 0-32767

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
案例:反向破解 RANDOM 0-32767
d2c74151
a9982990
4462a9fd
b195fe48
5e77d38
[root@backup /server/scripts]# cat RANDOM.sh
#!/bin/bash
for i in {0..32767}
do
num1=`echo $i|md5sum|cut -c1-8`
[ $num1 = "d2c74151" -o $num1 = "a9982990" -o $num1 = "4462a9fd" -o $num1 = "b195fe48" ];
[ $? = 0 ] && echo "$num1 is $i"
num2=`echo $i|md5sum|cut -c1-7`
[ $num2 = "5e77d38" ];[ $? = 0 ] && echo "$num2 is $i"
done
[root@backup /server/scripts]# sh RANDOM.sh
4462a9fd is 2458
5e77d38 is 2945
d2c74151 is 6420
a9982990 is 13008
b195fe48 is 29193

5.使用if分支 来比较两个数字的大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@backup /server/scripts]# cat count.sh 
#!/bin/sh
read -p "please input two number: " num1 num2
if [[ ! "$num1" =~ ^[0-9]+$ || ! "$num2" =~ ^[0-9]+$ ]]
then
echo "请输入正确的整数"
exit
fi
if [ $num1 -gt $num2 ];then
echo "$num1>$num2"
elif [ $num1 -lt $num2 ];then
echo "$num1<$num2"
else
echo "$num1=$num2"
fi
[root@backup /server/scripts]# sh count.sh
please input two number: 10 20
10<20

6.随机生成一个随机数1-100 判断生成的随机数和输入的随机数是否相等,如果相等则退出,大了提示大了,小则提示小了,总共猜了多少次

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
[root@backup /server/scripts]# cat 1_100.sh 
#!/bin/sh
ran=`echo $((RANDOM%100+1))`
> ran.txt
read -p "请回车开始系统自动猜: " re
i=1
case $re in
y)
while true
do
ra=`echo $((RANDOM%100+1))`
if [ `grep -w $ra ran.txt|wc -l` -eq 1 ];then
continue
fi
if [ $ra -gt $ran ];then
echo "系统猜的数字为 $ra 猜大了"
echo $ra >> ran.txt
elif [ $ra -lt $ran ];then
echo "系统猜的数字为 $ra 猜小了"
echo $ra >> ran.txt
else
echo "系统猜对了数字为$ra"
echo "总共猜了 $i 次"
exit
fi
let i++
done
;;
*)
echo hehe
esac

7.按照系统版本号的不同 更改默认YUM源

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
32
33
34
35
36
37
38
39
[root@backup /server/scripts]# cat yum.sh 
#!/bin/sh
. /etc/init.d/functions
os=`cat /etc/redhat-release |awk '{print $4}'`
if [ "$os" = "(Final)" ]
then
os=`cat /etc/redhat-release|awk '{print $3}'`
fi
ping -c 1 -W1 www.baidu.com &>/dev/null
if [ $? -ne 0 ];then
systemctl restart network
action "请检查网络" /bin/false
else

if [ ${os%%.*} -eq 7 ];then
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo &>/dev/null
if [ $? -eq 0 ];then
action "yum源已更新完成......." /bin/true
else
action "yum源更新失败,请检查.." /bin/false
exit
fi

elif [ ${os%%.*} -eq 6 ];then
mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo &>/dev/null
if [ $? -eq 0 ];then
action "yum源已更新完成......." /bin/true
else
action "yum源更新失败,请检查.." /bin/false
exit
fi
else
echo "请检查你的版本号"
fi
fi
[root@backup /server/scripts]# sh yum.sh
yum源已更新完成....... [ OK ]

8.nginx启动脚本

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
32
33
34
35
36
37
38
39
[root@backup /server/scripts]# cat nginx_start.sh 
#!/bin/sh
[ -f /etc/init.d/functions ] && . /etc/init.d/functions
te=$1
test(){

if [ $? -eq 0 ];then
action "Nginx $te is" /bin/true
else
action "Nginx $te is" /bin/false
fi

}
case $1 in
start)
/usr/sbin/nginx
test
;;
stop)
/usr/sbin/nginx -s stop
test
;;
restart)
/usr/sbin/nginx -s stop
sleep 1
/usr/sbin/nginx
test
;;
reload)
/usr/sbin/nginx -s reload
test
;;
status)
echo "WEB端口号: `netstat -tnulp|grep master|grep '\<tcp\>'|awk '{print $4}'`"
echo "WEB-PID: `ps axu|grep [n]ginx|grep master|awk '{print $2}'`"
;;
*)
echo "Usage: $0 {start|stop|status|restart|reload}"
esac

9.生活案例: 吃饭

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
32
33
34
35
36
37
38
39
40
41
42
43
44
[root@backup /server/scripts]# cat eat.sh 
#!/bin/bash
cat<<EOF
1.皇萌鸡
2.酸笋鱼
3.瓦香鸡
4.炒菜
5.酸辣粉
6.炒粉
7.面
8.饺子
9.不吃
EOF
read -p "想吃什么,请按回车键 :"
ran=`echo $((RANDOM%9+1))`
case $ran in
1)
echo "皇萌鸡"
;;
2)
echo "酸笋鱼"
;;
3)
echo "瓦香鸡"
;;
4)
echo "炒菜"
;;
5)
echo "酸辣粉"
;;
6)
echo "炒粉"
;;
7)
echo "面"
;;
8)
echo "饺子"
;;
9)
echo "不吃"
;;
esac

10.脚本批量创建10个用户,密码统一为123,需要对用户输入是否为数字和输入的名字是否为空做判断

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
32
33
34
35
36
37
[root@backup /server/scripts]# cat useradd.sh 
#!/bin/sh
read -p "请输入用户名的前缀: " prefix
[ -z $prefix ] && echo "请输入前缀" && exit
read -p "请输入要创建多少个用户: " num
expr 1 + $num &>/dev/null
[ $? -ne 0 ] && echo "请输入整数" && exit
for i in `seq $num`
do
echo $prefix$i
done
read -p "你确定要创建以上用户吗?[y|yse|Y|YES|n|N|NO]" re
for n in `seq $num`
do
user=$prefix$n
case $re in
y|yes|Y|YES)
id $user &>/dev/null
if [ $? -ne 0 ];then
mm=`mkpasswd -l 8`
useradd $user && echo $mm|passwd --stdin $user &>/dev/null
[ $? -eq 0 ]
#echo -e "$user\t$mm" >> /tmp/useradd.txt
echo -e "用户: $user\t创建成功\t密码是:$mm"
else
echo "用户已存在"
continue
fi
;;
n|N|no|NO)
echo "不创建则退出"
exit
;;
*)
read -p "你确定要创建以上用户吗?[y|yse|Y|YES|n|N|NO]" re
esac
done

11.简单jumpserver脚本

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
32
33
34
35
36
37
38
39
40
41
42
43
44
[root@backup /server/scripts]# cat jum.sh 
#/bin/bash
menu(){
cat<<EOF
1)WEB01=10.0.1.7
2)WEB02=10.0.1.8
3)MySQL=10.0.1.51
4)NFS=10.0.1.31
5)BACKUP=10.0.1.41
6)help
EOF
}
menu
trap "echo 不要乱输入,小心爆炸" INT HUP TSTP
while true
do
read -p "请输入需要连接的服务器: " num
case $num in
1)
ssh 10.0.1.7
;;
2)
ssh 10.0.1.8
;;
3)
ssh 10.0.1.51
;;
4)
ssh 10.0.1.31
;;
5)
ssh 10.0.1.41
;;
6|h)
clear
menu
;;
woshiyunwei)
exit
;;
*)
echo "请输入正确信息!"
esac
done

12.取10位随机小写字母

1
2
3
4
5
6
7
8
9
10
[root@backup /server/scripts]# cat az.sh 
#!/bin/bash
randstr() {
index=0
str=""
for i in {a..z}; do arr[index]=$i; index=`expr ${index} + 1`; done
for i in {1..10}; do str="$str${arr[$RANDOM%$index]}"; done
echo $str
}
echo `randstr`

13.Ping10.0.1.0/24网段那些能通

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@backup /server/scripts]# cat ping.sh 
#!/bin/bash
for i in `seq 254`
do
{
IP=10.0.1.$i
ping -c 1 -W 1 $IP &>/dev/null
if [ $? -eq 0 ];then
echo "10.0.1.$i is OK"
fi
} &
done
wait
echo "在线取IP完成..."

14.输入两个整数计算这两个整数的相加,相减,相乘,相除,求余的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
read -p "please input num1: " num1
read -p "please input num2: " num2
expr $num1 + 1 &>/dev/null
RERVAL_A=$?
expr $num2 + 1 &>/dev/null
RERVAL_B=$?
if [ $RERVAL_A -ne 0 -o $RERVAL_B -ne 0 ];then
echo "请输入整数"
exit
fi
echo "mun1+num2 =$(( num1 + num2 ))"
echo "mun1-num2 =$(( num1 - num2 ))"
echo "mun1*num2 =$(( num1 * num2 ))"
echo "mun1/num2 =$(( num1 / num2 ))"

15.打印下面这句话中字母数小于5的单词 I am lizhenya teacher I am 18

1
2
3
4
5
6
7
#!/bin/bash
for i in I am lizhenya teacher I am 18
do
if [ ${#i} -lt 5 ];then
echo $i
fi
done

16.写个shell,看看你的linux系统中是否有自定义用户(普通用户),若是有,一共有几个?

1
2
3
#!/bin/bash
user=`awk 'NR!=1' /etc/passwd|awk -F: '/\/bin\/bash$/{print $1}'`
echo $user

17.写一个shell脚本来看看你使用最多的命令是哪些,列出你最常用的命令top10

1
2
3
4
5
#!/bin/bash
HISTFILE=~/.bash_history
set -o history
re=`history|awk '{print $2}'|sort|uniq -c|sort -nr|head`
echo -e "最近使用最多的前个命令10是:\n$re"

18.编写一个脚本,计算100以内所有能被3整除数字的和

1
2
3
4
5
6
7
8
9
#!/bin/bash
sum=0
for i in {1..100}
do
if [ $((i % 3)) -eq 0 ];then
sum=$[$sum+$i]
fi
done
echo $sum

19.写一个脚本计算一下Linux系统所有进程占用内存大小的和

1
2
3
4
5
6
7
#!/bin/bash
sum=0
for mem in `ps aux |awk '{print $6}' |grep -v 'RSS'`
do
sum=$[$sum+$mem]
done
echo "The total memory is $sum."

20.打印一个菜单如下,然后用循环加case语句输出用户输入菜单选项的结果
h 显示命令帮助
f 显示登陆信息
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序

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
32
33
34
35
36
37
38
#!/bin/bash
nume(){
cat<<EOF
h 显示命令帮助
f 显示登陆信息
d 显示磁盘挂载
m 查看内存使用
u 查看系统负载
q 退出程序
EOF
}
nume
while true
do
read -p “please input num”num
case $num in
h)
man
;;
f)
who
;;
d)
df -h
;;
m)
free -h
;;
u)
w
;;
q)
exit
;;
*)
echo “请输入正确编号 ”
esac
done

21.写一个数组脚本统计/var/log/nginx.log里IP访问次数

1
2
3
4
5
6
7
8
9
10
11
awk ‘{print $1} /var/log/nginx.log >ip.txt
#!/bin/bash
declare -A array
while read line
do
let array[$line]++
done<ip.txt
for i in ${!array[*]}
do
echo “nginx 的$i 访问次数为 $i|sort -nr|wc -l”
done

22.统计下面这句话中字母数不大于6的单词(至少两种方式)

1
2
3
4
5
6
7
8
1.echo “I am oldboy teacher welcome to oldboy training class”|xargs -n1|awk ‘if(length<7){print}’
2.#!/bin/bash
for i in I am oldboy teacher welcome to oldboy training class
do
if [ ${#i} -le 6 ];then
echo $i
fi
done

23.使用for循环在/oldboy目录下通过随机小写10个字母加固定字符串oldboy批量创建10个html文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@backup /server/scripts]# cat oldboy.sh 
#!/bin/bash
dir=/oldboy
[ ! -d $dir ] && mkdir $dir
for n in `seq 10`
do
randstr() {
index=0
str=""
for i in {a..z}; do arr[index]=$i; index=`expr ${index} + 1`; done
for i in {1..10}; do str="$str${arr[$RANDOM%$index]}"; done
echo $str
}
touch $dir/`randstr`_oldboy.html
if [ $? -eq 0 ];then
echo `randstr`_oldboy.html create successful
fi
done
文章作者: Wu Fei
文章链接: http://linuxwf.com/2020/04/15/4-Shell-%E7%BC%96%E7%A8%8B%E6%80%BB%E7%BB%93/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 WF's Blog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论