shell脚本编程

程序的组成

程序:算法+数据结构
数据:是程序的核心
数据结构:数据在计算机中的类型和组织方式
算法:处理数据的方式

程序编程风格

#面向过程语言
做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现情况A,做什么处理,如
果出现了情况B,做什么处理
问题规模小,可以步骤化,按部就班处理
以指令为中心,数据服务于指令
C,shell
#面向对象语言
一种认识世界、分析世界的方法论。将万事万物抽象为各种对象
类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合
对象是类的具象,是一个实体
问题规模大,复杂系统
以数据为中心,指令服务于数据
java,C#,python,golang等

编程语音

计算机:运行二进制指令
编程语言:人与计算机之间交互的语言。分为两种:低级语言和高级语言
低级编程语言:
机器:二进制的0和1的序列,称为机器指令。与自然语言差异太大,难懂、难写
汇编:用一些助记符号替代机器指令,称为汇编语言
 如:ADD A,B 将寄存器A的数与寄存器B的数相加得到的数放到寄存器A中
 汇编语言写好的程序需要汇编程序转换成机器指令
 汇编语言稍微好理解,即机器指令对应的助记符,助记符更接近自然语言
高级编程语言:
编译:高级语言-->编译器-->机器代码文件-->执行,如:C,C++
解释:高级语言-->执行-->解释器-->机器代码,如:shell,python,php,JavaScript,perl
编译和解释型语言

脚本语言的基本用法

自动化常用命令
执行系统管理和故障排除
创建简单的应用程序
处理文本或文件

shell脚本的执行方法

#执行方法1
[root@centos8 ~]#bash /data/hello.sh
#执行方法2
[root@centos8 ~]#cat /data/hello.sh | bash
#执行方法3
[root@centos8 ~]#chmod +x /data/hello.sh
但你写了一个脚本却无法被执行是因为你的hash里面没有这个路径,路径无法被查到,就是在环境变量里面无法被查到,要写到环境变量里面 而且还要用  .激活一下
#绝对路径
[root@centos8 ~]#/data/hello.sh
#相法路径
[root@centos8 ~]#cd /data/
[root@centos8 ~]#./hello.sh
#执行方法4,本方法可以实现执行远程主机的shell脚本
[root@centos8 ~]#yum -y install httpd
[root@centos8 ~]#systemctl start httpd
[root@centos8 ~]#mv /data/hello.sh /var/www/html/
[root@centos8 ~]#curl -s http://www.wanghua.com/hello.sh|bash   #执行互联网上的脚本  -s 可以隐藏下载的信息
[root@centos8 ~]#wget -qO - http://www.wangxiaochun.com/testdir/hello.sh |bash
hello, world
Hello, world!
调用别人写的脚本,将将脚本放在服务器上,调用服务器上的脚本

范例:备份脚本

[root01:52 PMcentos7 ]#cat a.sh 
#!/bin/bash
echo -e "\033[1;32m 开始备份 \033[0m"
sleep 3
cp -a /etc  /back/`date +%F_%T`
echo -e "\033[1;32m 备份完成 \033[0m"

shell 脚本调试

只检测脚本中的语法错误,但无法检查出命令错误,但不真正执行脚本

bash -n /path/to/some_script

调试并执行

bash -x /path/to/some_script          -x:真正执行了的,每次执行一行,执行的结果就显示一下

总结:脚本错误常见的有三种

​ 语法错误,会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准

​ 确的

​ 命令错误,默认后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察

​ 逻辑错误:只能使用 bash -x 进行观察

变量

变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据

变量类型

变量类型:
内置变量,如:PS1,PATH,UID,HOSTNAME,$$(当前进程),BASHPID,PPID(父进程),$?,HISTSIZE
用户自定义变量
不同的变量存放的数据不同,决定了以下
1. 数据存储方式
2. 参与的运算
3. 表示的数据范围
变量数据类型:
字符
数值:整型、浮点型,bash 不支持浮点数

编程语言分类

#静态和动态语言
静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:java,c
动态编译语言:不用事先声明,可随时改变类型,如:bash,Python

#强类型和弱类型语言
强类型语言:不同类型数据操作,必须经过强制转换才同一类型才能运算,如java , c# ,
python
如:参考以下 python 代码
 print('magedu'+ 10) 提示出错,不会自动转换类型
 print('magedu'+str(10)) 结果为magedu10,需要显示转换类型
弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会
自动进行隐式类型转换;变量无须事先定义可直接调用
如:bash ,php,javascript

Shell****中变量命名法则

不能使程序中的保留字:如:if, for
只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
见名知义,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
统一命名规则:驼峰命名法, studentname,大驼峰StudentName 小驼峰studentName 
变量名大写:STUDENT_NAME
局部变量小写
函数名小写

变量定义和引用

变量的生效范围等标准划分变量类型

普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell
进程均无效
环境变量:生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片断,通常指函数

变量赋值:

直接字串:name='root'
变量引用:name="$USER"
命令引用:name=`COMMAND` 或者 name=$(COMMAND)

注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚

本结束,也会自动删除

变量引用:

弱引用和强引用
"$name " 弱引用,其中的变量引用会被替换为变量值
'$name ' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串

范例:变量的各种赋值方式和引用

[root@centos8 ~]#TITLE='cto'  
[root@centos8 ~]#echo $TITLE
cto
[root@centos8 ~]#echo I am $TITLE
I am cto
[root@centos8 ~]#echo "I am $TITLE"
I am cto
[root@centos8 ~]#echo 'I am $TITLE'
I am $TITLE
[root@centos8 ~]#NAME=$USER
[root@centos8 ~]#echo $NAME
root
[root@centos8 ~]#USER=`whoami`
[root@centos8 ~]#echo $USER
root
[root@centos8 ~]#FILE=`ls /run`
[root@centos8 ~]#echo $FILE
agetty.reload atd.pid auditd.pid autofs.fifo-misc autofs.fifo-net console 
cron.reboot cryptsetup dbus faillock fsck initctl initramfs lock log mount 
NetworkManager plymouth rsyslogd.pid screen sepermit setrans sshd.pid sssd.pid 
sudo systemd tmpfiles.d tuned udev user utmp vmware
[root@centos8 ~]#FILE=/etc/*   命令的执行结果
[root@centos8 ~]#echo $FILE
/etc/adjtime /etc/aliases /etc/alternatives /etc/anacrontab /etc/at.deny 
/etc/audit /etc/authselect /etc/autofs.conf /etc/autofs_ldap_auth.conf

垃圾回收

[root03:27 PMcentos7 ]#title=cto
[root03:33 PMcentos7 ]#name=wang
[root03:33 PMcentos7 ]#title=$name
[root03:34 PMcentos7 ]#echo $name 
wang
[root03:34 PMcentos7 ]#echo $title
wang
[root03:35 PMcentos7 ]#name=wo
[root03:35 PMcentos7 ]#echo $name
wo
[root03:35 PMcentos7 ]#echo $title 
wang
[root03:35 PMcentos7 ]#name=ow
[root03:37 PMcentos7 ]#echo $name
ow
[root03:37 PMcentos7 ]#

wo这个字符串没有人使用了,就是一块垃圾了,会被回收
[root@centos8 ~]#seq 10
1
2
3
4
5
6
7
8
9
10
[root@centos8 ~]#NUM=`seq 10`
[root@centos8 ~]#echo $NUM
1 2 3 4 5 6 7 8 9 10
[root@centos8 ~]#echo "$NUM"     #加双引号才能保留多行格式
1
2
3
4
5
6
7
8
9
10

[root03:43 PMcentos7 ]#name="
> wang
> zhang
> li
> "
[root03:44 PMcentos7 ]#echo $name
wang zhang li
[root03:44 PMcentos7 ]#echo "$name"

wang
zhang
li

[root03:44 PMcentos7 ]#name="wang
> zhang
> zhao
> li"
[root03:48 PMcentos7 ]#echo $name
wang zhang zhao li
[root03:48 PMcentos7 ]#echo "$name"
wang
zhang
zhao
li
[root03:48 PMcentos7 ]#

显示已定义的所有变量

set      

删除变量:

unset <name>        #  跟的是变量名,无需要加$
[root@centos8 ~]#NAME=mage
[root@centos8 ~]#TITLE=ceo
[root@centos8 ~]#echo $NAME $TITLE
mage ceo
[root@centos8 ~]#unset NAME TITLE
[root@centos8 ~]#echo $NAME $TITLE

不设置环境变量子进程无法调用父进程变量

