shell脚本编程

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 脚本调试

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

bash -n /path/to/some_script

调试并执行php

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

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

​ 语法错误,会致使后续的命令不继续执行,能够用bash -n 检查错误,提示的出错行数不必定是准java

​ 确的node

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

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

变量

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

变量类型

变量类型:
内置变量,如: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
局部变量小写
函数名小写

变量定义和引用

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

普通变量:生效范围为当前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

shell脚本编程

shell脚本编程
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 里面的覆盖了

练习

一、让全部用户的PATH环境变量的值多出一个路径,例如:/usr/local/apache/bin
二、用户 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)
三、任意用户登陆系统时,显示红色字体的警示提醒信息“Hi,dangerous!” 四、编写生成脚本基本格式的脚本,包括做者,联系方式,版本,时间,描述等

答案:第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"

练习

一、编写脚本 createuser.sh,实现以下功能:使用一个用户名作为参数,若是指定参数的用户存在,就
显示其存在,不然添加之。并设置初始密码为123456,显示添加的用户的id号等信息,在此新用户第一
次登陆时,会提示用户当即改密码,若是没有参数,就提示:请输入用户名
二、编写脚本 yesorno.sh,提示用户输入yes或no,并判断用户输入的是yes仍是no,或是其它信息
三、编写脚本 filetype.sh,判断用户输入文件路径,显示其文件类型(普通,目录,连接,其它文件类
型)
四、编写脚本 checkint.sh,判断用户输入的参数是否为正整数
五、编写脚本 reset.sh,实现系统安装后的初始化环境,包括:一、别名 二、环境变量,如PS1等 三、
安装经常使用软件包,如:tree 五、实现固定的IP的设置,六、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

练习

一、每隔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

二、随机生成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

三、用文件名作为参数,统计全部参数文件的总行数

[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

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

[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,那样就仅仅能够在函数里面使用,实现了变量的隔离

shell脚本编程
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

环境函数

shell脚本编程
02.jpg

declare -xf func1 等价于 export -f func1

shell脚本编程
03.jpg

三种变量

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

shell脚本编程
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 炸弹

shell脚本编程
05.jpg

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

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

shell脚本编程
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三、2一、3四、……,斐波纳契数列

以以下被以递归的方法定义: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

shell脚本编程
07.jpg
expect中相关命令

spawn 启动新的进程

expect 从进程接收字符串

send 用于向进程发送字符串

interact 容许用户交互

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

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

shell脚本编程
08.jpg

shell脚本编程
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]=

shell脚本编程

shell脚本编程

10.jpg11.jpg

数组的切片

shell脚本编程
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

字符串切片

shell脚本编程
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,,}

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

shell脚本编程

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**命令**

shell脚本编程
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

shell脚本编程
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

shell脚本编程
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
相关文章
相关标签/搜索