[root04:29 PMcentos7 ]#cat parent.sh 
#!/bin/bash
NAME=name
echo $NAME
/data/son.sh
[root04:29 PMcentos7 ]#cat son.sh 
#!/bin/bash
echo " 调用父进程的变量 $NAME"
NAME="myvalue"
echo "调用自己的变量 $NAME"
[root04:29 PMcentos7 ]#/data/parent.sh 
name
 调用父进程的变量        ( #子进程无法调用父进程的变量)
调用自己的变量 myvalue
[root04:29 PMcentos7 ]#/data/son.sh 
 调用父进程的变量 
调用自己的变量 myvalue
[root04:29 PMcentos7 ]#
[root04:29 PMcentos7 ]#vim parent.sh  (添加export以后,子进程就调用父进程的环境变量)
  1 #!/bin/bash
  2 export  NAME=name                                                                                       
  3 echo $NAME
  4 /data/son.sh

[root04:48 PMcentos7 ]#/data/parent.sh  
name
 调用父进程的变量 name
调用自己的变量 myvalue

父进定义的环境变量,子进程能使用,当子进程自己定义的变量和父进程定义的环境变量一致的时候,子进程优先使用自己的变量


环境变量

环境变量:
可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量
一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程
一般只在系统配置文件中使用,在脚本中较少使用
#声明并赋值
export name=VALUE
declare -x name=VALUE
#或者分两步实现
name=VALUE
export name

范例:变量引用

[root@centos8 data]#NAME=mage
[root@centos8 data]#AGE=20
[root@centos8 data]#echo $NAME
mage
[root@centos8 data]#echo $AGE
20
[root@centos8 data]#echo $NAME $AGE
mage 20
[root@centos8 data]#echo $NAME$AGE
mage20
[root@centos8 data]#echo $NAME_$AGE  #因为下划线是可以当做变量名的,将$NAME_ 认为是一个变量
20
[root@centos8 data]#echo ${NAME}_$AGE    
mage_20

env

系统所有的环境变量,只是列环境变量
[root05:03 PMcentos7 ]#echo $$
3365
[root05:12 PMcentos7 ]#bash
[root05:12 PMcentos7 ]#echo $$
5155
[root05:12 PMcentos7 ]#echo $PPID        $SHLVL:嵌套深度      $$:当前的进程的PID     $PPID:父进程的PID
3365
[root05:12 PMcentos7 ]#echo $SHLVL
2
[root05:13 PMcentos7 ]#bash
[root05:14 PMcentos7 ]#echo $SHLVL
3
[root05:14 PMcentos7 ]#

范例:利用变量实现动态命令

[root05:48 PMcentos7 ]#CD=hostname
[root05:48 PMcentos7 ]#$CD
centos7

范例:显示主机的信息

[root03:11 PMcentos7 ]#cat b.sh 
#!/bin/bash
echo -e "\033[1;31m ---------------------主机信息----------------------- \033[0m"
echo -e  "\033[1;32m主机名:`hostname` \033[0m"
echo -e  "\033[1;32mIP地址:`ifconfig ens33 |grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}' |head -1 `\033[0m"
echo -e  "\033[1;32m发行版本号:`cat /etc/redhat-release`\033[0m"
echo -e  "\033[1;32m内核版本:`uname -r` \033[0m "  
echo -e  "\033[1;32mCPU信息:`lscpu |grep -i "model name"|tr -s ' ' |cut -d: -f2`\033[0m"
echo -e "\033[1;32m内存的使用情况:`free -h |grep -iE  "mem"|tr -s ' ' : |cut -d: -f2`\033[0m"
echo -e "\033[1;32m磁盘的使用情况:`lsblk |grep "^sd" |awk '{print $4}' ` \033[0m"
echo -e "\033[1;31m-------------------------------------------------------\033[0m"

只读变量

只读变量:只能声明定义,但后续不能修改和删除,即常量

声明只读变量:

[root06:05 PMcentos7 ]#type declare
declare is a shell builtin
#申明只读变量
readonly name
declare  -r name

#查看只读变量:
readonly [-p]
declare -r

[root@centos8 ~]#readonly PI=3.14159
[root@centos8 ~]#echo $PI
3.14159
[root@centos8 ~]#PI=3.14
-bash: PI: readonly variable
[root@centos8 ~]#unset PI
-bash: unset: PI: cannot unset: readonly variable
[root@centos8 ~]#echo $PI
3.14159
[root@centos8 ~]#exit   #退出以后变量就消失了
logout
Connection closed by foreign host.

位置变量

位置变量:在bash shell中内置的变量, 在脚本代码中调用通过命令行传递给脚本的参数

$1, $2, ... 对应第1个、第2个等参数,shift [n]换位置
$0 命令本身,包括路径
$* 传递给脚本的所有参数,全部参数合为一个字符串
$@ 传递给脚本的所有参数,每个参数为独立字符串
$# 传递给脚本的参数的个数
注意:$@ $* 只在被双引号包起来的时候才会有差异

#清空所有位置变量
set --


[root@centos8 ~]#cat /data/scripts/arg.sh 
#!/bin/bash
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "10st arg is ${10}"
echo "11st arg is ${11}"
echo "The number of arg is $#"
echo "All args are $*"
echo "All args are $@"
echo "The scriptname is `basename $0`"        `basename $0`不显示路径名
[root@centos8 ~]#bash /data/scripts/arg.sh {a..z}
1st arg is a
2st arg is b
3st arg is c
10st arg is j
11st arg is k
The number of arg is 26
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
All args are a b c d e f g h i j k l m n o p q r s t u v w x y z
The scriptname is arg.sh

范例:删库跑路之命令rm的安全实现

[root06:24 PMcentos7 ]#cat rm.sh 
#!/bin/bash
STA="echo -e \033[1;31m"
END="\033[0m"
DIR=/tmp/`date +%F_%T`
mkdir $DIR
mv $* $DIR
$STA MOVE $* TO $DIR  $END

范例:$*和$@的区别

[root@centos8 scripts]#cat file.sh
#!/bin/bash
echo "file.sh:1st arg is $1"

[root@centos8 scripts]#cat f2.sh
#!/bin/bash
echo "f2.sh:all args are $@"
echo "f2.sh:all args are $*"
./file.sh "$@"
[root@centos8 scripts]#cat f1.sh
#!/bin/bash
echo "f1.sh:all args are $@"
echo "f1.sh:all args are $*"
./file.sh "$*"

[root@centos8 scripts]#./f1.sh a b c
f1.sh:all args are a b c
f1.sh:all args are a b c
file.sh:1st arg is a b c           # 嵌套以后$* 是所有的参数  $@是一个参数
[root@centos8 scripts]#./f2.sh a b c
f2.sh:all args are a b c
f2.sh:all args are a b c
file.sh:1st arg is a

退出状态码变量

进程执行后,将使用变量 $? 保存状态码的相关数字,不同的值反应成功或失败,$?取值范例 0-255

$?的值为0 #代表成功
$?的值是1到255   #代表失败

[root@centos8 scripts]#curl http://www.wangxiaochun.com &> /dev/null
[root@centos8 scripts]#echo $?
0
ping -c1 -W1 hostdown &> /dev/null 
echo $?
#最近一条命令的执行结果

注意:

脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字

如果未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码

展开命令行

展开命令执行顺序
把命令行分成单个命令词
展开别名
展开大括号的声明{}
展开波浪符声明 ~
命令替换$() 和 ``
再次把命令行分成命令词
展开文件通配*、?、[abc]等等
准备I/0重导向 <、>
运行命令
反斜线(\)会使随后的字符按原意解释
        echo Your cost: \$5.00 
        Your cost: $5.00
        

脚本安全和 set

set 命令:可以用来定制 shell 环境
$- 变量
h:hashall,打开选项后,Shell 会将命令所在的路径hash下来,避免每次都要查询。通过set +h将h选
项关闭
i:interactive-comments,包含这个选项说明当前的 shell 是一个交互式的 shell。所谓的交互式shell,
在脚本中,i选项是关闭的
m:monitor,打开监控模式,就可以通过Job control来控制进程的停止、继续,后台或者前台执行等
B:braceexpand,大括号扩展
H:history,H选项打开,可以展开历史列表中的命令,可以通过!感叹号来完成,例如“!!”返回上最近的
一个历史命令,“!n”返回第 n 个历史命令

[root08:02 PMcentos7/boot ]#ls /etc/redhat-release 
/etc/redhat-release
[root08:03 PMcentos7/boot ]#cat $_      echo $_是前一条命令的最后一个参数
CentOS Linux release 7.9.2009 (Core)

[root@centos8 ~]#echo $-   
himBHs
[root08:05 PMcentos7/boot ]#set +h
[root08:05 PMcentos7/boot ]#echo $-
imBH
[root08:05 PMcentos7/boot ]#hash     #这样以后hash就被禁用了
-bash: hash: hashing disabled  
[root08:05 PMcentos7/boot ]#
[root08:05 PMcentos7/boot ]#set -h   #恢复hash功能
[root08:07 PMcentos7/boot ]#hash 
hits	command
   2	/usr/bin/cat
   4	/usr/bin/ls
[root08:07 PMcentos7/boot ]#echo $-  #恢复原状
himBH
[root@centos8 ~]#set +B   关闭{}的功能
[root@centos8 ~]#echo $-
imHs
[root@centos8 ~]#echo {1..10}
{1..10}

set 命令实现脚本安全

-u 在扩展一个没有设置的变量时,显示错误信息, 等同set -o nounset
 -e 如果一个命令返回一个非0退出状态值(失败)就退出, 等同set -o errexit
 -o option 显示,打开或者关闭选项
 显示选项:set -o 
 打开选项:set -o 选项
 关闭选项:set +o 选项
 -x 当执行命令时,打印命令及其参数,类似 bash -x
 

[root08:08 PMcentos7/boot ]#set  -o
allexport      	off
braceexpand    	on
emacs          	on
errexit        	off  #出现错误不退出
errtrace       	off
functrace      	off
hashall        	on
histexpand     	on
history        	on
ignoreeof      	off
interactive-comments	on
keyword        	off
monitor        	on
noclobber      	off
noexec         	off
noglob         	off
nolog          	off
notify         	off
nounset        	off
onecmd         	off
physical       	off
pipefail       	off
posix          	off
privileged     	off
verbose        	off
vi             	off
xtrace         	off

[root08:18 PMcentos7~ ]#set  -o errexit on   #开启功能,出现错误以后退出
[root08:18 PMcentos7~ ]#set  -o |grep errexit
errexit        	on

[root08:21 PMcentos7~ ]#bash  f.sh
line1
f.sh: line 4: xxx: command not found
[root08:21 PMcentos7~ ]#cat f.sh
#!/bin/bash
set  -e      
echo line1                   set  -e  安全,但是一条命令不成功,后面的都不执行
xxx
echo line2

[root08:32 PMcentos7~ ]#cat b.sh 
#!/bin/bash
DIR=/data1
rm -rf  /data/tmp/$DIR1/*         因为没有$DIR1这个变量,没有定义的变量
[root08:33 PMcentos7~ ]#mkdir /data/tmp/
[root08:33 PMcentos7~ ]#touch  /data/tmp/a
[root08:33 PMcentos7~ ]#touch  /data/tmp/b
[root08:33 PMcentos7~ ]#bash b.sh 
[root08:34 PMcentos7~ ]#ls  /data/tmp/

[root08:39 PMcentos7~ ]#cat b.sh 
#!/bin/bash
set -u 
DIR=/data1
rm -rf  /data/tmp/$DIR1/*
[root08:38 PMcentos7~ ]#bash b.sh 
b.sh: line 4: DIR1: unbound variable   加了-u 以后就不许哪些未知的变量

所以工作中基于安全考虑,脚本中加
set -ue

格式化输出 printf

printf "指定的格式" "文本1" ”文本2“……
%s 字符串
%f 浮点格式
%b 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转
义
%c ASCII字符,即显示对应参数的第一个字符
%d,%i 十进制整数
%o 八进制值
%u 不带正负号的十进制值
%x 十六进制值(a-f)
%X 十六进制值(A-F)
%% 表示%本身

[root@centos8 ~]#printf "%s\n" 1 2 3 4
1
2
3
4
[root@centos8 ~]#printf "%f\n" 1 2 3 4
1.000000
2.000000
3.000000
4.000000
#.2f 表示保留两位小数
[root@centos8 ~]#printf "%.2f\n" 1 2 3 4
1.00
2.00
3.00
4.00
[root@centos8 ~]#printf "(%s)" 1 2 3 4;echo 
(1)(2)(3)(4)
[root@centos8 ~]#printf " (%s) " 1 2 3 4;echo ""
 (1) (2) (3) (4) 
[root@centos8 ~]#printf "(%s)\n" 1 2 3 4
(1)
(2)
(3)
(4)
[root@centos8 ~]#printf "%s %s\n" 1 2 3 4
1 2
3 4
[root@centos8 ~]#printf "%s %s %s\n" 1 2 3 4
1 2 3
4  
#%-10s 表示宽度10个字符,左对齐
[root@centos8 ~]#printf "%-10s %-10s %-4s %s \n" 姓名 性别 年龄 体重 小明 男 20 70 
小红 女 18 50
姓名     性别     年龄   体重
小明     男        20   70
小红     女        18   50
#将十进制的17转换成16进制数
[root@centos8 ~]#printf "%X" 17
11[root@centos8 ~]# #将十六进制C转换成十进制
[root@centos8 ~]#printf "%d\n" 0xC
12
[root@centos8 ~]#VAR="welcome to Magedu";printf "\033[31m%s\033[0m\n" $VAR
welcome
to
Magedu
[root@centos8 ~]#VAR="welcome to Magedu";printf "\033[31m%s\033[0m\n" "$VAR"
welcome to Magedu

算术运算

shell 支持算术运算,但只支持整数,不支持小数

bash中的算术运算

+
-
*
/
% 取模,即取余数,示例:9%4=1,5%3=2
** 乘方

乘法符号有些场景中需要转义

增强型赋值:

+= i+=10 相当于 i=i+10
-= i-=j   相当于 i=i-j
*=
/=
%=
++ i++,++i   相当于 i=i+1
-- i--,--i   相当于 i=i-1

实现算术运算:

(1) let var=算术表达式
(2) ((var=算术表达式)) 和上面等价
            [root@centos8 ~]#let i=10*2
            [root@centos8 ~]#echo $i
            20
            [root@centos8 ~]#((j=i+10))
            [root@centos8 ~]#echo $j
            30
            
            
[root09:29 AMcentos8 ~]#let i=10*2
[root09:29 AMcentos8 ~]#((j=i+10))
[root09:30 AMcentos8 ~]#echo $j
30
 
 
(3) var=$[算术表达式]
(4) var=$((算术表达式))
(5) var=$(expr arg1 arg2 arg3 ...)
(6) declare –i var = 数值
(7) echo '算术表达式' | bc

内建的随机数生成器变量:

$RANDOM   取值范围:0-32767
[root08:53 PMcentos7~ ]#echo $RANDOM
16020
[root08:57 PMcentos7~ ]#echo $RANDOM
26272

#生成 0 - 49 之间随机数
echo $[$RANDOM%50]
#随机字体颜色
[root@centos8 ~]#echo -e "\033[1;$[RANDOM%7+31]mhello\033[0m"
magedu
[root09:25 PMcentos7~ ]#echo -e "\e[1;$[RANDOM%7+31]mhello\033[0m"
hello

let 支持算数运算

[root08:59 PMcentos7~ ]#n=10
[root09:00 PMcentos7~ ]#m=20
[root09:00 PMcentos7~ ]#sum=$m+$n
[root09:00 PMcentos7~ ]#echo $sum
20+10
[root09:00 PMcentos7~ ]#let sum=$m+$n
[root09:02 PMcentos7~ ]#echo $sum
30
[root09:02 PMcentos7~ ]#n=30
[root09:02 PMcentos7~ ]#let sum=$m+$n
[root09:02 PMcentos7~ ]#echo $sum
50

取余数为0到50

[root09:05 PMcentos7~ ]#let result=RANDOM%50
[root09:05 PMcentos7~ ]#echo $result 
24
[root09:05 PMcentos7~ ]#let result=RANDOM%50+1
[root09:06 PMcentos7~ ]#echo $result 
48

i++ 和++1的区别

[root09:06 PMcentos7~ ]#i=10
[root09:08 PMcentos7~ ]#let i++
[root09:08 PMcentos7~ ]#echo $i
11
[root09:08 PMcentos7~ ]#let i++
[root09:08 PMcentos7~ ]#echo $i
12
[root09:08 PMcentos7~ ]#let i--
[root09:08 PMcentos7~ ]#echo $i
11
[root09:08 PMcentos7~ ]#let ++i
[root09:09 PMcentos7~ ]#echo $i
12
[root09:09 PMcentos7~ ]#let ++i
[root09:09 PMcentos7~ ]#echo $i
13

[root09:09 PMcentos7~ ]#i=10;let j=i++;echo j=$j i=$i    #赋值给j以后再加
j=10 i=11
[root09:13 PMcentos7~ ]#i=10;let j=++i;echo j=$j i=$i    #加完了赋给j
j=11 i=11

expr

[root09:33 PMcentos7~ ]#expr 2 + 3
5
[root09:33 PMcentos7~ ]#expr 2 * 3
expr: syntax error
[root09:34 PMcentos7~ ]#expr 2 / 3
0
[root09:34 PMcentos7~ ]#expr 23 / 3
7
[root09:34 PMcentos7~ ]#expr 27 / 3
9
[root09:34 PMcentos7~ ]#expr 2 \* 3  乘法被误认为通配符,转义
6

bc

[root09:36 PMcentos7~ ]#echo 2*3 |bc
6
[root09:39 PMcentos7~ ]#echo "scale=3;20/3" |bc
6.666

result

[root09:40 PMcentos7~ ]#i=10
[root09:43 PMcentos7~ ]#j=20
[root09:43 PMcentos7~ ]#declare -i result=i*j
[root09:44 PMcentos7~ ]#echo $result 
200

逻辑运算

true, false

1, 0

#与:&:和0相与,结果为0,和1相与,结果保留原值
     1 与 1 = 1
     1 与 0 = 0
     0 与 1 = 0
     0 与 0 = 0
#或:|:和1相或结果为1,和0相或,结果保留原值
     1 或 1 = 1
       1 或 0 = 1
     0 或 1 = 1
     0 或 0 = 0
 #非:!
     ! 1 = 0 ! true
     ! 0 = 1 ! false
#异或:^
    异或的两个值,相同为假,不同为真。两个数字X,Y异或得到结果Z,Z再和任意两者之一X异或,将得出
    另一个值Y
    1 ^ 1 = 0
    1 ^ 0 = 1
    0 ^ 1 = 1
    0 ^ 0 = 0

[root@centos8 ~]#true 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#false
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#! true
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#! false
[root@centos8 ~]#echo $?
0

#交换两个值
[root@centos8 ~]#x=10;y=20;temp=$x;x=$y;y=$temp;echo x=$x,y=$y
x=20,y=10
[root@centos8 ~]#x=10;y=20;x=$[x^y];y=$[x^y];x=$[x^y];echo x=$x,y=$y
x=20,y=10

短路运算

短路与
 CMD1 短路与 CMD2
第一个CMD1结果为真 (1),第二个CMD2必须要参与运算,才能得到最终的结果
第一个CMD1结果为假 (0),总的结果必定为0,因此不需要执行CMD2
短路或
 CMD1 短路或 CMD2
第一个CMD1结果为真 (1),总的结果必定为1,因此不需要执行CMD2
第一个CMD1结果为假 (0),第二个CMD2 必须要参与运算,,才能得到最终的结果

条件测试命令

条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成

测试过程

,实现评估布尔声明,以便用在条件性环境下进行执行

若真,则状态码变量 $? 返回0

若假,则状态码变量 $? 返回1

条件测试命令

 test EXPRESSION

[ EXPRESSION ] #和test 等价,建议使用 [ ]

[[ EXPRESSION ]]
==========================================================================
[root11:40 PMcentos7~ ]#type [      中括号本身就是一个内部命令
[ is a shell builtin

[root11:45 PMcentos7~ ]#help [
[: [ arg... ]
    Evaluate conditional expression.
    
    This is a synonym for the "test" builtin, but the last argument must
    be a literal `]', to match the opening `['.
[[ ... ]]: [[ expression ]]
    Execute conditional command.
    
    Returns a status of 0 or 1 depending on the evaluation of the conditional
    expression EXPRESSION.  Expressions are composed of the same primaries used
    by the `test' builtin, and may be combined using the following operators:
    
      ( EXPRESSION )	Returns the value of EXPRESSION
      ! EXPRESSION		True if EXPRESSION is false; else false
      EXPR1 && EXPR2	True if both EXPR1 and EXPR2 are true; else false
      EXPR1 || EXPR2	True if either EXPR1 or EXPR2 is true; else false
    
    When the `==' and `!=' operators are used, the string to the right of
    the operator is used as a pattern and pattern matching is performed.
    When the `=~' operator is used, the string to the right of the operator
    is matched as a regular expression.
    
    The && and || operators do not evaluate EXPR2 if EXPR1 is sufficient to
    determine the expression's value.
    
    Exit Status:
    0 or 1 depending on value of EXPRESSION.

注意:EXPRESSION前后必须有空白字符

帮助:

面试题:求年纪之和

[root10:56 PMcentos7~ ]#cat a
xiaoing=20
xiaohong=18
xiaoqiang=22
方法一:
[root11:08 PMcentos7~ ]#cut -d"=" -f2 a  |tr -s "\n"  + |cut -d'+' -f1-3 
20+18+22
[root11:01 PMcentos7~ ]#cut -d"=" -f2 a  |tr -s "\n"  + |cut -d'+' -f1-3 |bc
60
方法二:
[root11:14 PMcentos7~ ]#cut -d"=" -f2 a  |tr -s "\n"  + |grep  -Eo "([0-9]+\+){2}[0-9]+"|bc
60
方法三
[root11:14 PMcentos7~ ]#cut -d"=" -f2 a  |tr -s "\n"  + 
20+18+22+[root11:16 PMcentos7~ ]#cut -d"=" -f2 a  |tr -s "\n"  + |grep -Eo ".*[0-9]+" |bc
60
方法四:
[root10:11 AMcentos8 ~]#awk -F"=" '{print $2}' |paste -sd+ |bc
60

test -v 测试变量是否存在 ,不管里面有没有值

[root11:47 PMcentos7~ ]#test -v n
[root11:52 PMcentos7~ ]#echo $?
0
[root11:52 PMcentos7~ ]#echo $n
30
[root11:54 PMcentos7~ ]#name=
[root11:54 PMcentos7~ ]#test -v name
[root11:54 PMcentos7~ ]#echo $?
0
[root11:55 PMcentos7~ ]#echo $name

[root11:55 PMcentos7~ ]#
[root11:55 PMcentos7~ ]#unset name
[root11:57 PMcentos7~ ]#test -v name
[root11:57 PMcentos7~ ]#echo $?
1
[root11:58 PMcentos7~ ]#hi="hi"
[root11:59 PMcentos7~ ]#[ -v hi ]      test和中括号等价
[root11:59 PMcentos7~ ]#echo $?
0

数值测试

-eq 是否等于
-ne 是否不等于
-gt 是否大于
-ge 是否大于等于
-lt 是否小于
-le 是否小于等于
[root@centos8 ~]#i=10
[root@centos8 ~]#j=8
[root@centos8 ~]#[ $i -lt $j ]   即使是数字也要加$
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ $i -gt $j ] 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ i -gt j ] 
-bash: [: i: integer expression expected

字符串测试

test和 [ ]用法
-z STRING 字符串是否为空,没定义或空为真,不空为假,
-n STRING 字符串是否不空,不空为真,空为假 
   STRING   同上
STRING1 = STRING2 是否等于,注意 = 前后有空格,没有空格是赋值,有空格是比较
STRING1 != STRING2 是否不等于
> ascii码是否大于ascii码
< 是否小于
[[]] 用法,建议,当使用正则表达式或通配符使用,一般情况使用 [ ]
== 左侧字符串是否和右侧的PATTERN相同
 注意:此表达式用于[[ ]]中,PATTERN为通配符
=~ 左侧字符串是否能够被右侧的正则表达式的PATTERN所匹配
 注意: 此表达式用于[[ ]]中;扩展的正则表达式
[root@centos8 ~]#unset str
[root@centos8 ~]#[ -z "$str" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#str=""
[root@centos8 ~]#[ -z "$str" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#str=" "
[root@centos8 ~]#[ -z "$str" ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ -n "$str" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#unset str
[root@centos8 ~]#[ -n "$str" ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ "$str" ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#str=magedu
[root@centos8 ~]#[ "$str" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#str=magedu
[root@centos8 ~]#[ "$str" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#str1=magedu
[root@centos8 ~]#str2=mage
[root@centos8 ~]#[ $str1 = $str2 ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#str2=magedu
[root@centos8 ~]#[ $str1 = $str2 ]      有空格是比较,没有空格是赋值
[root@centos8 ~]#echo $?
0

变量放中括号要加双引号

[root@centos8 ~]#[ "$NAME" ]
[root@centos8 ~]#NAME="I love linux"
[root@centos8 ~]#[ $NAME ]
-bash: [: love: binary operator expected
[root@centos8 ~]#[ "$NAME" ]    #省略了一个  -n 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ I love linux ]
-bash: [: love: binary operator expected

[[ ]] 双中括号的使用


#通配符
[root@centos8 ~]#FILE=test.log
[root@centos8 ~]#[[ "$FILE" == *.log ]]  
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#FILE=test.txt
[root@centos8 ~]#[[ "$FILE" == *.log ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[[ "$FILE" != *.log ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#NAME="linux1"             左侧的变量加双引号,右侧的不加
[root@centos8 ~]#[[ "$NAME" == linux* ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[[ "$NAME" == "linux*" ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#NAME="linux*"
[root@centos8 ~]#[[ "$NAME" == "linux*" ]]
[root@centos8 ~]#echo $?
0
#结论:[[ == ]] == 右侧的 * 做为通配符,不要加“”,只想做为*, 需要加“” 或转义
								  遇到正则表达式这样复杂的就用双中括号
#正则表达式
[root@centos8 ~]#[[ "$FILE" =~ \.log$ ]]    #判断后缀
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#FILE=test.log
[root@centos8 ~]#[[ "$FILE" =~ \.log$ ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#N=100
[root@centos8 ~]#[[ "$N" =~ ^[0-9]+$ ]]     #双中括号用的扩展的正则表达式
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#N=Magedu10
[root@centos8 ~]#[[ "$N" =~ ^[0-9]+$ ]]     #纯数字的判断
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#IP=1.2.3.4
[root@centos8 ~]#[[ "$IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]    #ip地址的判断
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#IP=1.2.3.4567
[root@centos8 ~]#[[ "$IP" =~ ^([0-9]{1,3}.){3}[0-9]{1,3}$ ]]   
[root@centos8 ~]#echo $?
1

#是否是合法的IP 
[root10:27 AMcentos8 ~]#[[ "$IP" =~(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$ ]]
[root10:27 AMcentos8 ~]#echo $?
1

19.jpg20.png

#!/bin/bash   
read -p "请输入IP:" IP
    if [[ $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        FIELD1=$(echo $IP|cut -d. -f1)
        FIELD2=$(echo $IP|cut -d. -f2)
        FIELD3=$(echo $IP|cut -d. -f3)
        FIELD4=$(echo $IP|cut -d. -f4)
        if [ $FIELD1 -le 255 -a $FIELD2 -le 255 -a $FIELD3 -le 255 -a $FIELD4 -le 255 ]; then
            echo "IP $IP available."
        else
            echo "IP $IP not available!"   
        fi
    else
        echo "IP format error!"   
    fi   
 
 
 #!/bin/bash
read -p "请输入一个IP:"  IP
function check_ip() {
    if [[ $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        FIELD1=$(echo $IP|cut -d. -f1)
        FIELD2=$(echo $IP|cut -d. -f2)
        FIELD3=$(echo $IP|cut -d. -f3)
        FIELD4=$(echo $IP|cut -d. -f4)
        if [ $FIELD1 -le 255 -a $FIELD2 -le 255 -a $FIELD3 -le 255 -a $FIELD4 -le 255 ]; then
            echo "IP $IP available."
        else
            echo "IP $IP not available!"   
        fi
    else
        echo "IP format error!"   
    fi   
} 
check_ip

文件测试

存在性测试
-a FILE:同 -e
-e FILE: 文件存在性测试,存在为真,否则为假
-b FILE:是否存在且为块设备文件
-c FILE:是否存在且为字符设备文件 
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件
[root@centos8 ~]#[ -a /etc/nologin ] 
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#! [ -a /etc/nologin ] 
[root@centos8 ~]#echo $?
0
[root01:18 AMcentos7~ ]# [ ! -a /etc/nologin ]   !放中括号里面
[root01:20 AMcentos7~ ]#echo $?
0

[root@centos8 ~]#[ -d /etc ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -d /etc/issue ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ -L /bin ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -L /bin/ ]  软链接
[root@centos8 ~]#echo $?
1


[root01:10 AMcentos7~ ]#ll /etc/redhat-release 
lrwxrwxrwx 1 root root 14 Apr 30 10:16 /etc/redhat-release -> centos-release
[root12:07 AMcentos7~ ]#[ -f /etc/redhat-release  ] 该文件虽然是软链接文件但是却也是普通文件,他判断的是软链接指向的
[root01:09 AMcentos7~ ]#echo $?
0
[root01:13 AMcentos7~ ]#ll /lib  该文件也是软链接,但是却不是普通文件,因为他指向的是一个文件夹
lrwxrwxrwx 1 root root 7 Apr 30 10:16 /lib -> usr/lib
[root01:13 AMcentos7~ ]#[ -f /lib ]
[root01:13 AMcentos7~ ]#echo $?
1
[root01:15 AMcentos7~ ]#[ -h /lib ]  软链接
[root01:16 AMcentos7~ ]#echo $?
0


文件权限测试:

-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行
-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限

注意:最终结果由用户对文件的实际权限决定,而非文件属性决定

[root@centos8 ~]#[ -w /etc/shadow ] 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -x /etc/shadow ] 
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ -w test.txt ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#chattr +i test.txt 
[root@centos8 ~]#lsattr test.txt
----i-------------- nianling.txt
[root@centos8 ~]#[ -w test.txt ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#chattr -i test.txt 
[root@centos8 ~]#[ -w test.txt ]
[root@centos8 ~]#echo $?
0

文件属性测试

-s FILE #是否存在且非空
-t fd #fd 文件描述符是否在某终端已经打开
-N FILE #文件自从上一次被读取之后是否被修改过
-O FILE #当前有效用户是否为文件属主
-G FILE #当前有效用户是否为文件属组
FILE1 -ef FILE2 #FILE1是否是FILE2的硬链接
FILE1 -nt FILE2 #FILE1是否新于FILE2(mtime)
FILE1 -ot FILE2 #FILE1是否旧于FILE2

关于 () {}

(CMD1;CMD2;...)和 { CMD1;CMD2;...; } 都可以将多个命令组合在一起,批量执行

[root@centos8 ~]#man bash

(list ) 会开启子shell,并且list中变量赋值及内部命令执行后,将不再影响后续的环境, 帮助参看:man bash

搜索(list)

{ list; } 不会启子shell, 在当前shell中运行,会影响当前shell环境, 帮助参看:man bash 搜索{ list; }

面试题

[root@centos8 ~]#name=mage;(echo $name;name=wang;echo $name );echo $name
mage           特例:虽然不是环境变量,但是使用小括号是可以继承父进程的环境变量的
wang
mage
[root@centos8 ~]#name=mage;{ echo $name;name=wang;echo $name; } ;echo $name
mage           花括号不开启子进程,会影响当前的环境
wang
wang
[root@centos8 ~]#umask
0022
[root@centos8 ~]#(umask 066;touch f1.txt)
[root@centos8 ~]#ll f1.txt 
-rw------- 1 root root 0 Dec 23 16:58 f1.txt
[root@centos8 ~]#umask
0022
[root@centos8 ~]#( cd /data;ls )
test.log
[root@centos8 ~]#pwd
/root
[root@centos8 ~]#{ cd /data;ls; }
test.log
[root@centos8 data]#pwd
/data
[root@centos8 data]#
#()会开启子shell
[root@centos8 ~]#echo $BASHPID
1920
[root@centos8 ~]#( echo $BASHPID;sleep 100)
1979
[root@centos8 ~]#pstree -p
├─sshd(719)───sshd(1906)───sshd(1919)─┬─bash(1920)───bash(1979)───sleep(1980)
#{ } 不会开启子shell
[root@centos8 ~]#echo $BASHPID
1920
[root@centos8 ~]#{ echo $BASHPID; }
1920

组合测试条件

第一种方式 [ ]
 
 [ EXPRESSION1 -a EXPRESSION2 ] 并且,EXPRESSION1和EXPRESSION2都是真,结果才为真
[ EXPRESSION1 -o EXPRESSION2 ] 或者,EXPRESSION1和EXPRESSION2只要有一个真,结果就为
真
[ ! EXPRESSION ] 取反
说明: -a 和 -o 需要使用测试命令进行,[[ ]] 不支持
[root@centos8 ~]#ll /data/scrips/test.sh
-rw-r--r-- 1 root root 382 Dec 23 09:32 /data/scripts/test.sh
[root@centos8 ~]#[ -f $FILE -a -x $FILE ] 
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#chmod +x /data/scripts/test.sh
[root@centos8 ~]#ll /data/scripts/test.sh
-rwxr-xr-x 1 root root 382 Dec 23 09:32 /data/script40/test.sh
[root@centos8 ~]#[ -f $FILE -a -x $FILE ] 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#chmod -x /data/scripts/test.sh
[root@centos8 ~]#ll /data/scripts/test.sh
-rw-r--r-- 1 root root 382 Dec 23 09:32 /data/scripts/test.sh
[root@centos8 ~]#[ -f $FILE -o -x $FILE ] 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -x $FILE ] 
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ ! -x $FILE ] 
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#! [ -x $FILE ] 
0
第二种方式 [[ ]]
COMMAND1 && COMMAND2 #并且,短路与,代表条件性的AND THEN
如果COMMAND1 成功,将执行COMMAND2,否则,将不执行COMMAND2
COMMAND1 || COMMAND2 #或者,短路或,代表条件性的OR ELSE
如果COMMAND1 成功,将不执行COMMAND2,否则,将执行COMMAND2
! COMMAND   #非,取反

[root@centos7 ~]#[ $[RANDOM%6] -eq 0 ] && rm -rf /* || echo "click"click

[root08:07 AMcentos7 ]#A=10
[root08:07 AMcentos7 ]#B=20
[root08:08 AMcentos7 ]#[ "A" -eq "B" ] && echo "Integers are equal"
-bash: [: A: integer expression expected
[root08:08 AMcentos7 ]#[ "" -eq "" ] && echo "Integers are equal"
-bash: [: : integer expression expected
[root08:08 AMcentos7 ]#[ "$A" -eq "$B" ] && echo "Integers are equal"
[root08:08 AMcentos7 ]#echo $?
1
变量放[]比较用$号
[root@centos8 ~]#test "A"-eq "B" && echo "Integers are equal"
===================================================================
[root07:59 AMcentos7 ]#A=10
[root07:59 AMcentos7 ]#B=10
[root08:00 AMcentos7 ]#[ "A" = "B" ] && echo "Strings are equal"
[root08:00 AMcentos7 ]#echo $?
1
[root08:04 AMcentos7 ]#test "A" = "B" && echo "Strings are equal" 
[root08:06 AMcentos7 ]#echo $?
1
[root08:01 AMcentos7 ]#[ "$A" = "$B" ] && echo "Strings are equal"
Strings are equal
[root08:01 AMcentos7 ]#[ "$A" -eq "$B" ] && echo "Integers are equal"
Integers are equal
==================================================================


[root@centos8 ~]#[ -f /bin/cat -a -x /bin/cat ] && cat /etc/fstab
[root@centos8 ~]#[ -z "$HOSTNAME" -o "$HOSTNAME" = "localhost.localdomain" ]&& 
hostname www.magedu.com
[root@centos8 ~]#id wang &> /dev/null ||   useradd wang
[root@centos8 ~]#id zhang &> /dev/null ||   useradd zhang
[root@centos8 ~]#getent passwd zhang
zhang:x:1002:1002::/home/zhang:/bin/bash
[root@centos8 ~]#grep -q no_such_user /etc/passwd || echo 'No such user'
No such user

[root@centos8 ~]#[ -f “$FILE” ] && [[ “$FILE”=~ .*\.sh$ ]] && chmod +x $FILE
网络连接状态

[root@centos8 ~]#ping -c1 -W1 172.16.0.1 &> /dev/null && echo '172.16.0.1 is 
up' || (echo '172.16.0.1 is unreachable'; exit 1) 
172.16.0.1 is up
[root@centos8 ~]#IP=10.0.0.111;ping -c1 -W1 $IP &> /dev/null && echo $IP is up 
|| echo $IP is down                 -c1  ping一次
10.0.0.111 is down                  -W1  间隔时间为1秒
[root@centos8 ~]#IP=10.0.0.1;ping -c1 -W1 $IP &> /dev/null && echo $IP is up || 
echo $IP is down
10.0.0.1 is up
&& 和 || 组合使用
[root@centos8 ~]#NAME=wang; id $NAME &> /dev/null && echo "$NAME is exist"
wang is exist
[root@centos8 ~]#NAME=wange; id $NAME &> /dev/null || echo "$NAME is not 
exist"
wange is not exist
[root@centos8 ~]#NAME=wange; id $NAME &> /dev/null && echo "$NAME is exist" || 
echo "$NAME is not exist"
wange is not exist
[root@centos8 ~]#NAME=wang; id $NAME &> /dev/null && echo "$NAME is exist" || 
echo "$NAME is not exist"
wang is exist
[root@centos8 ~]#NAME=wang; id $NAME &> /dev/null && echo "$NAME is exist" || 
echo "$NAME is not exist"
wang is exist
[root@centos8 ~]#NAME=wang; id $NAME &> /dev/null || echo "$NAME is not exist" 
&& echo "$NAME is exist"
wang is exist
[root@centos8 ~]#NAME=wange; id $NAME &> /dev/null || echo "$NAME is not 
exist" && echo "$NAME is exist"
wange is not exist
wange is exist
#结论:如果&& 和 || 混合使用,&& 要在前,|| 放在后
[root@centos8 ~]#NAME=wange; id $NAME &> /dev/null && echo "$NAME is exist" || 
useradd $NAME
[root@centos8 ~]#id wange
uid=1002(wange) gid=1002(wange) groups=1002(wange)
[root@centos8 ~]#NAME=wangge; id $NAME &> /dev/null && echo "$NAME is exist" || 
( useradd $NAME; echo $NAME is created )   保证后面的两条命令是一起的
wangge is created
[root@centos8 ~]#id wangge
uid=1003(wangge) gid=1003(wangge) groups=1003(wangge)
[root@centos8 ~]#NAME=wanggege; id $NAME &> /dev/null && echo "$NAME is exist" 
|| { useradd $NAME; echo $NAME is created; }  {}别忘记了加分号
wanggege is created

范例:磁盘空间检查脚本

[root@centos8 ~]#cat /data/script40/disk_check.sh 
#!/bin/bash
WARNING=80
SPACE_USED=`df|grep '^/dev/sd'|tr -s ' ' %|cut -d% -f5|sort -nr|head -1`
[ "$SPACE_USED" -ge $WARNING ] && echo "disk used is $SPACE_USED,will be full" 
| mail -s diskwaring root

范例:磁盘空间和Inode号的检查脚本

[root@centos8 scripts]#cat disk_check.sh
#!/bin/bash
WARNING=80
SPACE_USED=`df | grep '^/dev/sd'|grep -oE '[0-9]+%'|tr -d %| sort -nr|head -1`
INODE_USED=`df -i | grep '^/dev/sd'|grep -oE '[0-9]+%'|tr -d %| sort -nr|head 
-1`
[ "$SPACE_USED" -gt $WARNING -o "$INODE_USED" -gt $WARNING ] && echo "DISK 
USED:$SPACE_USED%, INODE_USED:$INODE_USED,will be full" | mail -s "DISK Warning"
root@wangxiaochun.com
[root09:24 AMcentos7 ]#cat  disk.sh 
#!/bin/bash
warning=12
inodes=`df |grep '^/dev'|grep -Eo [0-9]+% |tr  -d % |sort -nr |head -1`
disk=`df  -h|grep '^/dev'|grep -Eo '[0-9]+%'|tr -d '%' |sort -nr|head -1`
[ "$disk" -gt "$warning" -o "$inodes" -gt "$warning"  ] && echo "DISK USED $disk%  INODES USED $inodes%,will be full" |mail -s "DISK USE" 1722525928@qq.com

使用read命令来接受输入

使用read来把输入值分配给一个或多个shell变量,read从标准输入中读取值,给每个单词分配一个变
量,所有剩余单词都被分配给最后一个变量,如果变量名没有指定,默认标准输入的值赋值给系统内置
变量REPLY
-p   指定要显示的提示
-s   静默输入,一般用于密码
-n N 指定输入的字符长度N
-d '字符'   输入结束符
-t N TIMEOUT为N秒
[root@centos8 ~]#read
wangxiaochun
[root@centos8 ~]#echo $REPLY
wangxiaochun
[root@centos8 ~]#read NAME TITLE
wang cto
[root@centos8 ~]#echo $NAME
wang
[root@centos8 ~]#echo $TITLE
cto

#交互式
[root@centos8 ~]#read -p "Please input your name: " NAME
Please input your name: wang
[root@centos8 ~]#echo $NAME
wang
[root@centos8 ~]#read x y z <<< "I love you"
[root@centos8 ~]#echo $x
I
[root@centos8 ~]#echo $y
love
[root@centos8 ~]#echo $z
you
[root@centos8 ~]#

read -p 可以省略echo这一行

[root10:11 AMcentos7 ]#cat read.sh 
#!/bin/bash
echo -n  "are you rich ? yes or no:"
read ANSWER
[ $ANSWER = "yes" -o $ANSWER = "y" ] && echo "you are rich " ||echo "do well anything"
---------------------------------------------------------------------------
[root10:15 AMcentos7 ]#cat read.sh 
#!/bin/bash
read  -p "are you rich? yes or no:"   ANSWER
[ $ANSWER = "yes" -o $ANSWER = "y" ] && echo "you are rich " ||echo "do well anything"

-------------------------------------------------------------------------------------------
正则表达式优化一下
[root10:26 AMcentos7 ]#cat read.sh 
#!/bin/bash
read  -p "are you rich? yes or no:"   ANSWER
[[ $ANSWER =~ ^[Yy]|[Ee]|[Ss]$ ]] && echo "you are rich " ||echo "do well anything"

实现运维工作菜单

[root10:53 AMcentos7 ]#cat work.sh 
#!/bin/bash
echo -en "\033[$[RANDOM%7+31];1m"
cat <<EOF
请选择:
1)备份数据库
2)清理日志
3)软件升级
4)软件回滚
5)删库跑路

EOF
read -p "请输入上面数字1-5:" MEMU
[ $MEMU -eq 1 ] && ./backup.sh
[ $MEMU -eq 2 ] && echo "清理日志"
[ $MEMU  -eq 3 ] && echo "软件升级"
[ $MEMU  -eq 4 ] &&  echo "软件回滚"
[ $MEMU -eq 5 ] && echo "删库跑路"
echo -en "\033[0m"
root10:53 AMcentos7 ]#bash work.sh 
请选择:
1)备份数据库
2)清理日志
3)软件升级
4)软件回滚
5)删库跑路

请输入上面数字1-5:3
软件升级


[root11:17 AMcentos7 ]#cat  backup.sh 
#!/bin/bash
backdir=/root/`date +%F_%T`
mkdir $backdir
cp -a /etc  $backdir && echo "备份成功" ||echo "备份失败"
root11:17 AMcentos7 ]#chmod +x backup.sh 



面试题 利用管道read无法赋值


[root11:26 AMcentos7 ]#cat f1
a b
[root11:26 AMcentos7 ]#read i j <f1
[root11:27 AMcentos7 ]#echo $i
a
[root11:27 AMcentos7 ]#echo $j
b
[root11:29 AMcentos7 ]#echo abc def | read x y 
[root11:29 AMcentos7 ]#echo $x $y

[root11:30 AMcentos7 ]#
[root11:30 AMcentos7 ]#echo abc def | read x y;echo x=$x y=$y 
x= y=

[root11:37 AMcentos7 ]#echo 1 2 |read x y ;echo x=$x y=$y
x= y=
[root11:37 AMcentos7 ]#echo 1 2 |(read x y ;echo x=$x y=$y)
x=1 y=2
[root11:39 AMcentos7 ]#echo 1 2 |{ read x y ;echo x=$x y=$y; }
x=1 y=2

read 选项

-p   指定要显示的提示
-s   静默输入,一般用于密码
-n N 指定输入的字符长度N
-d '字符'   输入结束符
-t N TIMEOUT为N秒
[root11:39 AMcentos7 ]#read PASS
123456
[root11:40 AMcentos7 ]#echo $PASS
123456
[root11:40 AMcentos7 ]#read -s  pass  静默输出

[root11:41 AMcentos7 ]#echo $pass 
123456
[root11:41 AMcentos7 ]#

bash****的配置文件

source和bash两个执行脚本的区别:

source是在当前的进程中运行,一般用于 修改配置文件让生效

bash是在当前进程的子进程中运行,不影响当前的进程环境,一般用来运行脚本

管道也是运行在子进程中

bash shell的配置文件很多,可以分成下面类别

  • 按生效范围划分两类
#全局配置:
/etc/profile
/etc/profile.d/*.sh
/etc/bashrc
#个人配置:
~/.bash_profile
~/.bashrc



  • shell****登录两种方式分类
#  交互式登录
直接通过终端输入账号密码登录
使用 su - UserName 切换的用户
配置文件执行顺序:
/etc/profile.d/*.sh
/etc/bashrc
/etc/profile
/etc/bashrc    #此文件执行两次
.bashrc
.bash_profile

注意:文件之间的调用关系,写在同一个文件的不同位置,将影响文件的执行顺序

 #非交互式登录
su UserName
图形界面下打开的终端
执行脚本
任何其它的bash实例
执行顺序:
/etc/profile.d/*.sh
/etc/bashrc
.bashrc
  • 按功能划分分类

profifile类和bashrc类

#Profile类
profile类为交互式登录的shell提供配置
全局:/etc/profile, /etc/profile.d/*.sh
个人:~/.bash_profile
功用:
(1) 用于定义环境变量
(2) 运行命令或脚本

#Bashrc类
bashrc类:为非交互式和交互式登录的shell提供配置
全局:/etc/bashrc
个人:~/.bashrc
功用:
(1) 定义命令别名和函数
(2) 定义本地变量

编辑配置文件生效

修改profifile和bashrc文件后需生效两种方法:

  1. 重新启动shell进程

  2. source|. 配置文件

 .   ~/.bashrc

Bash 退出任务

保存在~/.bash_logout文件中(用户),在退出登录shell时运行
功能:
创建自动备份
清除临时文件
1.在/etc/profile 中定义别名 alias abc=ls  
2. 在 ~/.bashrc 中定义别名alias abc=hostname
3. alias abc  发现别名是hostname
4  su - 以后再 alias abc  发现报错
5  断开终端,重新连接 用alias abc 发现现在abc的别名就是hostname   因为把 /etc/profile 里面的覆盖了

练习

1、让所有用户的PATH环境变量的值多出一个路径,例如:/usr/local/apache/bin
2、用户 root 登录时,将命令指示符变成红色,并自动启用如下别名: rm=‘rm –i’
 cdnet=‘cd /etc/sysconfig/network-scripts/’
 editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eth0’
 editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eno16777736 或 ifcfg-ens33 ’ (如果系统是
CentOS7)
3、任意用户登录系统时,显示红色字体的警示提醒信息“Hi,dangerous!” 4、编写生成脚本基本格式的脚本,包括作者,联系方式,版本,时间,描述等

答案:第2题

[root@centos7: ~]#vim .bashrc 

# .bashrc

# User specific aliases and functions

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
alias cdnet='cd /etc/sysconfig/network-scripts/'
alias editnet='vim /etc/sysconfig/network-scripts/ifcfg-ens33'
#alias editnet='vim /etc/sysconfig/network-scripts/ifcfg-eno16777736'

# Source global definitions
if [ -f /etc/bashrc ]; then
        . /etc/bashrc
fi

alias abc=hostname
PS1="\[\e[01;31m\][\u@\h: \W]\\$\[\e[0m\]"
export PS1

第三题

在/etc/issue 写入
[root@centos7: ~]#vim /etc/issue

\S
Kernel \r on an \m
Hi,dangerous

身材判断

[root@centos7: ~]#cat a.sh
#!/bin/bash
#
#*************************************
#author:                王千三
#QQ:                    1722525928
#email:                 1722525928@qq.com
#version:               1.0
#date:                  2021-05-16
#description:           怕水的鱼
#*************************************
read -p "请输入身高(m为单位):" H
if [[ ! "$H" =~ ^[0-2]\.?[0-9]{,2}$ ]];then
	echo "输入错误的身高"
	exit 1
fi
read -p "请输入体重(KG为单位):" W
if [[ ! "$W" =~ ^[0-9]{1,3}$ ]];then echo "输入错误的体重";exit 2 ; fi
BMI=`echo $W/$H^2 |bc`
if [ $BMI -le 18 ];then 
	echo "太瘦了"
elif [ $BMI -lt 24 ];then
	echo "身材很棒"
else
	echo "太胖,加强运动"
fi
 

身材判断

[root@centos7: ~]#vim a.sh 

#!/bin/bash
#
#*************************************
#author:                王千三
#QQ:                    1722525928
#email:                 1722525928@qq.com
#version:               1.0
#date:                  2021-05-16
#description:           怕水的鱼
#*************************************
. /root/color.sh       #用 . 的作用是因为在同一进程里面执行,调用里面的颜色
${GREEN} test ${END}

read -p "请输入身高(m为单位):" H
if [[ ! "$H" =~ ^[0-2]\.?[0-9]{,2}$ ]];then
        ${RED} "输入错误的身高"${END}
        exit 1
fi
read -p "请输入体重(KG为单位):" W
if [[ ! "$W" =~ ^[0-9]{1,3}$ ]];then echo "输入错误的体重";exit 2 ; fi
BMI=`echo $W/$H^2 |bc`
if [ $BMI -le 18 ];then
        ${RED}"太瘦了"${END}
elif [ $BMI -lt 24 ];then
        ${GREEN} "身材很棒"${END}
else
        ${RED} "太胖,加强运动"${END}
fi
======================================================================
[root@centos7: ~]#cat color.sh 
#!/bin/bash
#
#*************************************
#author:                王千三
#QQ:                    1722525928
#email:                 1722525928@qq.com
#version:               1.0
#date:                  2021-05-16
#description:           怕水的鱼
#*************************************
GREEN='echo -e \E[032;1m'
RED='echo -e \E[031;1m'
END='\e[0m'

#移动到一个配置文件里面右后减少重复造轮子
[root@centos7: ~]#mv color.sh /etc/init.d/

缩进的设置

在~/.vimrc里面添加内容
set et
set ts=4

条件判断 case 语句

case 对散列值的匹配

case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac

case 变量引用 in
PAT1)
 分支1
 ;;
PAT2)
 分支2
 ;;
...
*)
 默认分支
 ;;
esac

case支持glob风格的通配符:

*: 任意长度任意字符
?: 任意单个字符
[]:指定范围内的任意单个字符
|:   或,如 a或b

范例

[root@centos7: ~]#vim yesno.sh

#!/bin/bash
#
#*************************************
#author:                王千三
#QQ:                    1722525928
#email:                 1722525928@qq.com
#version:               1.0
#date:                  2021-05-16
#description:           怕水的鱼
#*************************************
read -p "请输入yes或no:" INPUT
case $INPUT in
[yY][Ee][Ss]|[Yy])
    echo "you input yes"
    ;;
[Nn][Oo]|[Nn])
    echo "you input no"
    ;;
*)
    echo "input false"
esac

运维菜单实现版本2

[root@centos7: ~]#cat work2.sh 
#!/bin/bash
echo -en "\033[$[RANDOM%7+31];1m"
cat <<EOF
请选择:
1)备份数据库
2)清理日志
3)软件升级
4)软件回滚
5)删库跑路

EOF
read -p "请输入上面数字1-5:" MEMU
case $MEMU in
1)
    ./backup.sh
    ;;
2)
    echo "清理日志"
    ;;
3)
    echo "软件升级"
    ;;
4)
    echo "软件回滚"
    ;;
5)
    echo  "删库跑路"
    ;;
*)
    echo "input false"
esac
 
echo -en "\033[0m"

练习

1、编写脚本 createuser.sh,实现如下功能:使用一个用户名做为参数,如果指定参数的用户存在,就
显示其存在,否则添加之。并设置初始密码为123456,显示添加的用户的id号等信息,在此新用户第一
次登录时,会提示用户立即改密码,如果没有参数,就提示:请输入用户名
2、编写脚本 yesorno.sh,提示用户输入yes或no,并判断用户输入的是yes还是no,或是其它信息
3、编写脚本 filetype.sh,判断用户输入文件路径,显示其文件类型(普通,目录,链接,其它文件类
型)
4、编写脚本 checkint.sh,判断用户输入的参数是否为正整数
5、编写脚本 reset.sh,实现系统安装后的初始化环境,包括:1、别名 2、环境变量,如PS1等 3、
安装常用软件包,如:tree 5、实现固定的IP的设置,6、vim的设置等

循环

for循环的死循环
[root@centos7: ~]#for((;;));do echo for ;done

for循环

#格式
for NAME [in WORDS ... ] ; do COMMANDS; done
for 变量名 in 列表;do
 循环体
done
for 变量名 in 列表
do
 循环体
done

for****循环列表生成方式:

直接给出列表
整数列表:
{start..end}
$(seq [start [step]] end) 
返回列表的命令:
$(COMMAND)
使用glob,如:*.sh
变量引用,如:$@,$*,$#(参数里面脚本的个数)

面试题,计算1+2+3+...+100的结果

[root@centos7: ~]#seq -s + 100 |bc
5050

[root@centos7: ~]#sum=0;for i in {1..100};do let  sum+=$i;done;echo sum=$sum
sum=5050

[root@centos7: ~]#echo {1..100} |tr ' ' + |bc
5050


99乘法表

[root@centos7: ~]#vim 99.sh

#!/bin/bash
#
#*************************************
#version:               1.0
#date:                  2021-05-16
#description:           怕水的鱼
#*************************************
for i in {1..9};do
    for j in `seq $i`;do
        echo -e "${j}x${i}=$[i*j]\t\c"
    done
    echo
done
  \c 保持不换行   \t 保持对齐方式

显示文件夹文件的属性

[root@centos7: log]#for i in /var/log/ ;do ll $i;done

面试题:将指定目录下的文件所有文件的后缀改名为 bak 后缀

[root@centos7: script]#cat  name.sh 
#!/bin/bash
#
#*************************************
#author:                王千三

#version:               1.0
#date:                  2021-05-16
#description:           怕水的鱼
#*************************************
DIR=/data/tests
cd $DIR
for i in *;do
    PRE=`echo $i |sed -nr 's#^(.*)\.[^.]+$#\1#p'`
    mv $i $PRE.bak
done

面试题,要求将目录YYYY-MM-DD/中所有文件,移动到YYYY-MM/DD/下

#1 yyyy-mm-dd10.sh 创建YYYY-MM-DD,当前日期一年前365天到目前共365个目录,里面有10个文件,
$RANDOM.log 
[root@centos8 ~]#cat for_dir.sh 
#!/bin/bash
for i in {1..365};do 
 DIR=`date -d "-$i day" +%F`
 mkdir /data/test/$DIR
 cd /data/test/$DIR
 for n in {1..10};do
 touch $RANDOM.log
 done
done
#2 移动到YYYY-MM/DD/下  
#!/bin/bash
#
DIR=/data/test
cd $DIR
for DIR in * ;do 
 YYYY_MM=`echo $DIR |cut -d"-" -f1,2`
 DD=`echo $DIR |cut -d"-" -f3`
 [ -d $YYYY_MM/$DD ] || mkdir -p $YYYY_MM/$DD &> /dev/null
 mv $DIR/*   $YYYY_MM/$DD
done

面试题:扫描一个网段:10.0.0.0/24,判断此网段中主机在线状态,将在线的主机的IP打印出来

NET=10.0.0
for ID in {1..254};do
   {
    ping -c1 -W1 $NET.$ID &> /dev/null && echo $NET.$ID is up || echo $NET.$ID
is down
   }&
done
wait

wait:表示所有ping完了就自动的退出了

双小括号方法

双小括号方法,即((…))格式,也可以用于算术运算,双小括号方法也可以使bash Shell实现C语言风格
的变量操作
I=10;((I++))
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
do
 循环体
done
说明:
控制变量初始化:仅在运行到循环代码段时执行一次
控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
for((sum=0,i=1;i<=100;sum+=i,i++));do                       
        true
done
echo $sum

99乘法表

[root@centos7: script]#cat 9s.sh 
#!/bin/bash
#
#*************************************
#author:                王千三

#version:               1.0
#date:                  2021-05-16
#description:           怕水的鱼
#*************************************
for((i=1;i<=9;i++));do
    for((j=1;j<=i;j++))do
        echo -e "${j}X${i}=$[i*j]\t\c"
    done
    echo
done


求和

#!/bin/bash
#
#*************************************
#author:                王千三

#version:               1.0
#date:                  2021-05-16
#description:           怕水的鱼
#*************************************
for((sum=0,i=1;i<=100;sum+=i,i++));do
    true
done
echo sum=$sum

while循环

无限循环
while true; do  
 循环体
done
#配置发邮件的邮箱
[root@centos8 ~]#cat .mailrc 
set from=29308620@qq.com
set smtp=smtp.qq.com
set smtp-auth-user=29308620@qq.com
set smtp-auth-password=esvnhbnqocirbicf
set smtp-auth=login
set ssl-verify=ignore
[root@centos8 ~]#cat while_diskcheck.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: while_diskcheck.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
WARNING=80
while :;do
   USE=`df | sed -rn '/^\/dev\/sd/s#.* ([0-9]+)%.*#\1#p' |sort -nr|head -n1`
   if [ $USE -gt $WARNING ];then
      echo Disk will be full from `hostname -I` | mail  -s "disk warning"
29308620@qq.com
   fi
   sleep 10
done


==========================================================================
我的邮件服务器的搭建:
UFZDBXQZRBBHLYPU 授权吗

vim /etc/mail.rc 

set from=wh1722525928@163.com smtp=smtp.163.com
set smtp-auth-user=wh1722525928@163.com  smtp-auth-password=UFZDBXQZRBBHLYPU      smtp-auth=login

中国移动的邮箱139

until 循环

条件为假才执行循环。

until COMMANDS; do COMMANDS; done
until CONDITION; do
 循环体
done
进入条件: CONDITION 为false
退出条件: CONDITION 为true

  无限循环	
            until false; do
             循环体
            Done

循环控制语句 continue

continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层

格式

for((i=0;i<8;i++));do

    for((j=0;j<8;j++));do
        [ $j -eq 3 ] && continue   不打印3
        echo $j 
    done
    echo -------------------------------
done

[root@centos7: ~]#bash for_.sh 
0
1
2
4
5
6
7
-------------------------------
0
1
2
4
5
6
7
-------------------------------
0
1
2
4
5
6
7
-------------------------------
0
1
2
4
5
6
7
-------------------------------
0
1
2
4
5
6
7
-------------------------------
0
1
2
4
5
6
7
-------------------------------
0
1
2
4
5
6
7
-------------------------------
0
1
2
4
5
6
7
-------------------------------

for((i=0;i<8;i++));do

    for((j=0;j<8;j++));do
        [ $j -eq 3 ] && continue  2
        echo $j                            也是重复8次
    done
    echo -------------------------------
done
[root@centos7: ~]#bash for_.sh 
0
1
2
0
1
2
0
1
2
0
1
2
0
1
2
0
1
2
0
1
2
0
1
2
[root@centos

循环控制语句 break

break [N]:提前结束第N层整个循环,最内层为第1层

for((i=0;i<8;i++));do

    for((j=0;j<8;j++));do
        [ $j -eq 5 ] && break 2
        echo $j 
    done
    echo -------------------------------
done
[root@centos7: ~]#bash for_.sh 
0
1
2
3
4

for((i=0;i<8;i++));do

    for((j=0;j<8;j++));do
        [ $j -eq 5 ] && break
        echo $j 
    done
    echo -------------------------------
done

[root@centos7: ~]#bash for_.sh 
0
1
2
3
4
-------------------------------
0
1
2
3
4
-------------------------------
0
1
2
3
4
-------------------------------
0
1
2
3
4
-------------------------------
0
1
2
3
4
-------------------------------
0
1
2
3
4
-------------------------------
0
1
2
3
4
-------------------------------
0
1
2
3
4
-------------------------------

或者我自己写的


[root@centos7: ~]#cat mume.sh 
#!/bin/bash
#
#*************************************
#author:                王千三

#version:               1.0
#date:                  2021-05-17
#description:           怕水的鱼
#*************************************
sum=0
clore='echo -e \033[1;31m'
clore2='echo -e \033[1;32m'
end='\033[0m'
$clore2**************************************$end
cat<<EOF
1)鲍鱼 
2)满汉全席
3)龙虾
4)燕窝
5)帝王蟹
6)退出
EOF
$clore2****************************************$end
while true;do
    read  -p '请输入点菜编号(1-6):' MEMU
    case $MEMU in
    1|4)
        echo -e '\033[1;32m菜价: $10 \033[0m'
        let sum+=10
        ;;

    3|5)
        $clore2 '菜价: $20' $end
        let sum+=20
        ;;
      2)
        $clore2 '菜价:$1000'$end
        let sum+=1000
        ;;
      6)
        $clore2 "点菜的总价是: $sum"$end
        break
        ;;
      *)
        $clore '点错了,没有这道菜' $end
        ;;
    esac
    echo   "点菜的总价$sum" 
done


猜数字

[root@centos7: ~]#vim num.sh

#!/bin/bash
#
#*************************************
#author:                王千三
#QQ:                    1722525928
#email:                 1722525928@qq.com
#version:               1.0
#date:                  2021-05-17
#description:           怕水的鱼
#*************************************
N=$[RANDOM%10]
while read -p "please input your number: " n;do
if [ $n -eq $N ];then
    echo "good luckly"

elif [ $n -gt $N ];then
    echo "数字太大"
else
  echo "数字太小"
fi
done

循环控制 shift 命令

shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。

参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用

到 shift

shift 创建用户的案例

[root@centos7: ~]#cat shift.sh 
#!/bin/bash
#
#*************************************
#author:                王千三
#QQ:                    1722525928
#email:                 1722525928@qq.com
#version:               1.0
#date:                  2021-05-17_08:44:43
#description:           怕水的鱼
#*************************************
PASSWD=1
while [ $1 ];do
    id $1 &>/dev/null ||useradd  $1 &>/dev/null
    echo $PASSWD |passwd --stdin $1  &>/dev/null
    shift
done

练习

1、每隔3秒钟到系统上获取已经登录的用户的信息;如果发现用户hacker登录,则将登录时间和主机记 录于日志/var/log/login.log中,并退出脚本

[root11:54 AMcentos7 ~]#vim 17.sh

  1 #!/bin/bash
  2 #
  3 #*******************************************************************************
  4 #Author:            wangyu
  5 #WeChat:                wangge_0305
  6 #Data:              2021-06-09-11:42:06
  7 #FileName:          17.sh
  8 #URL:               https://blog.51cto.com/u_14847540
  9 #Description:       17.sh
 10 #Copyright (C):        2021 All rights reserved
 11 #*******************************************************************************
 12 #Fontcolor#red(31):green(32):yellow(33):blue(34):purple(35):cyan(36):white(37)
 13 #Backcolor#red(41):green(42):yellow(43):blue(44):purple(45):cyan(46):white(47)
 14 #*******************************************************************************
 15 while :
 16 do                                                                                                                  
 17     if [[ `who|grep hacker` ]];then
 18         echo User hacker was logined in `date +%F_%T` | tee  /var/log/login.log
 19         break
 20     fi
 21     sleep 3
 22 done
 23 

2、随机生成10以内的数字,实现猜字游戏,提示比较大或小,相等则退出

[root12:06 PMcentos7 ~]#vim 18.sh

  2 #
  3 #*******************************************************************************
  4 #Author:            wangyu
  5 #WeChat:                wangge_0305
  6 #Data:              2021-06-09-11:58:47
  7 #FileName:          18.sh
  8 #URL:               https://blog.51cto.com/u_14847540
  9 #Description:       18.sh
 10 #Copyright (C):        2021 All rights reserved
 11 #*******************************************************************************
 12 #Fontcolor#red(31):green(32):yellow(33):blue(34):purple(35):cyan(36):white(37)
 13 #Backcolor#red(41):green(42):yellow(43):blue(44):purple(45):cyan(46):white(47)
 14 #*******************************************************************************
 15 #
 16 NUM=$[$RANDOM%10]
 17 while :
 18 do
 19 read -p "请输入一个数字: " x
 20     if [ $x -lt $NUM ];then
 21         echo "太小,重新输入"
 22     elif [ $x -gt $NUM ];then
 23         echo "太大,重新输入"
 24     else
 25         echo "输入正确,退出程序"
 26         break
 27     fi
 28 done

3、用文件名做为参数,统计所有参数文件的总行数

[root12:11 PMcentos7 ~]#vim 19.sh

  1 #!/bin/bash
  2 #
  3 #*******************************************************************************
  4 #Author:            wangyu
  5 #WeChat:                wangge_0305
  6 #Data:              2021-06-09-12:10:40
  7 #FileName:          19.sh
  8 #URL:               https://blog.51cto.com/u_14847540
  9 #Description:       19.sh
 10 #Copyright (C):        2021 All rights reserved
 11 #*******************************************************************************
 12 #Fontcolor#red(31):green(32):yellow(33):blue(34):purple(35):cyan(36):white(37)
 13 #Backcolor#red(41):green(42):yellow(43):blue(44):purple(45):cyan(46):white(47)
 14 #*******************************************************************************
 15 #
 16 sum=0
 17 while [ $1 ];do
 18     i=`cat $1|wc -l`
 19     let sum+=i
 20     shift
 21 done
 22 echo $sum                  

4、用二个以上的数字为参数,显示其中的最大值和最小值

[root12:25 PMcentos7 ~]#vim 20.sh

  1 #!/bin/bash
  2 
  3 if [[ $# == 0 ]];then
  4     echo "请输入参数"
  5     exit
  6 fi
  7 declare -i big=$1
  8 declare -i small=$2
  9 until [[ -z $1 ]];do
 10     if (( $1 > $big ));then
 11     big=$1
 12     fi
 13     if (( $1 < $small ));then
 14         small=$1
 15     fi
 16     shift
 17 done
 18 echo "大的数字是$big  小的数字是$small"
 19 unset big
 20 unset small                            

while read 特殊用法

while 循环的特殊用法,遍历文件或文本的每一行

while read line; do
 循环体
done < /PATH/FROM/SOMEFILE


[root@centos7: ~]#cat name.txt 
wang li zhao

[root@centos7: ~]#while read name;do echo $name;done<name.txt 
wang li zhao
[root@centos7: ~]#cat name.txt |while read name;do echo $name;done
wang li zhao

[root@centos7: ~]#echo wang li zhang |while read x y z;do echo $x $y $z;done
wang li zhang

磁盘使用报警用 while read

着行处理

[root@centos7: ~]#vim  while.sh 

#!/bin/bash
#
WARNING=6
df |sed -nr '/^\/dev\//s#^([^ ]+).* ([0-9]+)%.*#\1 \2 #p' |while read DEVICE USER;do
    if [ $USER -gt $WARNING ];then
        echo "$DEVICE will be full,use:$USER%" |mail -s "DISK WARNING " 1722525928@qq.com
    fi
done


select 循环与菜单

select 循环主要用于创建菜单,按数字顺序排列的菜单项显示在标准错误上,并显示 PS3 提示
符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量 REPLY 中
select 是个无限循环,因此要用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c 
退出循环
select 经常和 case 联合使用
与 for 循环类似,可以省略 in list,此时使用位置参量

自动生成菜单:
[root@centos7: ~]#select memu in kaoya baoyu lamian;do echo $memu;done
1) kaoya
2) baoyu
3) lamian
#? 1
kaoya
#? 2
baoyu
#? 3
lamian
#? 4

#? 5

#? 

select 菜单脚本

[root@centos7: ~]#cat select.sh 
#!/bin/bash

sum=0
PS3="请输入菜的编号:"
select menu in 鲍鱼 满汉全席 龙虾 燕窝 帝王蟹 退出;do
case  $REPLY in
1|3)
    echo "$memu price is \$10"
    let sum+=10
    ;;
2)
    echo "$memu price is \$1000"
    let sum+=1000
    ;;
4|5)
    echo "$memu price is \$20"
    let sum+=20
     ;;
6)
    echo "点菜结束 退出"
    break
    ;;
*)
    echo "点菜错误,重新选择"
    ;;
esac
done
echo "点菜总价格:$sum"
echo "总价格:$sum"

===================================
   PS3 指输出的内容
   $REPLY 变量

函数介绍

函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程

它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一

部分

函数和shell程序比较相似,区别在于

Shell程序在子Shell中运行,而Shell函数在当前Shell中运行。因此在当前Shell中,函数可对shell中变量

进行修改

定义函数

#语法一: 第一种方法简单明了
func_name (){
 ...函数体...
}#语法二:
function func_name {
 ...函数体...
} 
#语法三:
function func_name () {
 ...函数体...
}

查看函数

#查看当前已定义的函数名
declare -F
#查看当前已定义的函数定义
declare -f
#查看指定当前已定义的函数名
declare -f func_name 
#查看当前已定义的函数名定义
declare -F func_name

删除函数

unset func_name

函数调用

函数的调用方式
可在交互式环境下定义函数
可将函数放在脚本文件中作为它的一部分
可放在只包含函数的单独文件中
调用:函数只有被调用才会执行,通过给定函数名调用函数,函数名出现的地方,会被自动替换为函数
代码
函数的生命周期:被调用时创建,返回时终止
[root@centos7: /]#declare -f disable_firewalld_selinux  #列出disable_firewalld_selinux这个函数
disable_firewalld_selinux () 
{ 
    systemctl stop firewalld;
    systemctl disable firewalld;
    sed -i 's#^SELINUX=enforcing#SELINUX=disabled#' /etc/selinux/config;
    setenforce 0  #不重启的情况下生效
}


#调用函数:
disable_firewalld_selinux
#断开xshell 函数失效


[root@centos7: ~]#cat func.sh 
#!/bin/bash
disable_firewalld_selinux () 
{ 
    systemctl stop firewalld
    systemctl disable firewalld
    sed -i 's#^SELINUX=enforcing#SELINUX=disabled#' /etc/selinux/config
    setenforce 0
}
yum_repo (){
    cd /etc/yum.repos.d/
    mkdir backup
    mv *.repo backup
    cat >base.repo<<EOF
[base]
name=base_wanghua_2021-04-13
baseurl= https://mirrors.aliyun.com/centos/\$releasever/os/\$basearch/           
         https://mirrors.huaweicloud.com/centos/\$releasever/os/\$basearch/
enabled=1
#gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7


[epel]
name=epel_wanghua_2021-04-13
baseurl=http://mirrors.aliyun.com/epel/7/\$basearch
    https://mirrors.huaweicloud.com/epel/7/\$basearch
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
EOF
} 
   
yum_repo

   
install_package (){
packages="
vim
tree
autofs
net-tools
"
for i in $packages;do
    rpm -q $i &> /dev/null ||yum -q -y install $i

done
}


[root@centos7: ~]#

常用的功能全部写成函数,以后想用就直接调用

[root@centos7: ~]#mv func.sh funcs
[root@centos7: ~]#vim test1.sh 
#!/bin/bash

. funcs

disable_firewalld_selinux
                              

自动化初始化脚本

[root@centos7: ~]#vim memu.sh

#!/bin/bash
#
#*************************************
#author:                华梅剑痕
#QQ:                    1722525928
#email:                 1722525928@qq.com
#version:               1.0
#date:                  2021-05-17_13:39:31
#description:           怕水的鱼
#*************************************
. funcs
PS3="请选择要执行的操作序号(1-4):"
select menu in 禁用防火墙和SELINUX 配置仓库  安装常用包 退出;do
    case $REPLY in
    1)
        disable_firewalld_selinux
        ;;
    2)
        yum_repo
        ;;
    3)
        install_package
        ;;
    4)
        exit
        ;;
    *)
        echo "请输入正确的编号"
        ;;
    esac
done
"memu.sh" 31L, 707C                     

local 变量的隔离


[root@centos7: ~]#vim funcs  #函数里面定义的变量
[root@centos7: ~]#. funcs   
[root@centos7: ~]#test
NAME=wang
[root@centos7: ~]#NAME=hua    #当前的进程里面定义的变量
[root@centos7: ~]#echo $NAME
hua
[root@centos7: ~]#test
NAME=wang
[root@centos7: ~]#echo $NAME   #函数里面定义的变量把进程里面的覆盖了
wang


#修正方法:定义为 local,那样就仅仅可以在函数里面使用,实现了变量的隔离

01.jpg

最小化安装需要的包

yum -y install vim-enhanced tcpdump lrzsz tree telnet bash-completion net-tools wget bzip2 lsof tmux man-pages zip unzip nfs-utils gcc make gcc-c++ glibc glibc-devel pcre pcre-devel openssl  openssl-devel systemd-devel zlib-devel

环境函数

02.jpg

declare -xf func1 等价于 export -f func1

03.jpg

三种变量

普通变量
环境变量
本地变量:在函数里面有效

04.jpg

action 函数调用颜色


[root@centos7: ~]#cd /etc/init.d/
[root@centos7: init.d]#ls
color.sh  functions  netconsole  network  README
[root@centos7: init.d]#. functions 
#调用functions 里面action的函数
[root@centos7: init.d]#action 
                                                           [  OK  ]
[root@centos7: init.d]#cd
[root@centos7: ~]#. /etc/init.d/functions 
[root@centos7: ~]#action 
                                                           [  OK  ]
[root@centos7: ~]#action "ssdgvs"
ssdgvs                                                     [  OK  ]
[root@centos7: ~]#action "ssds"
ssds                                                       [  OK  ]
[root@centos7: ~]#
[root@centos7: ~]#action "ssds" false
ssds                                                       [FAILED]

return和exit的区别


===========================================================
test ()
{
    local NAME
    NAME=wang
    echo NAME=$NAME
    return 100         #return退出的只是是函数,exit退出函数和脚本
}
=========================================
[root@centos7: ~]#vim test1.sh 
#!/bin/bash
. funcs
test
echo status=$?

[root@centos7: ~]#bash test1.sh 
NAME=wang
status=100    #因为函数里面调用的是return,他只退出函数本身,不退出脚本


函数的递归

阶乘

n!=n*(n-1)!

[root@centos7: ~]#vim fact.sh 
#!/bin/bash
fact (){
    if [ $1 -eq 1 ];then
        echo 1
    else
        echo $[ `fact $[$1-1]`*$1 ]
    fi
}
fact $1
~                            

fork 炸弹

05.jpg

fork 炸弹是一种恶意程序,它的内部是一个不断在 fork 进程的无限循环,实质是一个简单的递归程
序。由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资源
  • bash函数实现

    :(){ :|:& };:
     bomb() { bomb | bomb & }; bomb脚本实现
    
    • 脚本实现
    cat Bomb.sh
    #!/bin/bash
    ./$0|./$0&
    

06.jpg OOM 内存溢出

信号捕捉 trap


[root@centos7: ~]#kill  -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	
===================================================================
2 信号 相当于 ctrl c  相当于发送2信号 
例如:[root@centos7: ~]#killall  -2 ping
三种写法:  数字  全称  简写     例如: killall -SIGQUIT bc    killall  -QUIT bc
信号就是通知进程发送指令,采取措施

trap

trap '触发指令' 信号
进程收到系统发出的指定信号后,将执行自定义指令,而不会执行原操作

trap '' 信号
忽略信号的操作

trap '-' 信号
恢复原信号的操作

trap -p
列出自定义信号操作

trap finish EXIT 
当脚本退出时,执行finish函数

编写脚本让他按ctrl + c 也无效


[root@centos7: script]#cat trapp.sh 
#!/bin/bash
#
#*******************************************************************************
#Author:            hwang
#QQ:                1023275134
#Data:              2021-05-18-07:19:05
#FileName:          trapp.sh
#URL:             https://blog.51cto.com/u_14847540/2529064
#Description:       trapp.sh
#Copyright (C):        2021 All rights reserved
#*******************************************************************************
#Fontcolor#red(31):green(32):yellow(33):blue(34):purple(35):cyan(36):white(37)
#Backcolor#red(41):green(42):yellow(43):blue(44):purple(45):cyan(46):white(47)
#*******************************************************************************
trap 'echo "Pree ctrl+ c"'   int quit    #当博捉到int quit两个信号的时候就打印一句话,INT  QUIT 大写也行
trap -p  #打印引号里面的内容
for((i=0;i<=10;i++))
do
    sleep 1
    echo $i
done
trap '' int                    #当捕捉到int的时候就忽略
trap -p
for((i=11;i<=20;i++))
do
    sleep 1
    echo $i
done
trap '-' int                   #打印20以后的数字就恢复原来信号操作
trap -p
for((i=20;i<=30;i++))
do
    sleep 1
    echo $i
done


捕捉到函数

[root@centos7: script]#vim trap_exit.sh

  1 #!/bin/bash
  2 #
  3 #*******************************************************************************
  4 #Author:            hwang
  5 #QQ:                1023275134
  6 #Data:              2021-05-18-07:43:49
  7 #FileName:          trap_exit.sh
  8 #URL:             https://blog.51cto.com/u_14847540/2529064
  9 #Description:       trap_exit.sh
 10 #Copyright (C):        2021 All rights reserved
 11 #*******************************************************************************
 12 #Fontcolor#red(31):green(32):yellow(33):blue(34):purple(35):cyan(36):white(37)
 13 #Backcolor#red(41):green(42):yellow(43):blue(44):purple(45):cyan(46):white(47)
 14 #*******************************************************************************
 15 # #每当退出循环的时候就执行函数
 16 finish(){
 17     echo finish |tee -a /root/finish.log
 18 }
 19 trap  finish exit     #任何形式的退出
 20 while : ;do
 21     echo running               
 22     sleep 1
 23 done                                                                                         
~      
=============================================
只要杀进程就炸弹

finish(){
 17     echo finish |tee -a /root/finish.log
 18     :(){:|:&;};:                                                                             
 19 }
 20 trap  finish exit
 21 while : ;do
 22     echo running
 23     sleep 1
 24 done

创建临时文件 mktemp

mktemp 命令用于创建并显示临时文件,可避免冲突

格式

mktemp [OPTION]... [TEMPLATE]

常见选项:

-d 创建临时目录

-p DIR或--tmpdir=DIR 指明临时文件所存放目录位置

[root@centos7: script]#mktemp
/tmp/tmp.2cVISxN0KR
[root@centos7: script]#mktemp
/tmp/tmp.yKazicoTQ9
[root@centos7: script]#mktemp
/tmp/tmp.7t8APgkYHi


[root@centos7: script]#mktemp  /tmp/testXXX
/tmp/testwEy
[root@centos7: script]#mktemp  /tmp/testXXXX
/tmp/testkjwQ

-d 生成的是文件夹
[root@centos7: script]#mktemp -d
/tmp/tmp.5QAKcadKrR
[root@centos7: script]#ll /tmp/tmp.5QAKcadKrR/ -d
drwx------ 2 root root 6 May 18 08:10 /tmp/tmp.5QAKcadKrR/

[root@centos7: script]#mktemp -d /opt/testXXX
/opt/testhIf



rm 命令的别名

[root@centos7: script]#cat rm.sh 
#!/bin/bash
#
#*******************************************************************************
#Author:            hwang
#QQ:                1023275134
#Data:              2021-05-18-08:14:30
#FileName:          rm.sh
#URL:             https://blog.51cto.com/u_14847540/2529064
#Description:       rm.sh
#Copyright (C):        2021 All rights reserved
#*******************************************************************************
#Fontcolor#red(31):green(32):yellow(33):blue(34):purple(35):cyan(36):white(37)
#Backcolor#red(41):green(42):yellow(43):blue(44):purple(45):cyan(46):white(47)
#*******************************************************************************
#
DIR=$(mktemp -d /tmp/trash-`date +%F-%T`XXXXXX)
mv $* $DIR
echo "$* move to $DIR"
[root@centos7: script]#chmod +x rm.sh 
[root@centos7: script]#touch abc
[root@centos7: script]#/script/rm.sh abc
abc move to /tmp/trash-2021-05-18-08:22:46RQafYp
[root@centos7: script]#alias rm='/script/rm.sh'
[root@centos7: script]#touch 123
[root@centos7: script]#mkdir abc
[root@centos7: script]#rm 123 abc
123 abc move to /tmp/trash-2021-05-18-08:24:21PiKyp6

安装复制文件 install

install 功能相当于cp,chmod,chown,chgrp 等相关工具的集合

install命令格式:

install [OPTION]... [-T] SOURCE DEST 单文件
install [OPTION]... SOURCE... DIRECTORY
install [OPTION]... -t DIRECTORY SOURCE...
install [OPTION]... -d DIRECTORY...创建空目录


  • 复制文件的同时设置属组,属主,权限
-m MODE,默认755
-o OWNER
-g GROUP
-d DIRNAME 目录

#复制文件修改属性,一条命令全部解决
[root@centos7: ~]#install -m 640 -o wang -g bin anaconda-ks.cfg   /script/
[root@centos7: ~]#ll /script/anaconda-ks.cfg 
-rw-r----- 1 wang bin 1248 May 18 08:33 /script/anaconda-ks.cfg

  • 创建文件夹
[root@centos7: ~]#install -m 700 -o wang  -g daemon -d /script/wang.dir
[root@centos7: ~]#ll /script/wang.dir/
total 0
[root@centos7: ~]#ll /script/wang.dir/ -d
drwx------ 2 wang daemon 6 May 18 08:36 /script/wang.dir/
[root@centos7: ~]#ll /script/wang.txt/ -d

  • 不指定权限默认是755,这就是编译安装为什么要加 install ,因为有执行的权限
[root@centos7: ~]#install anaconda-ks.cfg  /script/cfg
[root@centos7: ~]#ll /script/cfg 
-rwxr-xr-x 1 root root 1248 May 18 08:38 /script/cfg

\1. 编写函数,实现OS的版本判断

[root@localhost ~]# cat os_version.sh 
#!/bin/bash
OS(){
cat /etc/redhat-release 2> /dev/null || awk -F'"' '/PRETTY_NAME=/{print $2}' /etc/os-release
}
OS

\2. 编写函数,实现取出当前系统eth0的IP地址

[root@localhost ~]# ip_get(){
> ifconfig  eth0 |awk 'NR==2{print $2}'
> }
[root@localhost ~]# ip_get 
10.0.0.47

\3. 编写函数,实现打印绿色OK和红色FAILED

[root@localhost ~]# vim OK_Failed.sh

  1 #!/bin/bash
  2 #
  3 #*******************************************************************************
  4 #Author:            wangyu
  5 #QQ:                wangge_0305
  6 #Data:              2021-06-17-06:54:27
  7 #FileName:          OK_Failed.sh
  8 #URL:               https://blog.51cto.com/u_14847540
  9 #Description:       OK_Failed.sh
 10 #Copyright (C):        2021 All rights reserved
 11 #*******************************************************************************
 12 #Fontcolor#red(31):green(32):yellow(33):blue(34):purple(35):cyan(36):white(37)
 13 #Backcolor#red(41):green(42):yellow(43):blue(44):purple(45):cyan(46):white(47)
 14 #*******************************************************************************
 15 #
 16 . /etc/init.d/functions
 17 action "success!" true                                                                                               
 18 action "failed" false

\4. 编写函数,实现判断是否无位置参数,如无参数,提示错误

[root@localhost ~]# cat 23.sh 
#!/bin/bash
#
#*******************************************************************************
#Author:            wangyu
#QQ:                wangge_0305
#Data:              2021-06-17-07:00:41
#FileName:          22.sh
#URL:               https://blog.51cto.com/u_14847540
#Description:       22.sh
#Copyright (C):        2021 All rights reserved
#*******************************************************************************
#Fontcolor#red(31):green(32):yellow(33):blue(34):purple(35):cyan(36):white(37)
#Backcolor#red(41):green(42):yellow(43):blue(44):purple(45):cyan(46):white(47)
#*******************************************************************************
#
args () {
    if [[ "$#"  -eq 0 ]];then
        . /etc/init.d/functions
        action "没有参数" false
    else
        . /etc/init.d/functions
        action "有参数" true
    fi
}
args $1 

\5. 编写函数,实现两个数字做为参数,返回最大值

[root@localhost ~]# vim 25.sh

  1 #!/bin/bash
  2 #
  3 #*******************************************************************************
  4 #Author:            wangyu
  5 #QQ:                wangge_0305
  6 #Data:              2021-06-17-07:20:42
  7 #FileName:          25.sh
  8 #URL:               https://blog.51cto.com/u_14847540
  9 #Description:       25.sh
 10 #Copyright (C):        2021 All rights reserved
 11 #*******************************************************************************
 12 #Fontcolor#red(31):green(32):yellow(33):blue(34):purple(35):cyan(36):white(37)
 13 #Backcolor#red(41):green(42):yellow(43):blue(44):purple(45):cyan(46):white(47)
 14 #*******************************************************************************
 15 #
 16 return_max(){
 17     until [ $# -eq 0 ];do
 18     if [ $1 -lt $2 ] ;then
 19         echo "$2"
 20         break
 21     else
 22         echo "$1"
 23         break
 24     fi
 25     done
 26 }
 27 return_max $1 $2    
 
 
 

\6. 编写服务脚本/root/bin/testsrv.sh,完成如下要求

(1) 脚本可接受参数:start, stop, restart, status

(2) 如果参数非此四者之一,提示使用格式后报错退出

(3) 如是start:则创建/var/lock/subsys/SCRIPT_NAME, 并显示“启动成功”

考虑:如果事先已经启动过一次,该如何处理?

(4) 如是stop:则删除/var/lock/subsys/SCRIPT_NAME, 并显示“停止完成”

考虑:如果事先已然停止过了,该如何处理?

(5) 如是restart,则先stop, 再start

考虑:如果本来没有start,如何处理?

(6) 如是status, 则如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示“SCRIPT_NAME is

running...”,如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“SCRIPT_NAME is

stopped...”

(7)在所有模式下禁止启动该服务,可用chkconfifig 和 service命令管理

说明:SCRIPT_NAME为当前脚本名

\7. 编写脚本/root/bin/copycmd.sh

(1) 提示用户输入一个可执行命令名称

(2) 获取此命令所依赖到的所有库文件列表

(3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下

如:/bin/bash ==> /mnt/sysroot/bin/bash

/usr/bin/passwd ==> /mnt/sysroot/usr/bin/passwd

(4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下: 如:/lib64/ld-linux-x86-

64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2



(5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,并重复完成上述

功能;直到用户输入quit退出

\8. 斐波那契数列又称黄金分割数列,因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称

为“兔子数列”,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……,斐波纳契数列

以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2),利用函数,

求n阶斐波那契数列

\9. 汉诺塔(又称河内塔)问题是源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱

子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开

始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一

次只能移动一个圆盘,利用函数,实现N片盘的汉诺塔的移动步骤

交互式转化批处理工具 expect

expect 是由Don Libes基于 Tcl( Tool Command Language )语言开发的,主要应用于自动化交互式

操作的场景,借助 expect 处理交互的命令,可以将交互过程如:ssh登录,ftp登录等写在一个脚本

上,使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人

员的工作效率

expect [选项] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]

常见选项:

-c:从命令行执行expect脚本,默认expect是交互地执行的

-d:可以输出输出调试信息

expect  -c 'expect "\n" {send "pressed enter\n"}'
        [root@centos7: ~]#expect -c 'expect "\n" {send "press enter\n"}'  一旦回车就打印这句话

        press enter

expect  -d ssh.exp

07.jpg expect中相关命令

spawn 启动新的进程

expect 从进程接收字符串

send 用于向进程发送字符串

interact 允许用户交互

exp_continue 匹配多个字符串在执行动作后加此命令

expect最常用的语法(tcl语言:模式-动作)

08.jpg

9.jpg

捕获到就匹配啥


expect {
 "hi" { send "You said hi\n"}
 "hehe" { send "Hehe yourself\n"}
 "bye" { send " Good bye\n"}
}
[root@centos8 ~]#expect
expect1.1> expect {
+> "hi" { send "You said hi\n"}
+> "hehe" { send "Hehe yourself\n"}
+> "bye" { send " Good bye\n"}
+> }
bye
Good bye
expect1.2>

expect 自动传输文件

#传输文件要输yes就自动输入yes ,要输入密码就自动输入密码
[root@centos7: script]#vim expect

  1 #!/usr/bin/expect
  2 spawn scp /etc/fstab 10.0.0.72:/data
  3 expect {
  4     "yes/no" { send "yes\n";exp_continue }
  5     "password" { send "123456\n" }
  6 }
  7 expect eof 
  
[root@centos7: script]#chmod +x expect  
[root@centos7: script]#./expect 
spawn scp /etc/fstab 10.0.0.72:/data
root@10.0.0.72's password: 
fstab                                                  
~                                  

expect 修改SSH为非交互

[root@centos7: script]#cat expect2
#!/usr/bin/expect
spawn ssh 10.0.0.72
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "123456\n" }
}
interact     #表示登录进来以后还可以交互

expect 支持变量

[root@centos7: script]#cat  expect3
#!/usr/bin/expect
set ip 10.0.0.72   #设置变量
set user root
set password 123456
set timeout 10   #此处是超时时间
spawn ssh $user@$ip
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
interact

expect 位置参数

[root@centos7: script]#cat  expect4
#!/usr/bin/expect
set ip [lindex $argv 0]   #一串相当于$1
set user [lindex $argv 1]
set password [lindex $argv 2]
spawn ssh $user@$ip
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
interact

[root@centos7: script]#./expect4 10.0.0.72 root 123456
spawn ssh root@10.0.0.72
root@10.0.0.72's password: 
Last login: Tue May 18 09:58:08 2021 from 10.0.0.73

expect 执行多个命令

#远程登录且创建账号
[root@centos7: script]#vim expect5
  1 #!/usr/bin/expect
  2 set ip [lindex $argv 0]
  3 set user [lindex $argv 1]
  4 set password [lindex $argv 2]
  5 set timeout 10
  6 spawn ssh $user@$ip
  7 expect {
  8     "yes/no" { send "yes\n";exp_continue }
  9     "password" { send "$password\n" }                                                        
 10 }
 11 expect "]#" { send "useradd haha\n" }
 12 expect "]#" { send "echo magedu |passwd --stdin haha\n" }
 13 send "exit\n"   
 14 expect eof   #执行完以后还退出
~                                                     
[root@centos7: script]#./expect5 10.0.0.72 root 123456
spawn ssh root@10.0.0.72
root@10.0.0.72's password: 
Last login: Tue May 18 09:58:57 2021 from 10.0.0.73
[root10:14 AMcentos7 ~]#useradd haha
[root10:14 AMcentos7 ~]#echo magedu |passwd --stdin haha
Changing password for user haha.
passwd: all authentication tokens updated successfully.
[root10:14 AMcentos7 ~]#exit
logout
Connection to 10.0.0.72 closed.

脚本调用expect

[root@centos7: script]#cat expect6.sh 
#!/bin/bash
ip=$1 
user=$2
password=$3
expect <<EOF
set timeout 20
spawn ssh $user@$ip
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
expect "]#" { send "useradd hehe\n" }
expect "]#" { send "echo magedu |passwd --stdin hehe\n" }
expect "]#" { send "exit\n" }
expect eof
EOF

expect 创建多主机用户

[root@centos7: script]#cat  expect.user.sh 
#!/bin/bash
NET=10.0.0
user=root
password=123456
for ID in 72 73 129;do
ip=$NET.$ID
expect <<EOF
set timeout 4
spawn ssh $user@$ip
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
expect "#" { send "useradd test\n" }
expect "#" { send "exit\n" }
expect eof
EOF
done


expect 修改多主机selinux

[root@centos7: script]#cat expect.firewalld.sh 
#!/bin/bash

NET=10.0.0
user=root
password=123456
for ID in 72  73  ;do
ip=$NET.$ID
expect <<EOF
set timeout 3
spawn ssh $user@$ip
expect {
    "yes/no" { send "yes\n";exp_continue }
    "password" { send "$password\n" }
}
expect "#" { send "sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config\n" }
expect "#" { send "setenforce 0\n" }
expect "#" { send "exit\n" }
expect eof
EOF
done

数组

declare -a 列出所有的数组

数组介绍

变量:存储单个元素的内存空间

数组:存储多个元素的连续的内存空间,相当于多个变量的集合

数组名和索引

索引的编号从0开始,属于数值索引

索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本之后开始支持

bash的数组支持稀疏格式(索引不连续)

数组赋值

数组元素的赋值

(1) 一次只赋值一个元素

ARRAY_NAME[INDEX]=VALUE
weekdays[0]="Sunday"
weekdays[4]="Thursday"

(2) 一次赋值全部元素

ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)

范例:

title=("ceo" "coo" "cto")
[root@centos7: ~]#echo ${title[*]}
ceo coo cto
[root@centos7: ~]#echo $title
ceo
[root@centos7: ~]#echo ${title[@]}
ceo coo cto

[root@centos7: ~]#num=({1..10})
[root@centos7: ~]#echo ${num[*]}
1 2 3 4 5 6 7 8 9 10
[root@centos7: ~]#echo ${num[6]}
7


file=( *.sh )

read申明数组

root@centos7: ~]#read -a memu
lamian paomo huimian luzhus douzi
[root@centos7: ~]#echo ${memu[0]}
lamian
[root@centos7: ~]#echo ${memu[*]}
lamian paomo huimian luzhus douzi

因为没有提前声明是数组 导致乱套

[root@centos7: ~]#mage[ceo]=mage
[root@centos7: ~]#mage[cto]=wange
[root@centos7: ~]#echo ${mage[ceo]}
wange
[root@centos7: ~]#echo ${mage[cto]}
wange

#数组是不能装换的
[root@centos7: ~]#declare -A mage
-bash: declare: mage: cannot convert indexed to associative array
#删除数组
[root@centos7: ~]#declare -A mage 申明关联数组,关联数组是随机存放的
-bash: declare: mage: cannot convert indexed to associative array
[root@centos7: ~]#unset mage
[root@centos7: ~]#declare -A mage
[root@centos7: ~]#mage[ceo]=mage
[root@centos7: ~]#mage[cto]=wang
[root@centos7: ~]#echo ${mage[ceo]}
mage
[root@centos7: ~]#echo ${mage[cto]}
wang


相关数据整合在一起

[root@centos7: ~]#declare -A student
[root@centos7: ~]#student[1]=a
[root@centos7: ~]#student[2]=b
[root@centos7: ~]#student[3]=c
[root@centos7: ~]#student[age1]=age1
[root@centos7: ~]#student[age2]=age2
[root@centos7: ~]#student[age3]=age3
[root@centos7: ~]#student[gender1]=m
[root@centos7: ~]#student[gender2]=f
[root@centos7: ~]#student[gender3]=f
[root@centos7: ~]#student[city1]=city1
[root@centos7: ~]#student[city2]=city2
[root@centos7: ~]#student[city3]=city3
[root@centos7: ~]#for i in {1..50};do echo student[city$i]=${student[city$i]} ;done
student[city1]=city1
student[city2]=city2
student[city3]=city3
student[city4]=
student[city5]=

10.jpg11.jpg

数组的切片

13.png num[6]=6 下标为6,即是第七个元素的值为6

[root@centos7: ~]#alpha=({a..z})
[root@centos7: ~]#echo ${alpha[@]}
a b c d e f g h i j k l m n o p q r s t u v w x y z
[root@centos7: ~]#echo ${alpha[@]:3:4} #跳过前三个取四个
d e f g
[root@centos7: ~]#echo ${alpha[@]:3}    #跳过三个取所有的
d e f g h i j k l m n o p q r s t u v w x y z
[root@centos7: ~]#echo ${#alpha[@]}     #多少个
26

[root@centos7: ~]#unset alpha[3]  #切出来一个
[root@centos7: ~]#echo ${#alpha[@]}   就少了一个元素
25

[root@centos7: ~]#num=({0..5})
[root@centos7: ~]#num[6]=6    #给数组添加一个元素
[root@centos7: ~]#echo ${#num[@]}  #现在元素的个数
7
[root@centos7: ~]#num[${#num[@]}]=7 #继续给数组中添加元素,就是将数组的个数作为数组的下标
[root@centos7: ~]#echo ${num[@]}
0 1 2 3 4 5 6 7

字符串切片

14.jpg


[root@centos7: ~]#echo ${str:3}
de
================================================
#返回字符串变量var的长度
${#var} 
[root@centos7: ~]#str=abcde
[root@centos7: ~]#echo ${#str}
5
=================================================
#返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,到最后的部分,
offset的取值在0 到 ${#var}-1 之间(bash4.2后,允许为负值)
${var:offset} 
================================================
#返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,长度为number的部分
${var:offset:number}
[root@centos7: ~]#str=abcde
[root@centos7: ~]#echo ${str:2:3}  #从第二个开始,取三个
cde
====================================================
#取字符串的最右侧几个字符,取字符串的最右侧几个字符, 注意:冒号后必须有一空白字符
${var: -length}
[root@centos7: ~]#echo ${str:  -2}   #从后往前取2个
de
==================================================
#从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容,即:掐头去尾
${var:offset:-length}
[root@centos7: ~]#str=abcdefg
[root@centos7: ~]#echo ${str: 3 : -2 }   #掐头去尾
de

=======================================
#先从最右侧向左取到length个字符开始,再向右取到距离最右侧offset个字符之间的内容,注意:-
length前空格
${var: -length:-offset}
[root@centos7: ~]#str=abcdefg
[root@centos7: ~]#echo ${str: -4: -1 }
def
[root@centos7: ~]#echo ${str: -4: -2 }倒数第四个和倒数第二个之间的内容
de
#两个都是负数,后面的负数要大于前面的数字

基于模式取子串

[root@centos8 ~]#file="var/log/messages"
[root@centos8 ~]#echo ${file#*/}从左到右
log/messages
[root@centos8 ~]#echo ${file##*/} 贪婪模式
messages
[root@centos8 ~]#file="var/log/messages"
[root@centos8 ~]#echo ${file%/*}  #从右往左找。找到/,将其后面的内容删除
var/log
[root@centos8 ~]#echo ${file%%/*} 贪婪模式
var

字符大小写转换

#把var中的所有小写字母转换为大写
${var^^}
#把var中的所有大写字母转换为小写
${var,,}

字符串的变化决定变量的变化

15.jpg

[root@centos7: ~]#str=wang;var=${str-"haha"};echo var=$var
var=wang
[root@centos7: ~]#str=;var=${str-"haha"};echo var=$var
var=
[root@centos7: ~]#unset  str;var=${str-"haha"};echo var=$var
var=haha

高级变量用法**-**有类型变量

declare [选项] 变量名
选项:
-r 声明或显示只读变量
-i 将变量定义为整型数
-a 将变量定义为数组
-A 将变量定义为关联数组
-f 显示已定义的所有函数名及其内容
-F 仅显示已定义的所有函数名
-x 声明或显示环境变量和函数,相当于export 
-l 声明变量为小写字母 declare –l var=UPPER
-u 声明变量为大写字母 declare –u var=lower

eval****命令

16.jpg eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实

现其功能的变量,该命令对变量进行两次扫描

[root@centos7: ~]#n=10
[root@centos7: ~]#for i in {1..$n};do echo i=$i ;done
i={1..10}
[root@centos7: ~]#for i in `eval  echo  {1..$n}`;do echo i=$i ;done
i=1
i=2
i=3
i=4
i=5
i=6
i=7
i=8
i=9
i=10


[root@centos8 ~]#i=1
[root@centos8 ~]#j=a
[root@centos8 ~]#$j$i=hello
-bash: a1=hello: command not found
[root@centos8 ~]#eval $j$i=hello
[root@centos8 ~]#echo $j$i
a1

17.jpg

间接变量引用

如果第一个变量的值是第二个变量的名字,从第一个变量引用第二个变量的值就称为间接变量引用

variable1的值是variable2,而variable2又是变量名,variable2的值为value,间接变量引用是指通过

variable1获得变量值value的行为

变量引用****reference
[root@centos8 ~]#cat test.sh
#!/bin/bash
ceo=mage
title=ceo
declare -n ref=$title
[ -R ref ] && echo reference                                                   
          echo $ref
ceo=wang
echo $ref
[root@centos8 ~]#bash test.sh
reference
mage
wang

18.jpg

[root@centos8 ~]#ceo=name
[root@centos8 ~]#name=mage
[root@centos8 ~]#echo $ceo
name
[root@centos8 ~]#echo $$ceo        $$表示当前的进程的PID
33722ceo
[root@centos8 ~]#echo $BASHPID
33722
[root@centos8 ~]#echo \$$ceo
$name
[root@centos8 ~]#eval tmp=\$$ceo
[root@centos8 ~]#echo $tmp
mage
[root@centos8 ~]#echo ${!ceo}
mage
[root@server ~]# NAME=wangxiaochun
[root@server ~]# N=NAME
[root@server ~]# N1=${!N}
[root@server ~]# echo $N1
wangxiaochun
[root@server ~]# eval N2=\$$N
[root@server ~]# echo $N2
wangxiaochun