内容概述
1 编程基础
Linus:Talk is cheap, show me the code
1.1 程序组成
程序:算法+数据结构
算法:处理数据的方式
数据结构:数据在计算机中的类型和组织方式
数据:是程序的核心,程序为数据提供服务
1.2 程序编程风格
面向过程语言
做一件事情,排出个步骤,第一步干什么,第二步干什么,如果出现情况A,做什么处理,如
果出现了情况B,做什么处理
问题规模小,可以步骤化,按部就班处理
以指令为中心,数据服务于指令
C,shell
面向对象语言
将编程看成是一个事物,对外界来说,事物是直接使用的,不用关心事物内部的情况。而编程
就是设置事物能够完成功能。
一种认识世界、分析世界的方法论。将万事万物抽象为各种对象
类是抽象的概念,是万事万物的抽象,是一类事物的共同特征的集合
对象是类的具体实现,是一个实体
问题规模大,复杂系统
以数据为中心,指令服务于数据
java,C#,python,golang等
1.3 编程语言
编程语言排名链接
TIBOE 2021 年 1 月的最新编程语言流行度排名
https://www.tiobe.com/tiobe-index/
计算机:运行二进制指令
编程语言:人与计算机之间交互的语言。分为两种:低级语言和高级语言
低级编程语言:
机器:二进制的0和1的序列,称为机器指令。与自然语言差异太大,难懂、难写
汇编:用一些助记符号替代机器指令,称为汇编语言
如:ADD A,B 将寄存器A的数与寄存器B的数相加得到的数放到寄存器A中
汇编语言写好的程序需要汇编程序转换成机器指令
汇编语言稍微好理解,即机器指令对应的助记符,助记符更接近自然语言
高级编程语言:
编译:高级语言-->编译器-->机器代码文件-->执行,如:C,C++
解释:高级语言-->执行-->解释器-->机器代码,如:shell,python,php,JavaScript,perl
编译和解释型语言
1.4 编程逻辑处理方式
三种处理逻辑
顺序执行:程序按从上到下顺序执行
选择执行:程序执行过程中,根据条件的不同,进行选择不同分支继续执行
循环执行:程序执行过程中需要重复执行多次某段语句
2 shell 脚本语言的基本用法
2.1 shell 脚本的用途
将简单的命令组合完成复杂的工作,自动化执行命令,提高工作效率
减少手工命令的输入,一定程度上避免人为错误
将软件或应用的安装及配置实现标准化
用于实现日常性的,重复性的,非交互式的运维工作,如:文件打包压缩备份,监控系统运行状态并实现告
警等
2.2 shell 脚本基本结构
shell脚本编程:是基于过程式、解释执行的语言
编程语言的基本结构:
各种系统命令的组合
数据存储:变量、数组
表达式:a + b
控制语句:if
shell脚本:包含一些命令或声明,并符合一定格式的文本文件
格式要求:首行shebang机制
2.3 shell脚本创建过程
第一步:使用文本编辑器来创建文本文件
第一行必须包括shell声明序列:#!
示例:
添加注释,注释以#开头
第二步:加执行权限
给予执行权限,在命令行上指定脚本的绝对或相对路径
第三步:运行脚本
直接运行解释器,将脚本作为解释器程序的参数运行
2.4 shell 脚本注释规范
1、第一行一般为调用使用的语言
2、程序名,避免更改文件名为无法找到正确的文件
3、版本号
4、更改后的时间
5、作者相关信息
6、该程序的作用,及注意事项
7、最后是各版本的更新简要说明
2.5 第一个 shell 脚本
范例:第一个 Shell 脚本 hello world
参考文档:
https://zh.wikipedia.org/wiki/Hello_World程序样例)
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
#!/usr/bin/ruby
#!/usr/bin/lua
#!/bin/bash
#!SHEBANG
CONFIGURATION_VARIABLES
FUNCTION_DEFINITIONS
MAIN_CODE
https://zh.wikipedia.org/wiki/Hello_World
https://zh.wikipedia.org/wiki/Hello_World程序样例
[root@centos8 ~]#vim /data/hello.sh
#!/bin/bash
# ------------------------------------------
# Filename: hello.sh
# Version: 1.0
# Date: 2017/06/01
# Author: wang
# Email: 29308620@qq.com
# Website: www.wangxiaochun.com
# Description: This is the first script
# Copyright: 2017 wang
# License: GPL
# ------------------------------------------
#经典写法
echo "hello, world"
#流行写法
echo 'Hello, world!'
#执行方法1
[root@centos8 ~]#bash /data/hello.sh
#执行方法2
[root@centos8 ~]#cat /data/hello.sh | bash
#执行方法3
[root@centos8 ~]#bash < /data/hello.sh
#执行方法4
[root@centos8 ~]#chmod +x /data/hello.sh
#绝对路径
[root@centos8 ~]#/data/hello.sh
#相法路径
[root@centos8 ~]#cd /data/
[root@centos8 ~]#./hello.sh
#执行方法5,本方法可以实现执行远程主机的shell脚本
[root@centos8 ~]#yum -y install httpd
[root@centos8 ~]#systemctl start httpd
[root@centos8 ~]#mv /data/hello.sh /var/www/html/
[root@centos8 ~]#curl http://10.0.0.8/hello.sh
#!/bin/bash
# ------------------------------------------
# Filename: hello.sh
# Version: 1.0
# Date: 2017/06/01
# Author: wang
# Email: 29308620@qq.com
# Website: www.wangxiaochun.com
# Description: This is the first script
# Copyright: 2017 wang
# License: GPL
# ------------------------------------------
#经典写法
echo "hello, world"
#流行写法
echo 'Hello, world!'
范例:执行远程主机的脚本
范例:在远程主机运行本地shell脚本
范例:备份脚本
[root@centos8 ~]#curl http://10.0.0.8/hello.sh |bash % Total % Received % Xferd Average Speed Time Time | Time Current | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
Dload Upload Total Spent | Left Speed | |||||||||
100 | 388 | 100 | 388 | 0 | 0 | 378k | 0 | --:--:-- | --:--:-- | --:--:-- 378k |
hello, world Hello, world! [root@centos8 ~]#curl -s http://10.0.0.8/hello.sh |bash hello, world Hello, world! [root@centos8 ~]#curl http://10.0.0.8/hello.sh 2>/dev/null |bash hello, world Hello, world! [root@centos8 ~]#curl http://10.0.0.8/hello.sh >/dev/null |bash % Total % Received % Xferd Average Speed Time Time | Time Current | |||||||||
Dload Upload Total Spent | Left Speed | |||||||||
100 | 388 | 100 | 388 | 0 | 0 | 378k | 0 | --:--:-- | --:--:-- | --:--:-- 378k |
[root@centos8 ~]#wget -qO - http://www.wangxiaochun.com/testdir/hello.sh | bash
hello, world
Hello, world!
[root@centos8 ~]#curl http://www.wangxiaochun.com/testdir/hello.sh |bash
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 388 100 388 0 0 16869 0 --:--:-- --:--:-- --:--:-- 16869
hello, world
Hello, world!
[root@centos8 ~]#curl -s http://www.wangxiaochun.com/testdir/hello.sh |bash
[root@centos8 ~]#curl http://www.wangxiaochun.com/testdir/hello.sh 2>/dev/null |
bash
hello, world
Hello, world!
[root@centos8 ~]#wget -qO - http://www.wangxiaochun.com/testdir/hello.sh |bash
hello, world
Hello, world!
[root@centos8 ~]#hostname -I
10.0.0.8
[root@centos8 ~]#cat test.sh
#!/bin/bash
hostname -I
[root@centos8 ~]#ssh 10.0.0.18 /bin/bash < test.sh
root@10.0.0.18's password:
10.0.0.18
#!/bin/bash
2.6 shell 脚本调试
只检测脚本中的语法错误,但无法检查出命令错误,但不真正执行脚本
调试并执行
范例:
总结:脚本错误常见的有三种
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-20
#FileName: backup.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
echo -e "\033[1;32mStarting backup...\033[0m"
sleep 2
cp -av /etc/ /data/etc`date +%F`/
echo -e "\033[1;32mBackup is finished\033[0m"
bash -n /path/to/some_script
bash -x /path/to/some_script
[root@centos8 scripts]#cat -A test.sh
#!/bin/bash$
#$
#$
#Author:IIwangxiaochun$
#QQ: II^I29308620$
#Date: II^I2020-04-01$
#FileNameM-oM-<M-ZI^Itest.sh$
#URL: II^Ihttp://www.magedu.com$
#DescriptionM-oM-<M-ZI^IThe test script$
#Copyright (C): ^I2020 All rights reserved$
#$
echo line1$
hostnam$
cat > test.txt <<EOF $
aaa$
bbb$
ccc$
EOF $
$
echo line22$
[root@centos8 scripts]#bash -n test.sh
f1.sh: line 20: warning: here-document at line 14 delimited by end-of-file
(wanted `EOF')
语法错误,会导致后续的命令不继续执行,可以用bash -n 检查错误,提示的出错行数不一定是准
确的
命令错误,默认后续的命令还会继续执行,用bash -n 无法检查出来 ,可以使用 bash -x 进行观察
逻辑错误:只能使用 bash -x 进行观察
2.7 变量
2.7.1 变量
变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据
2.7.2 变量类型
变量类型:
内置变量,如:PS1,PATH,UID,HOSTNAME,$$,BASHPID,PPID,$?,HISTSIZE
用户自定义变量
不同的变量存放的数据不同,决定了以下
数据存储方式
参与的运算
表示的数据范围
变量数据类型:
字符
数值:整型、浮点型,bash 不支持浮点数
2.7.3 编程语言分类
静态和动态语言
静态编译语言:使用变量前,先声明变量类型,之后类型不能改变,在编译时检查,如:java,c
动态编译语言:不用事先声明,可随时改变类型,如:bash,Python
强类型和弱类型语言
强类型语言:不同类型数据操作,必须经过强制转换才同一类型才能运算,如: java , c# ,
python
如:参考以下 python 代码
print('magedu'+ 10) 提示出错,不会自动转换类型
print('magedu'+str(10)) 结果为magedu10,需要显示转换类型
弱类型语言:语言的运行时会隐式做数据类型转换。无须指定类型,默认均为字符型;参与运算会
自动进行隐式类型转换;变量无须事先定义可直接调用
如:bash ,php,javascript
2.7.4 Shell中变量命名法则
2.7.4.1 命名要求
区分大小写
不能使程序中的保留字和内置变量:如:if, for
只能使用数字、字母及下划线,且不能以数字开头,注意:不支持短横线 “ - ”,和主机名相反
2.7.4.2 命名习惯
见名知义,用英文单词命名,并体现出实际作用,不要用简写,如:ATM
变量名大写
局部变量小写
函数名小写
大驼峰StudentFirstName,由多个单词组成,且每个单词的首字母是大写,其它小写
小驼峰studentFirstName ,由多个单词组成,第一个单词的首字母小写,后续每个单词的首字母是
大写,其它小写
下划线: student_name
2.7.5 变量定义和引用
变量的生效范围等标准划分变量类型
普通变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell
进程均无效
环境变量:生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片断,通常指函数
变量赋值:
value 可以是以下多种形式
注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存,脚本中的变量会随着脚
本结束,也会自动删除
变量引用:
name='value'
直接字串:name='root'
变量引用:name="$USER"
命令引用:name=COMMAND
或者 name=$(COMMAND)
弱引用和强引用
"$name" 弱引用,其中的变量引用会被替换为变量值
'$name' 强引用,其中的变量引用不会被替换为变量值,而保持原字符串
范例:变量的各种赋值方式和引用
$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
[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
[root@centos8 ~]#NAMES="wang
> zhang
> zhao
> li"
[root@centos8 ~]#echo $NAMES
wang zhang zhao li
[root@centos8 ~]#echo "$NAMES"
wang
zhang
zhao
li
[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
20
[root@centos8 data]#echo ${NAME}_$AGE
mage_20
[root@centos8 ~]#TITLE=cto
[root@centos8 ~]#NAME=wang
[root@centos8 ~]#TITLE=$NAME
[root@centos8 ~]#echo $NAME
wang
[root@centos8 ~]#echo $TITLE
wang
[root@centos8 ~]#NAME=mage
[root@centos8 ~]#echo $NAME
mage
[root@centos8 ~]#echo $TITLE
wang
范例:利用变量实现动态命令
显示已定义的所有变量:
删除变量:
范例:
范例:显示系统信息
[root@centos8 ~]#TITLE=CTO
[root@centos8 ~]#TITLE+=:wang
[root@centos8 ~]#echo $TITLE
CTO:wang
[root@centos8 ~]#CMD=hostname
[root@centos8 ~]#$CMD
centos8.wangxiaochun.com
set
unset
[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
[root@centos8 scripts]#cat systeminfo.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-23
#FileName: systeminfo.sh
#URL: http://www.magedu.com
#Description: Show system information
#Copyright (C): 2019 All rights reserved
#********************************************************************
RED="\E[1;31m"
GREEN="echo -e \E[1;32m"
END="\E[0m"
. /etc/os-release
$GREEN----------------------Host systeminfo--------------------$END
echo -e "HOSTNAME: $REDhostname
$END"
| #echo -e "IPADDR: $RED ifconfig eth0|grep -Eo '([0-9]{1,3}\.){3}[0-9] {1,3}' |head -n1
$END" | | | |
| ------------------------------------------------------------ | ---- | ----------- | ----------------------- |
| echo | -e | "IPADDR: | $RED hostname -I
$END" |
| echo | -e | "OSVERSION: | $RED$PRETTY_NAME$END" |
范例:
echo -e "KERNEL: $REDuname -r
$END"
echo -e "CPU: $REDlscpu|grep '^Model name'|tr -s ' '|cut -d : - f2
$END"
echo -e "MEMORY: $REDfree -h|grep Mem|tr -s ' ' : |cut -d : -f2
$END"
echo -e "DISK: $REDlsblk |grep '^sd' |tr -s ' ' |cut -d " " -f4
$END"
$GREEN---------------------------------------------------------$END
[root@centos8 scripts]#cat system_info.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-23
#FileName: systeminfo.sh
#URL: http://www.magedu.com
#Description: Show system information
#Copyright (C): 2019 All rights reserved
#********************************************************************
RED="\E[1;31m"
GREEN="echo -e \E[1;32m" END="\E[0m" $GREEN----------------------Host | systeminfo--------------------$END | ||
---|---|---|---|
echo | -e | "HOSTNAME: | $REDhostname $END" |
echo | -e | "IPADDR: | $RED` ifconfig eth0|grep -Eo '([0-9]{1,3}.){3}[0-9] |
{1,3}' |head -n1$END" echo -e "OSVERSION: $RED
cat /etc/redhat-release$END" echo -e "KERNEL: $RED
uname -r$END" echo -e "CPU: $RED
lscpu|grep 'Model name'|tr -s ' '|cut -d : -f2$END" echo -e "MEMORY: $RED
free -h|grep Mem|tr -s ' ' : |cut -d : -f2$END" echo -e "DISK: $RED
lsblk |grep '^sd' |tr -s ' ' |cut -d " " -f4$END" $GREEN---------------------------------------------------------$END [root@centos8 script]#cat backup.sh 练习: 1、编写脚本 systeminfo.sh,显示当前主机系统信息,包括:主机名,IPv4地址,操作系统版本,内核版 本,CPU型号,内存大小,硬盘大小 2、编写脚本 backup.sh,可实现每日将 /etc/ 目录备份到 /backup/etcYYYY-mm-dd中 3、编写脚本 disk.sh,显示当前硬盘分区中空间利用率最大的值 4、编写脚本 links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数,并按连接数从大到小排 序 2.7.6 环境变量 环境变量: 可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量 一旦子进程修改从父进程继承的变量,将会新的值传递给孙子进程 一般只在系统配置文件中使用,在脚本中较少使用 变量声明和赋值: 变量引用: 显示所有环境变量: \#!/bin/bash \#Author: wang \#Date: 2020-08-05 \#Description: test \#FILE: backup.sh \#VERSION: 1.0 COLOR='echo -e \E[1;35m' END='\E[0m' BACKUP=/backup SRC=/etc DATE=
date +%F${COLOR}Starting backup...$END sleep 2 cp -av $SRC ${BACKUP}${SRC}_$DATE ${COLOR}Backup is finished$END \#声明并赋值 export name=VALUE declare -x name=VALUE \#或者分两步实现 name=VALUE export name $name ${name} 查看指定进程的环境变量 删除变量: bash内建的环境变量 范例: 查看进程的环境变量 env printenv export declare -x cat /proc/$PID/environ unset name PATH SHELL USER UID HOME PWD SHLVL #shell的嵌套层数,即深度 LANG MAIL HOSTNAME HISTSIZE _ #下划线,表示前一命令的最后一个参数 [root@centos8 ~]#cat /proc/1235/environ USER=rootLOGNAME=rootHOME=/rootPATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/us r/binSHELL=/bin/bashTERM=linuxSSH_AUTH_SOCK=/tmp/sshiIeuAxdLiY/agent.1234XDG_SESSION_ID=1XDG_RUNTIME_DIR=/run/user/0DBUS_SESSION_BUS _ADDRESS=unix:path=/run/user/0/busSSH_CLIENT=10.0.0.1 13258 22SSH_CONNECTION=10.0.0.1 13258 10.0.0.8 22SSH_TTY=/dev/pts/0[root@centos8 ~]# [root@centos8 ~]# [root@centos8 ~]#cat /proc/1235/environ |tr '\0' '\n' USER=root LOGNAME=root HOME=/root PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin SHELL=/bin/bash TERM=linux SSH_AUTH_SOCK=/tmp/ssh-iIeuAxdLiY/agent.1234 XDG_SESSION_ID=1 XDG_RUNTIME_DIR=/run/user/0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/bus SSH_CLIENT=10.0.0.1 13258 22 SSH_CONNECTION=10.0.0.1 13258 10.0.0.8 22 SSH_TTY=/dev/pts/0 2.7.7 只读变量 只读变量:只能声明定义,但后续不能修改和删除,即常量 声明只读变量: 查看只读变量: 范例: 2.7.8 位置变量 位置变量:在bash shell中内置的变量, 在脚本代码中调用通过命令行传递给脚本的参数 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. Disconnected from remote host(10.0.0.8) at 14:27:04. Type
help' to learn how to use Xshell prompt.
[c:~]$
Reconnecting in 1 seconds. Press any key to exit local shell.
.
Connecting to 10.0.0.8:22...
Connection established.
To escape to local shell, press 'Ctrl+Alt+]'.
WARNING! The remote SSH server rejected X11 forwarding request.
Last login: Wed Apr 1 13:51:28 2020 from 10.0.0.1
[root@centos8 ~]#echo $PI
[root@centos8 ~]#
清空所有位置变量
范例:
范例:删库跑路之命令rm的安全实现
$1, $2, ... 对应第1个、第2个等参数,shift [n]换位置
$0 命令本身,包括路径
$* 传递给脚本的所有参数,全部参数合为一个字符串
$@ 传递给脚本的所有参数,每个参数为独立字符串
$# 传递给脚本的参数的个数
注意:$@ $* 只在被双引号包起来的时候才会有差异
set --
[root@centos8 ~]#cat /data/scripts/arg.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-01
#FileName: arg.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
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
"
[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
[root@centos8 ~]#cat /data/scripts/rm.sh
#!/bin/bash
范例:$和$@的区别
范例: 利用软链接实现同一个脚本不同功能
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-01
#FileName: rm.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
WARNING_COLOR="echo -e \E[1;31m"
END="\E[0m"
DIR=/tmp/date +%F_%H-%M-%S
mkdir $DIR
mv $* $DIR
${WARNING_COLOR}Move $* to $DIR $END
[root@centos8 ~]#chmod a+x /data/scripts/rm.sh
[root@centos8 ~]#alias rm='/data/scripts/rm.sh'
[root@centos8 ~]#touch {1..10}.txt
[root@centos8 ~]#rm .txt
Move 10.txt 1.txt 2.txt 3.txt 4.txt 5.txt 6.txt 7.txt 8.txt 9.txt to /tmp/2020-
04-01_15-15-28
[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]#cat f2.sh
#!/bin/bash
echo "f2.sh:all args are $@"
echo "f2.sh:all args are $"
./file.sh "$@"
[root@centos8 scripts]#cat file.sh
#!/bin/bash
echo "file.sh:1st arg is $1"
[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
2.7.9 退出状态码变量
当我们浏览网页时,有时会看到下图所显示的数字,表示网页的错误信息,我们称为状态码,在shell脚
本中也有相似的技术表示程序执行的相应状态。
进程执行后,将使用变量 $? 保存状态码的相关数字,不同的值反应成功或失败,$?取值范例 0-255
范例:
范例:
用户可以在脚本中使用以下命令自定义退出状态码
注意:
脚本中一旦遇到exit命令,脚本会立即终止;终止退出状态取决于exit命令后面的数字
[root@centos8 ~]#cat test.sh
#!/bin/bash
#********************************************************************
echo $0
[root@centos8 ~]#ln -s test.sh a.sh
[root@centos8 ~]#ln -s test.sh b.sh
[root@centos8 ~]#./a.sh
./a.sh
[root@centos8 ~]#./b.sh
./b.sh
$?的值为0 #代表成功
$?的值是1到255 #代表失败
ping -c1 -W1 hostdown &> /dev/null
echo $?
[root@centos8 ~]#curl -fs http://www.wangxiaochun.com >/dev/null
[root@centos8 ~]#echo $?
0
exit [n]
如果exit后面无数字,终止退出状态取决于exit命令前面命令执行结果
如果没有exit命令, 即未给脚本指定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一
条命令的状态码
2.7.10 展开命令行
展开命令执行顺序
防止扩展
范例:
加引号来防止扩展
变量扩展
范例: ``和$() 区别
把命令行分成单个命令词
展开别名
展开大括号的声明{}
展开波浪符声明 ~
命令替换$() 和 ``
再次把命令行分成命令词
展开文件通配符*、?、[abc]等等
准备I/0重导向 <、>
运行命令
反斜线(\)会使随后的字符按原意解释
[root@centos8 ~]#echo Your cost: $5.00
Your cost: $5.00
[root@rocky8 ~]#echo "The book's price is $10"
The book's price is $10
单引号(’’)防止所有扩展
双引号(”“)也可防止扩展,但是以下情况例外:$(美元符号)
`` : 反引号,命令替换
\:反斜线,禁止单个字符扩展
!:叹号,历史命令替换
[root@centos8 ~]#echo echo \
> ^C
[root@centos8 ~]#echo echo \\
[root@centos8 ~]#echo echo \\\
> ^C
[root@centos8 ~]#echo echo \\\\
[root@centos8 ~]#echo $(echo )
> ^C
2.7.11 脚本安全和 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 个历史命令
范例:
set 命令实现脚本安全
-u 在扩展一个没有设置的变量时,显示错误信息, 等同set -o nounset
-e 如果一个命令返回一个非0退出状态值(失败)就退出, 等同set -o errexit
-o option 显示,打开或者关闭选项
显示选项:set -o
打开选项:set -o 选项
关闭选项:set +o 选项
-x 当执行命令时,打印命令及其参数,类似 bash -x
范例:
[root@centos8 ~]#echo $(echo \)
[root@centos8 ~]#echo $(echo \)
> ^C
[root@centos8 ~]#echo $(echo \\)
\
[root@centos8 ~]#echo $-
himBHs
[root@centos8 ~]#set +h
[root@centos8 ~]#echo $-
imBHs
[root@centos8 ~]#hash
-bash: hash: hashing disabled
[root@centos8 ~]#echo {1..10}
1 2 3 4 5 6 7 8 9 10
[root@centos8 ~]#echo $-
imBHs
[root@centos8 ~]#set +B
[root@centos8 ~]#echo $-
imHs
[root@centos8 ~]#echo {1..10}
{1..10}
范例:
2.8 格式化输出 printf
相当于增强版的 echo, 实现丰富的格式化输出
格式
常用格式替换符
[root@centos8 ~]#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
DIR=/data
cd $DIR
rm -rf *
#rm -rf $DIr/*
printf "指定的格式" "文本1" ”文本2“……
替换 符 | 功能 |
---|---|
%s | 字符串 |
%d,%i | 十进制整数 |
%f | 浮点格式 |
%c | ASCII字符,即显示对应参数的第一个字符 |
%b | 相对应的参数中包含转义字符时,可以使用此替换符进行替换,对应的转义字符会被转 义 |
%o | 八进制值 |
%u | 不带正负号的十进制值 |
%x | 十六进制值(a-f) |
%X | 十六进制值(A-F) |
%% | 表示%本身 |
转义符 | 功能 |
---|---|
\a | 警告字符,通常为ASCII的BEL字符 |
\b | 后退 |
\f | 换页 |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\ | 表示\本身 |
说明:
常用转义字符
范例:
%#s 中的数字代表此替换符中的输出字符宽度,不足补空格,默认是右对齐,%-10s表示10个字符宽,- 表示
左对齐
%03d 表示3位宽度,不足前面用0补全,超出位数原样输出
%.2f 中的2表示小数点后显示的小数位数
[root@centos8 ~]#printf "%s" 1 2 3 4
1234[root@centos8 ~]#
[root@centos8 ~]#printf "%s\n" 1 2 3 4
1
2.9 算术运算
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@rocky8 ~]#VAR="welcome to Magedu";printf "\033[1;32m%s\033[0m " $VAR
welcome to Magedu
[root@centos8 ~]#VAR="welcome to Magedu";printf "\033[1;32m%s\033[0m\n" $VAR
welcome
to
Magedu
[root@centos8 ~]#VAR="welcome to Magedu";printf "\033[1;32m%s\033[0m\n" "$VAR"
welcome to Magedu
Shell允许在某些情况下对算术表达式进行求值,比如:let和declare 内置命令,(( ))复合命令和算术扩
展。求值以固定宽度的整数进行,不检查溢出,尽管除以0 被困并标记为错误。运算符及其优先级,关
联性和值与C语言相同。以下运算符列表分组为等优先级运算符级别。级别按降序排列优先。
注意:bash 只支持整数,不支持小数
乘法符号有些场景中需要转义
实现算术运算:
内建的随机数生成器变量:
范例:
+ - addition, subtraction
* / % multiplication, division, remainder, %表示取模,即取余数,示例:9%4=1,5%3=2
i++ i-- variable post-increment and post-decrement
++i --i variable pre-increment and pre-decrement
= = /= %= += -= <<= >>= &= ^= |= assignment
- + unary minus and plus
! ~ logical and bitwise negation
** exponentiation 乘方,即指数运算
<< >> left and right bitwise shifts
<= >= < > comparison
== != equality and inequality
& bitwise AND
| bitwise OR
^ bitwise exclusive OR
&& logical AND
|| logical OR
expr?expr:expr conditional operator
expr1 , expr2 comma
(1) let var=算术表达式
(2) ((var=算术表达式)) 和上面等价
(3) var=$[算术表达式]
(4) var=$((算术表达式))
(5) var=$(expr arg1 arg2 arg3 ...)
(6) declare -i var = 数值
(7) echo '算术表达式' | bc
$RANDOM 取值范围:0-32767
#生成 0 - 49 之间随机数
echo $[$RANDOM%50]
#随机字体颜色
[root@centos8 ~]#echo -e "\033[1;$[RANDOM%7+31]mhello\033[0m"
magedu
增强型赋值:
格式:
范例:
范例:
范例:
+= i+=10 相当于 i=i+10
-= i-=j 相当于 i=i-j
=
/=
%=
++ i++,++i 相当于 i=i+1
-- i--,--i 相当于 i=i-1
let varOPERvalue
[root@centos8 ~]#let i=102
[root@centos8 ~]#echo $i
20
[root@centos8 ~]#((j=i+10))
[root@centos8 ~]#echo $j
30
[root@rocky8 ~]#i=10;((i++));echo $i
11
范例:
范例:
范例:
范例:
范例:鸡兔同笼,是中国古代著名典型趣题之一,记载于《孙子算经》之中。今有雉兔同笼,上有三十
五头,下有九十四足,问雉兔各几何?
#自加3后自赋值
let count+=3
[root@centos8 ~]#i=10
[root@centos8 ~]#let i+=20 #相当于let i=i+20
[root@centos8 ~]#echo $i
30
[root@centos8 ~]#j=20
[root@centos8 ~]#let i=j
[root@centos8 ~]#echo $i
600
#自增,自减
let var+=1
let var++
let var-=1
let var--
[root@centos8 ~]#unset i j ; i=1; let j=i++; echo "i=$i,j=$j"
i=2,j=1
[root@centos8 ~]#unset i j ; i=1; let j=++i; echo "i=$i,j=$j"
i=2,j=2
[root@centos8 ~]#expr 2 * 3
expr: syntax error: unexpected argument ‘anaconda-ks.cfg’
[root@centos8 ~]#ls
anaconda-ks.cfg
[root@centos8 ~]#expr 2 * 3
6
[root@centos8 ~]#echo "scale=3;20/3"|bc
6.666
[root@centos8 ~]#i=10
[root@centos8 ~]#j=20
[root@centos8 ~]#declare -i result=i*j
[root@centos8 ~]#echo $result
200
[root@centos8 scripts]#cat chook_rabbit.sh
#!/bin/bash
#
#********************************************************************
2.10 逻辑运算
2.10.1 与或非
true, false
与:& 和0相与结果为0,和1相与结果保留原值, 一假则假,全真才真
范例:
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-01
#FileName: chook_rabbit.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
HEAD=$1
FOOT=$2
RABBIT=$(((FOOT-HEAD-HEAD)/2))
CHOOK=$[HEAD-RABBIT]
echo RABBIT:$RABBIT
echo CHOOK:$CHOOK
[root@centos8 scripts]#./chook_rabbit.sh 30 80
RABBIT:10
CHOOK:20
[root@centos8 scripts]#
1,真
0,假
#注意,以上为二进制
0 与 0 = 0
0 与 1 = 0
1 与 0 = 0
1 与 1 = 1
或:| 和1相或结果为1,和0相或结果保留原值,一真则真,全假才假
范例:
非:!
异或:^
异或的两个值,相同为假,不同为真。两个数字X,Y异或得到结果Z,Z再和任意两者之一X异或,将得出
另一个值Y
范例:
范例: 变量互换
[root@ubuntu1804 ~]#x=$[2&6]
[root@ubuntu1804 ~]#echo $x
2
[root@ubuntu1804 ~]#x=$[7&3]
[root@ubuntu1804 ~]#echo $x
3
0 或 0 = 0
0 或 1 = 1
1 或 0 = 1
1 或 1 = 1
[root@ubuntu1804 ~]#x=$[7|3]
[root@ubuntu1804 ~]#echo $x
7
[root@ubuntu1804 ~]#x=$[2|5]
[root@ubuntu1804 ~]#echo $x
7
! 1 = 0 ! true
! 0 = 1 ! false
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 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
2.10.2 短路运算
短路与 &&
短路或 ||
短路与和或组合
2.11 条件测试命令
条件测试:判断某需求是否满足,需要由测试机制来实现,专用的测试表达式需要由测试命令辅助完成
测试过程,实现评估布尔声明,以便用在条件性环境下进行执行
若真,则状态码变量 $? 返回0
若假,则状态码变量 $? 返回1
条件测试命令
test EXPRESSION
[ EXPRESSION ] #和test 等价,建议使用 [ ]
[[ EXPRESSION ]] 相关于增强版的 [ ], 支持[]的用法,且支持扩展正则表达式和通配符
注意:EXPRESSION前后必须有空白字符
帮助:
[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=$[xy];y=$[xy];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 必须要参与运算,才能得到最终的结果
CMD1 && CMD2 || CMD3
当CMD1执行成功时,会执行CMD2
当CMD1执行失败时,会执行CMD3
注意: CMD1 || CMD2 && CMD3 逻辑不通,不使用
[root@centos8 ~]#type [
[ is a shell builtin
[root@centos8 ~]#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 `['.
[root@centos8 ~]#help test
test: test [expr]
Evaluate conditional expression.
Exits with a status of 0 (true) or 1 (false) depending on
the evaluation of EXPR. Expressions may be unary or binary. Unary
expressions are often used to examine the status of a file. There
are string operators and numeric comparison operators as well.
The behavior of test depends on the number of arguments. Read the
bash manual page for the complete specification.
File operators:
-a FILE True if file exists.
-b FILE True if file is block special.
-c FILE True if file is character special.
-d FILE True if file is a directory.
-e FILE True if file exists.
-f FILE True if file exists and is a regular file.
-g FILE True if file is set-group-id.
-h FILE True if file is a symbolic link.
-L FILE True if file is a symbolic link.
-k FILE True if file has its `sticky' bit set.
-p FILE True if file is a named pipe.
-r FILE True if file is readable by you.
-s FILE True if file exists and is not empty.
-S FILE True if file is a socket.
-t FD True if FD is opened on a terminal.
-u FILE True if the file is set-user-id.
-w FILE True if the file is writable by you.
-x FILE True if the file is executable by you.
-O FILE True if the file is effectively owned by you.
-G FILE True if the file is effectively owned by your group.
-N FILE True if the file has been modified since it was last read.
FILE1 -nt FILE2 True if file1 is newer than file2 (according to
modification date).
FILE1 -ot FILE2 True if file1 is older than file2.
FILE1 -ef FILE2 True if file1 is a hard link to file2.
String operators:
-z STRING True if string is empty.
-n STRING
STRING True if string is not empty.
STRING1 = STRING2
True if the strings are equal.
STRING1 != STRING2
True if the strings are not equal.
2.11.1 变量测试
范例:
STRING1 < STRING2
True if STRING1 sorts before STRING2 lexicographically.
STRING1 > STRING2
True if STRING1 sorts after STRING2 lexicographically.
Other operators:
-o OPTION True if the shell option OPTION is enabled.
-v VAR True if the shell variable VAR is set.
-R VAR True if the shell variable VAR is set and is a name
reference.
! EXPR True if expr is false.
EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.
EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.
arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,
-lt, -le, -gt, or -ge.
Arithmetic binary operators return true if ARG1 is equal, not-equal,
less-than, less-than-or-equal, greater-than, or greater-than-or-equal
than ARG2.
Exit Status:
Returns success if EXPR evaluates to true; fails if EXPR evaluates to
false or an invalid argument is given.
[root@centos8 ~]#
#判断 NAME 变量是否定义
[ -v NAME ]
[root@centos8 ~]#unset x
[root@centos8 ~]#test -v x
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#x=10
[root@centos8 ~]#test -v x
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#y=
[root@centos8 ~]#test -v y
[root@centos8 ~]#echo $?
0 #
注意 [ ] 中需要空格,否则会报下面错误
[root@centos8 ~]#[-v name]
-bash: [-v: command not found
[root@centos8 ~]#[ -v name ]
[root@centos8 ~]#echo $?
0
2.11.2 数值测试
范例:
算术表达式比较
范例:
范例:
-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
== 相等
!= 不相等
<=
>=
<
>
[root@centos8 ~]#x=10;y=10;(( x == y ));echo $?
0
[root@centos8 ~]#x=10;y=20;(( x == y ));echo $?
1
[root@centos8 ~]#x=10;y=20;(( x != y ));echo $?
0
[root@centos8 ~]#x=10;y=10;(( x != y ));echo $?
1
[root@centos8 ~]#x=10;y=20;(( x > y ));echo $?
1
[root@centos8 ~]#x=10;y=20;(( x < y ));echo $?
0
2.11.3 字符串测试
test和 [ ] 字符串测试用法
[[]] 字符串测试用法
建议:当使用正则表达式或通配符使用[[ ]],其它情况一般使用 [ ]
范例:使用 [ ]
-z STRING 字符串是否为空,没定义或空为真,不空为假,
-n STRING 字符串是否不空,不空为真,空为假
STRING 同上
STRING1 = STRING2 是否等于,注意 = 前后有空格
STRING1 != STRING2 是否不等于
> ascii码是否大于ascii码
< 是否小于
[[ expression ]] 用法
== 左侧字符串是否和右侧的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" ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ I love linux ]
-bash: [: love: binary operator expected
[root@centos8 ~]#FILE="a"
[root@centos8 ~]#echo $FILE
a
[root@centos8 ~]#[[ $FILE == a* ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#FILE="ab"
[root@centos8 ~]#[[ $FILE == a* ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#FILE="a"
#[[]]中如果不想使用通配符,只想表达本身,可以用" "引起来
[root@centos8 ~]#[[ $FILE == a"" ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#FILE="ab"
[root@centos8 ~]#[[ $FILE == a"" ]]
[root@centos8 ~]#echo $?
1
#[[]]中如果不想使用通配符,只想表达本身,也可以使用转义符
[root@centos8 ~]#[[ $FILE == a* ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#FILE="a\b"
[root@centos8 ~t]#[[ $FILE == a* ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#FILE="a"
[root@centos8 ~]#[[ $FILE == a* ]]
[root@centos8 ~]#echo $?
0
范例: 判断合理的考试成绩
范例:使用 [[ ]] 判断文件后缀
#通配符?
[root@centos8 script]#FILE=abc
[root@centos8 script]#[[ $FILE == ??? ]]
[root@centos8 script]#echo $?
0
[root@centos8 script]#FILE=abcd
[root@centos8 script]#[[ $FILE == ??? ]]
[root@centos8 script]#echo $?
1 #
通配符
[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 script]#SCORE=101
[root@centos8 script]#[[ $SCORE =~ 100|[0-9]{1,2} ]]
[root@centos8 script]#echo $?
0
[root@centos8 script]#[[ $SCORE =~ ^(100|[0-9]{1,2})$ ]]
[root@centos8 script]#echo $?
1
[root@centos8 script]#SCORE=10
[root@centos8 script]#[[ $SCORE =~ ^(100|[0-9]{1,2})$ ]]
[root@centos8 script]#echo $?
0
[root@centos8 script]#SCORE=abc
[root@centos8 script]#[[ $SCORE =~ ^(100|[0-9]{1,2})$ ]]
[root@centos8 script]#echo $?
1 #
通配符
[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 ]]
范例: 判断合法的非负整数
范例: 判断合法IP
范例:
[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" =~ [1]+$ ]]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#N=Magedu10
[root@centos8 ~]#[[ "$N" =~ [2]+$ ]]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#IP=1.2.3.4
[root@centos8 ~]#[[ "$IP" =~ ^([0-9]{1,3}.){3}[0-9]{1,3}$ ]]
[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
[root@centos8 ~]#[[ $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])$ ]]
[root@centos8 ~]#echo $?
1
[root@centos7 ~]#cat check_ip.sh
#!/bin/bash
#
#*****************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-12-11
#FileName: check_ip.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
IP=$1
[[ $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])$ ]] && echo $IP is valid || echo $IP is invalid
2.11.4 文件测试
存在性测试
范例: -e和-a 表示判断文件的存在性,建议使用-e
-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 #
文件是否存在
[root@centos8 ~]# [ -a /etc/issue ]
[root@centos8 ~]#echo $?
0 #
取反后结果却没有变化
[root@centos8 ~]# [ ! -a /etc/issue ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#! [ -a /etc/issue ]
[root@centos8 ~]#echo $?
1 #
文件是否存在
[root@centos8 ~]#! [ -e /etc/issue ]
[root@centos8 ~]#echo $?
1 #
此为推荐写法
[root@centos8 ~]#[ ! -e /etc/issue ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ -d /etc ]
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -d /etc/issue ]
[root@centos8 ~]#echo $?
1
[root@centos8 ~]#[ -L /bin ]
文件权限测试:
注意:最终结果由用户对文件的实际权限决定,而非文件属性决定
范例:
文件属性测试
2.12 关于 () 和 {}
(CMD1;CMD2;...)和 { CMD1;CMD2;...; } 都可以将多个命令组合在一起,批量执行
[root@centos8 ~]#echo $?
0
[root@centos8 ~]#[ -L /bin/ ]
[root@centos8 ~]#echo $?
1
-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 |
范例: () 和 {}
[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
2.13 组合测试条件
2.13.1 第一种方式
说明: -a 和 -o 需要使用测试命令进行,[[ ]] 不支持
范例:
[root@centos8 ~]#{ echo $BASHPID; }
1920
[ EXPRESSION1 -a EXPRESSION2 ] #并且,EXPRESSION1和EXPRESSION2都是真,结果才为真
[ EXPRESSION1 -o EXPRESSION2 ] #或者,EXPRESSION1和EXPRESSION2只要有一个真,结果就为
真
[ ! EXPRESSION ] #取反
[root@centos8 ~]#FILE="/data/scrips/test.sh"
[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
2.13.2 第二种方式
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"
[root@centos8 ~]#test "A" = "B" && echo "Strings are equal"
[root@centos8 ~]#test "A"-eq "B" && echo "Integers are equal"
[root@centos8 ~]#[ "A" = "B" ] && echo "Strings are equal"
[root@centos8 ~]#[ "$A" -eq "$B" ] && echo "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❌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
10.0.0.111 is down
[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/scripts/ping.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-23
#FileName: ping.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
IP=172.16.0.1
ping -c1 -W1 $IP &> /dev/null && echo "$IP is up" || { echo "$IP is
unreachable"; exit; }
echo "Script is finished"
[root@centos8 ~]#bash /data/scripts/ping.sh
172.16.0.1 is up
Script is finished
[root@centos8 ~]#. /etc/os-release; [[ $ID == "rocky" ]] && [[ $VERSION_ID == 8
]] && echo Rocky8 || echo CentOS8
[root@rocky8 ~]#. /etc/os-release; [[ $ID == "rocky" ]] && [[ $VERSION_ID == 8*
]] && echo Rocky8 || echo CentOS8
Rocky8
范例:磁盘空间和Inode号的检查脚本
练习
1、编写脚本 argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给
一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数
2、编写脚本 hostping.sh,接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提
示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”
3、编写脚本 checkdisk.sh,检查磁盘分区空间和inode使用率,如果超过80%,就发广播警告空间将满
4、编写脚本 per.sh,判断当前用户对指定参数文件,是否不可读并且不可写
5、编写脚本 excute.sh ,判断参数文件是否为sh后缀的普通文件,如果是,添加所有人可执行权限,
否则提示用户非脚本文件
6、编写脚本 nologin.sh和 login.sh,实现禁止和允许普通用户登录系统
2.13 使用read命令来接受输入
[root@centos8 ~]#cat /data/script/disk_check.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-23
#FileName: disk_check.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
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
[root@centos8 scripts]#cat disk_check.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-03
#FileName: disk_check.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
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
使用read来把输入值分配给一个或多个shell变量,read从标准输入中读取值,给每个单词分配一个变
量,所有剩余单词都被分配给最后一个变量,如果变量名没有指定,默认标准输入的值赋值给系统内置
变量REPLY
格式:
常见选项:
范例:
范例:
范例:
read [options] [name ...]
-p
指定要显示的提示 静默输入,一般用于密码 | |
---|---|
N | 指定输入的字符长度N |
'字符' | 输入结束符 |
N TIMEOUT为N秒 |
-s -n -d -t [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 ~]#
[root@centos8 ~]#man bash
范例:面试题 read和输入重定向
范例:判断用户输入的是否为 YES
范例: 判断用户输入的是否为 YES
#Pipelines:A pipeline is a sequence of one or more commands separated by one of
the control operators | or |&
Each command in a pipeline is executed as a separate process (i.e., in a
subshell).
[root@centos8 ~]#echo magedu | read NAME
[root@centos8 ~]#echo $NAME
[root@centos8 ~]#echo magedu | { read NAME; echo $NAME; }
magedu
[root@centos8 scripts]#cat test.txt
1 2
[root@centos8 scripts]#read i j < test.txt ; echo i=$i j=$j
i=1 j=2
[root@centos8 scripts]#echo 1 2 | read x y ; echo x=$x y=$y
x= y=
[root@centos8 ~]#echo 1 2 | ( read x y ; echo x=$x y=$y )
x=1 y=2
[root@centos8 ~]#echo 1 2 | { read x y ; echo x=$x y=$y; }
x=1 y=2
[root@centos8 scripts]#cat read.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-03
#FileName: read.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
read -p "Are you rich?yes or no: " ANSWER
[[ $ANSWER =~ ^([Yy]|[Yy][Ee][Ss])$ ]] && echo "You are rich" || echo "Good Good
Study,Day Day Up!"
root@ubuntu2004:~# cat yesorno.sh
#!/bin/bash
read -p "Please input yes or no: " input
answer=echo $input| tr 'A-Z' 'a-z'
[ $answer = 'yes' -o $answer = 'y' ] && echo YES
范例: 检查主机的网络状态
范例:
范例:鸡兔同笼算法,今有雉兔同笼,上有三十五头,下有九十四足,问雉兔各几何?
[ $answer = 'no' -o $answer = 'n' ] && echo NO
root@ubuntu2004:~# cat yesorno2.sh
#!/bin/bash
read -p "Please input yes or no: " input
[[ $input =~ ^([Yy][Ee][Ss]|[Yy])$ ]] && echo YES
[[ $input =~ ^([Nn][Oo]|[Nn])$ ]] && echo NO
[root@centos8 script]#cat check_host.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-08-07
#FileName: check_host.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
read -p "Please input a IP: " IP
[[ "$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])$ ]] || { echo "IP is invalid";exit; }
ping -c1 -W1 $IP &> /dev/null && echo $IP is up || echo $IP is down
read -p “Enter a filename: “ FILE
[root@centos8 ~]#cat /data/script40/chook_rabbit.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-23
#FileName: chook_rabbit.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
read -p "请输入头的数量: " HEAD
read -p "请输入脚的数量: " FOOT
RABBIT=$[FOOT/2-HEAD]
CHOOK=$[HEAD-RABBIT]
echo "兔子: " $RABBIT
echo "鸡: " $CHOOK
范例:实现运维工作菜单
3 bash shell 的配置文件
bash shell的配置文件很多,可以分成下面类别
3.1 按生效范围划分两类
全局配置:针对所有用户皆有效
[root@centos8 scripts]#cat work_menu.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-03
#FileName: work_menu.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
. /etc/init.d/functions
echo -en "\E[$[RANDOM%7+31];1m"
cat <<EOF
请选择:
1)备份数据库
2)清理日志
3)软件升级
4)软件回滚
5)删库跑路
EOF
echo -en '\E[0m'
read -p "请选择上面项对应的数字1-5: " MENU
[ $MENU -eq 1 ] && ./backup.sh
[ $MENU -eq 2 ] && action "清理日志"
[ $MENU -eq 3 ] && action "软件升级"
[ $MENU -eq 4 ] && action "软件回滚"
[ $MENU -eq 5 ] && action "删库跑路"
个人配置:只针对特定用户有效
3.2 shell登录两种方式分类
3.2.1 交互式登录
直接通过终端输入账号密码登录
使用 su - UserName 切换的用户
配置文件生效和执行顺序:
注意:文件之间的调用关系,写在同一个文件的不同位置,将影响文件的执行顺序
3.2.2 非交互式登录
su UserName
图形界面下打开的终端
执行脚本
任何其它的bash实例
执行顺序:
范例: 将命令放在最前面
/etc/profile
/etc/profile.d/.sh
/etc/bashrc
~/.bash_profile
~/.bashrc
#放在每个文件最前
/etc/profile
/etc/profile.d/.sh
/etc/bashrc
~/ .bash_ profile
~/ .bashrc
/etc/bashrc
#放在每个文件最后
/etc/profile.d/.sh
/etc/bashrc
/etc/profile
/etc/bashrc #此文件执行两次
~/.bashrc
~/.bash_profile
/etc/profile.d/.sh
/etc/bashrc
~/.bashrc
Last login: Wed Jun 10 11:24:03 2020 from 10.0.0.1
/etc/profile
/etc/profile.d/test.sh
范例:将命令放在最后面
3.3 按功能划分分类
profile类和bashrc类
/etc/bashrc
~/.bash_profile
~/.bashrc
/etc/bashrc
[root@centos8 ~]#su - root
Last login: Wed Jun 10 12:26:31 CST 2020 from 10.0.0.1 on pts/0
/etc/profile
/etc/profile.d/test.sh
/etc/bashrc
~/.bash_profile
~/.bashrc
/etc/bashrc
[root@centos8 ~]#exit
logout
[root@centos8 ~]#su root
~/.bashrc
/etc/bashrc
/etc/profile.d/test.sh
Last login: Wed Jun 10 12:29:20 2020 from 10.0.0.1
/etc/profile.d/test.sh
/etc/bashrc
/etc/profile
/etc/bashrc
~/.bashrc
~/.bash_profile
[root@centos8 ~]#su - root
Last login: Wed Jun 10 12:30:03 CST 2020 from 10.0.0.1 on pts/3
/etc/profile.d/test.sh
/etc/bashrc
/etc/profile
/etc/bashrc
~/.bashrc
~/.bash_profile
[root@centos8 ~]#su root
/etc/profile.d/test.sh
/etc/bashrc
~/.bashrc
3.3.1 Profile类
profile类为交互式登录的shell提供配置
功用:
(1) 用于定义环境变量
(2) 运行命令或脚本
3.3.2 Bashrc类
bashrc类:为非交互式和交互式登录的shell提供配置
功用:
(1) 定义命令别名和函数
(2) 定义本地变量
3.4 编辑配置文件生效
修改profile和bashrc文件后需生效两种方法:
- 重新启动shell进程
- source|. 配置文件
注意:source 会在当前shell中执行脚本,所有一般只用于执行置文件,或在脚本中调用另一个脚本的场景
范例:
3.5 Bash 退出任务
保存在~/.bash_logout文件中(用户),在退出登录shell时运行
功能:
创建自动备份
清除临时文件
练习
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、编写生成脚本基本格式的脚本,包括作者,联系方式,版本,时间,描述等
全局:/etc/profile, /etc/profile.d/*.sh
个人:~/.bash_profile
全局:/etc/bashrc
个人:~/.bashrc
. ~/.bashrc
4 流程控制
4.1 条件选择
4.1.1 条件判断分绍
4.1.1.1 单分支条件
4.1.1.2 多分支条件
4.1.2 选择执行 if 语句
格式:
单分支
双分支
多分支
说明:
多个条件时,逐个条件进行判断,第一次遇为“真”条件时,执行其分支,而后结束整个if语句
if 语句可嵌套
范例:
if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS;
] fi
if 判断条件;then
条件为真的分支代码
fi
if 判断条件; then
条件为真的分支代码
else
条件为假的分支代码
fi
if 判断条件1; then
条件1为真的分支代码
elif 判断条件2; then
条件2为真的分支代码
elif 判断条件3; then
条件3为真的分支代码
...
else
以上条件都为假的分支代码
fi
[root@centos6 ~]#declare -f
__udisks ()
{
local IFS='
';
local cur="${COMP_WORDS[COMP_CWORD]}";
if [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--show-info" ]; then
COMPREPLY=($(compgen -W "$(udisks --enumerate-device-files)" -- $cur));
else
if [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--inhibit-polling" ]; then
COMPREPLY=($(compgen -W "$(udisks --enumerate-device-files)" --
$cur));
else
if [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--mount" ]; then
范例:
COMPREPLY=($(compgen -W "$(udisks --enumerate-device-files)" --
$cur));
else
if [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--unmount" ]; then
COMPREPLY=($(compgen -W "$(udisks --enumerate-device-files)"
-- $cur));
else
if [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--detach" ];
then
COMPREPLY=($(compgen -W "$(udisks --enumerate-devicefiles)" -- $cur));
else
if [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--atasmart-refresh" ]; then
COMPREPLY=($(compgen -W "$(udisks --enumeratedevice-files)" -- $cur));
else
if [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--atasmart-simulate" ]; then
_filedir || return 0;
else
if [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" = "--
set-spindown" ]; then
COMPREPLY=($(compgen -W "$(udisks --
enumerate-device-files)" -- $cur));
else
if [ "${COMP_WORDS[$(($COMP_CWORD - 1))]}" =
"--poll-for-media" ]; then
COMPREPLY=($(compgen -W "$(udisks --
enumerate-device-files)" -- $cur));
else
COMPREPLY=($(IFS=: compgen -W "--dump:--
inhibit-polling:--inhibit-all-polling:--enumerate:--enumerate-device-files:--
monitor:--monitor-detail:--show-info:--help:--mount:--mount-fstype:--mountoptions:--unmount:--unmount-options:--detach:--detach-options:--ata-smartrefresh:--ata-smart-wakeup:--ata-smart-simulate:--set-spindown:--set-spindownall:--spindown-timeout:--poll-for-media" -- $cur));
fi;
fi;
fi;
fi;
fi;
fi;
fi;
fi;
fi
}
[root@centos6 ~]#
范例:身体质量指数 (BMI)
参考链接:
#根据命令的退出状态来执行命令
if ping -c1 -W2 station1 &> /dev/null; then
echo 'station1 is UP'
elif grep -q 'station1' ~/maintenance.txt; then
echo 'station1 is undergoing maintenance'
else
echo 'station1 is unexpectedly DOWN!'
exit 1
fi
https://baike.baidu.com/item/标准体重/1694152?fr=aladdin
[root@centos8 ~]#cat if_bmi.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-25
#FileName: if_bmi.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
read -p "请输入身高(m为单位): " HIGH
if [[ ! "$HIGH" =~ [3](.[0-9]{1,2})?$ ]];then
echo "输入错误的身高!"
exit 1
fi
read -p "请输入体重(kg为单位): " WEIGHT
if [[ ! "$WEIGHT" =~ [4]{1,3}$ ]];then echo "输入错误的体重!"; exit 2; fi
BMI=echo $WEIGHT/$HIGH^2|bc
if [ $BMI -le 18 ] ;then
echo "太瘦了,多吃点!"
elif [ $BMI -lt 24 ] ;then
echo "身材很棒!"
else
echo "太胖了,注意节食,加强运动!"
fi
4.1.3 条件判断 case 语句
格式:
case支持glob风格的通配符:
范例:
case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
case 变量引用 in
PAT1)
分支1
;;
PAT2)
分支2
;;
...
)
默认分支
;;
esac
* 任意长度任意字符
? 任意单个字符
[] 指定范围内的任意单个字符
| 或者,如: a|b
[root@centos8 scripts]#cat case_yesorno.sh
#!/bin/bash
#
#*******************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-25
#FileName: case_yesorno.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
read -p "Do you agree(yes/no)? " INPUT
INPUT=echo $INPUT | tr 'A-Z' 'a-z'
case $INPUT in
y|yes)
echo "You input is YES"
;;
n|no)
echo "You input is NO"
;;
)
echo "Input fales,please input yes or no!"
范例: 文件后缀处理
esac
[root@centos8 scripts]#cat case_yesorno2.sh
#!/bin/bash
#
#*******************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2019-12-25
#FileName: case_yesorno.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2019 All rights reserved
#********************************************************************
read -p "Do you agree(yes/no)? " INPUT
case $INPUT in
[yY]|[Yy][Ee][Ss])
echo "You input is YES"
;;
[Nn]|[Nn][Oo])
echo "You input is NO"
;;
)
echo "Input fales,please input yes or no!"
esac
[root@centos8 script]#cat suffix.sh
#!/bin/bash
#
#*******************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-08-07
#FileName: suffix.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
read -p "please input a file: " FILE
SUFFIX=echo $FILE | grep -Eo "[^.]+$"
case $SUFFIX in
gz)
echo gzip
;;
bz2)
echo bzip2
;;
xz)
echo xz
;;
Z)
echo compress
范例:运维菜单实现版本2
;;
zip)
echo zip
;;
)
echo other
;;
esac
[root@centos8 scripts]#cat work_menu.sh
#!/bin/bash
#
#*******************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-03
#FileName: work_menu.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
echo -en "\E[$[RANDOM%7+31];1m"
cat <<EOF
请选择:
1)备份数据库
2)清理日志
3)软件升级
4)软件回滚
5)删库跑路
EOF
echo -en '\E[0m'
read -p "请输入上面数字1-5: " MENU
case $MENU in
1)
echo "执行备份数据库"
#./backup.sh
;;
2)
echo "清理日志"
;;
3)
echo "软件升级"
;;
4)
echo "软件回滚"
;;
5)
echo "删库跑路"
;;
*)
echo "INPUT FALSE!"
esac
练习
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的设置等
4.2 循环
4.2.1 循环执行介绍
将某代码段重复运行多次,通常有进入循环的条件和退出循环的条件
重复运行次数
循环次数事先已知
循环次数事先未知
常见的循环的命令:for, while, until
4.2.2 循环 for
格式1:
#CentOS7的for帮助比CentOS8全面
[root@centos7 ~]#help for
for: for NAME [in WORDS ... ] ; do COMMANDS; done
Execute commands for each member in a list.
The for' loop executes a sequence of commands for each member in a list of items. If
in WORDS ...;' is not present, then in "$@"' is assumed. For each element in WORDS, NAME is set to that element, and the COMMANDS are executed. Exit Status: Returns the status of the last command executed. for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done Arithmetic for loop. Equivalent to (( EXP1 )) while (( EXP2 )); do COMMANDS (( EXP3 )) done EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is omitted, it behaves as if it evaluates to 1. Exit Status: Returns the status of the last command executed. [root@centos7 ~]# 执行机制: 依次将列表中的元素赋值给“变量名”; 每次赋值后即执行一次循环体; 直到列表中的元素耗尽,循环 结束 如果省略 [in WORDS ... ] ,此时使用位置参数变量 in "$@" for 循环列表生成方式: 直接给出列表 整数列表: 返回列表的命令: 使用glob,如:*.sh 变量引用,如:$@,$*,$# 范例:面试题,计算1+2+3+...+100 的结果 范例: 100以内的奇数之和 for NAME [in WORDS ... ] ; do COMMANDS; done \#方式1 for 变量名 in 列表;do 循环体 done \#方式2 for 变量名 in 列表 do 循环体 done {start..end} $(seq [start [step]] end) $(COMMAND) [root@centos8 ~]#sum=0;for i in {1..100};do let sum+=i;done ;echo sum=$sum sum=5050 [root@centos8 ~]#seq -s+ 100|bc5050 5050 [root@centos8 ~]#echo {1..100}|tr ' ' +|bc 5050 [root@centos8 ~]#seq 100|paste -sd +|bc 5050 [root@centos8 ~]#sum=0;for i in {1..100..2};do let sum+=i;done;echo sum=$sum sum=2500 [root@centos8 ~]#seq -s+ 1 2 100| bc 2500 [root@centos8 ~]#echo {1..100..2}|tr ' ' + | bc 2500 范例: 范例: 批量创建用户 范例: 批量创建用户和并设置随机密码 [root@centos8 ~]#cat /data/scripts/for_sum.sh \#!/bin/bash \# \#******************************************************************** \#Author: wangxiaochun \#QQ: 29308620 \#Date: 2020-04-27 \#FileName: for_sum.sh \#URL: http://www.wangxiaochun.com \#Description: The test script \#Copyright (C): 2020 All rights reserved \#******************************************************************** sum=0 for i in $* ; do let sum+=i done echo sum=$sum [root@centos8 ~]#bash /data/scripts/for_sum.sh 1 2 3 4 5 6 sum=21 [root@centos8 ~]#cat createuser.sh \#!/bin/bash \# \#******************************************************************** \#Author: wangxiaochun \#QQ: 29308620 \#Date: 2020-12-14 \#FileName: createuser.sh \#URL: http://www.wangxiaochun.com \#Description: The test script \#Copyright (C): 2020 All rights reserved \#******************************************************************** [ $# -eq 0 ] && { echo "Usage: createuser.sh USERNAME ..." ;exit 1 ; } for user ;do id $user &> /dev/null && echo $user is exist || { useradd $user ; echo $user is created; } done [root@centos8 script]#cat user_for.sh \#!/bin/bash \# \#******************************************************************** \#Author: wangxiaochun \#QQ: 29308620 \#Date: 2020-08-07 \#FileName: user_for.sh \#URL: http://www.wangxiaochun.com 范例: 九九乘法表 范例: printf 实现九九乘法表 范例: 实现九九乘法表 \#Description: The test script \#Copyright (C): 2020 All rights reserved \#******************************************************************** for i in {1..10};do useradd user$i PASS=
cat /dev/urandom | tr -dc '[:alnum:]' |head -c12echo $PASS | passwd --stdin user$i &> /dev/null echo user$i:$PASS >> /data/user.log echo "user$i is created" done [root@centos8 script]#cat 9x9_for.sh \#!/bin/bash \# \#******************************************************************** \#Author: wangxiaochun \#QQ: 29308620 \#Date: 2020-08-07 \#FileName: 9x9_for.sh \#URL: http://www.wangxiaochun.com \#Description: The test script \#Copyright (C): 2020 All rights reserved \#******************************************************************** for i in {1..9};do for j in
seq $i;do echo -e "${j}x${i}=$[j*i]\t\c" done echo done for i in {1..9};do for j in {1..9};do printf "%sx%s=%s\t" $j $i $[i*j] [ $i -eq $j ] && break done printf '\n' done [root@centos8 ~]#vim 9x9.sh \#!/bin/bash \# \#******************************************************************** \#Author: wangxiaochun \#QQ: 29308620 \#Date: 2021-04-02 \#FileName: 9x9.sh \#URL: http://www.wangxiaochun.com \#Description: The test script \#Copyright (C): 2021 All rights reserved 范例: 倒状的九九乘法表 \#******************************************************************** for j in {1..9};do for i in
seq $j;do echo -e "\E[1;$[RANDOM%7+31]m${i}x${j}=$[i*j]\E[0m\t\c" done echo done echo for((i=1;i<=9;i++));do for((j=1;j<=i;j++));do printf "\E[1;$[RANDOM%7+31]m${i}x${j}=$[i*j]\E[0m\t" done printf "\n" done [root@ubuntu1804 ~]#cat 9x9_v2.sh \#!/bin/bash \# \#******************************************************************** \#Author: wangxiaochun \#QQ: 29308620 \#Date: 2020-12-14 \#FileName: 9x9.sh \#URL: http://www.wangxiaochun.com \#Description: The test script \#Copyright (C): 2020 All rights reserved \#******************************************************************** for i in {1..9};do for j in $(seq
echo $[10-$i]);do echo -ne "${j}x
echo $[10-i]=$(((10-i)*j))\t" done echo done 生产案例:将指定目录下的文件所有文件的后缀改名为 bak 后缀 范例:M37期面试题,要求将目录YYYY-MM-DD/中所有文件,移动到YYYY-MM/DD/下 [root@ubuntu1804 ~]#bash 9x9_v2.sh 1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81 1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64 1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49 1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36 1x5=5 2x5=10 3x5=15 4x5=20 5x5=25 1x4=4 2x4=8 3x4=12 4x4=16 1x3=3 2x3=6 3x3=9 1x2=2 2x2=4 1x1=1 [root@ubuntu1804 ~]# [root@centos8 ~]#cat /data/scripts/for_rename.sh \#!/bin/bash \# \#******************************************************************** \#Author: wangxiaochun \#QQ: 29308620 \#Date: 2020-01-03 \#FileName: /data/script40/for_rename.sh \#URL: http://www.magedu.com \#Description: The test script \#Copyright (C): 2020 All rights reserved \#******************************************************************** DIR=/data/test cd $DIR || { echo 无法进入 $DIR;exit 1; } for FILE in * ;do PRE=
echo $FILE|grep -Eo ".." mv $FILE ${PRE}bak \# PRE=
echo $FILE|rev|cut -d. -f 2-|rev \# PRE=
echo $FILE | sed -nr 's/(.).([^.]+)$/\1/p'
# SUFFIX=echo $FILE | sed -nr 's/(.*)\.([^.]+)$/\2/p'
# mv $FILE $PRE.bak
done
#1.创建YYYY-MM-DD格式的目录,当前日期一年前365天到目前共365个目录,里面有10个文件.log后缀的
文件
[root@centos8 ~]#cat for_dir.sh
#!/bin/bash
PDIR=/data/test
for i in {1..365};do
DIR=date -d "-$i day" +%F
mkdir -pv $PDIR/$DIR
cd $PDIR/$DIR
for j in {1..10};do
touch $RANDOM.log
done
done
面试题:扫描一个网段:10.0.0.0/24,判断此网段中主机在线状态,将在线的主机的IP打印出来
M47期面试题
格式2
双小括号方法,即((…))格式,也可以用于算术运算,双小括号方法也可以使bash Shell实现C语言风格的
变量操作:
#2.将上面的目录移动到YYYY-MM/DD/下
#!/bin/bash
#
DIR=/data/test
cd $DIR || { echo 无法进入 $DIR;exit 1; }
for subdir in * ;do
YYYY_MM=echo $subdir |cut -d"-" -f1,2
DD=echo $subdir |cut -d"-" -f3
[ -d $YYYY_MM/$DD ] || mkdir -p $YYYY_MM/$DD &> /dev/null
mv $subdir/* $YYYY_MM/$DD
done
rm -rf $DIR/--*
[root@centos8 ~]#cat /data/scripts/for_scan_host.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-27
#FileName: for_scan_host.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
NET=10.0.0
for ID in {1..254};do
{
ping -c1 -W1 $NET.$ID &> /dev/null && echo $NET.$ID is up| tee -a
host_list.log || echo $NET.$ID is down
}&
done
wait
有若干只兔和鸡,兔和鸡加起来一共有100条腿,请写一个简单的shell算出兔和鸡各多少只可能组合(假设所
有的羊和鸡的腿都是健全的,且兔和鸡至少为1只)
说明:
控制变量初始化:仅在运行到循环代码段时执行一次
控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
范例:
范例:
for ((: for (( exp1; exp2; exp3 )); do COMMANDS; done
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))
do
循环体
done
[root@ubuntu1804 ~]#cat sum.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: for_sum2.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
for((sum=0,i=1;i<=100;i++));do
let sum+=i
done
echo sum=$sum
for((sum=0,i=1;i<=100;sum+=i,i++));do
范例:九九乘法表
范例:等腰三角形
true
done
echo sum=$sum
[root@ubuntu1804 ~]#bash sum.sh
sum=5050
sum=5050
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: for_99_2.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
#语法1实现
for i in {1..9};do
for j in seq $i
;do
echo -e "${j}x$i=$((ji))\t\c"
done
echo
done
#语法2实现
for((i=1;i<10;i++));do
for((j=1;j<=i;j++));do
echo -e "${j}x$i=$((ji))\t\c"
done
echo
done
[root@centos8 scripts]#cat for_triangle.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-27
#FileName: for_triangle.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
read -p "请输入三角形的行数: " line
for((i=1;i<=line;i++));do
for((k=0;k<=line-i;k++));do
echo -e ' \c'
范例:生成进度
范例:
练习:用 for 实现
1、判断/var/目录下所有文件的类型
2、添加10个用户user1-user10,密码为8位随机字符
3、/etc/rc.d/rc3.d目录下分别有多个以K开头和以S开头的文件;分别读取每个文件,以K开头的输出为
文件加stop,以S开头的输出为文件名加start,如K34filename stop S66filename start
4、编写脚本,提示输入正整数n的值,计算1+2+…+n的总和
5、计算100以内所有能被3整除的整数之和
6、编写脚本,提示请输入网络地址,如192.168.0.0,判断输入的网段中主机在线状态
7、打印九九乘法表
8、在/testdir目录下创建10个html文件,文件名格式为数字N(从1到10)加随机8个字母,如:
1AbCdeFgH.html
done
for((j=1;j<=2i-1;j++));do
echo -e '\c'
done
echo
done
[root@centos8 scripts]#bash for_triangle.sh
请输入三角形的行数: 10
*
[root@centos8 scripts]#
[root@centos8 ~]#for ((i = 0; i <= 100; ++i)); do printf "\e[4D%3d%%" $i;sleep
0.1s; done
100%[root@centos8 ~]#
[root@centos8 ~]#for((;😉);do echo for;sleep 1;done
for
for
for
for
for
for
for
9、打印等腰三角形
10、猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个。第二天早上又将剩下的桃子
吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,只
剩下一个桃子了。求第一天共摘了多少?
4.2.3 循环 while
格式:
说明:
CONDITION:循环控制条件;进入循环之前,先做一次判断;每一次循环之后会再次做判断;条件为
“true”,则执行一次循环;直到条件测试状态为“false”终止循环,因此:CONDTION一般应该有循环控
制变量;而此变量的值会在循环体不断地被修正
进入条件:CONDITION为 true
退出条件:CONDITION为 false
无限循环
范例:
范例:
while COMMANDS; do COMMANDS; done
while CONDITION; do
循环体
done
while true; do
循环体
done
while : ; do
循环体
done
[root@centos8 ~]#sum=0;i=1;while ((i<=100));do let sum+=i;let i++;done;echo $sum
5050
#配置发邮件的邮箱
[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
#
#********************************************************************
范例: 防止Dos攻击的脚本
练习:用while实现
1、编写脚本,求100以内所有正奇数之和
2、编写脚本,提示请输入网络地址,如:192.168.0.0,判断输入的网段中主机在线状态,并统计在线和
离线主机各多少
3、编写脚本,打印九九乘法表
4、编写脚本,利用变量RANDOM生成10个随机数字,输出这个10数字,并显示其中的最大值和最小值
5、编写脚本,实现打印国际象棋棋盘
#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
[root@centos8 ~]#cat check_link.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-12-28
#FileName: check_link.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
WARNING=10
touch deny_hosts.txt
while true;do
ss -nt | sed -nr '1!s#.* ([0-9.]+):[0-9]+ #\1#p'|sort |uniq -c|sort |
while read count ip;do
if [ $count -gt $WARNING ];then
echo $ip is deny
grep -q "$ip" deny_hosts.txt || { echo $ip >> deny_hosts.txt;
iptables -A INPUT -s $ip -j REJECT; }
fi
done
sleep 10
done
6、后续六个字符串:efbaf275cd、4be9c40b8b、44b2395c46、f8c8873ce0、b902c16c8b、
ad865d2f63是通过对随机数变量RANDOM随机执行命令: echo $RANDOM|md5sum|cut -c1-10
后的结果,请破解这些字符串对应的RANDOM值
4.2.4 while 特殊用法 while read
while 循环的特殊用法,遍历文件或文本的每一行
格式:
说明:依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line
范例:
范例:
范例:
while read line; do
循环体
done < /PATH/FROM/SOMEFILE
[root@centos8 ~]#echo magedu | read X ; echo $X
[root@centos8 ~]#echo magedu | while read X ; do echo $X;done
magedu
[root@centos8 ~]#echo magedu | { read X ; echo $X; }
magedu
[root@centos8 ~]#echo magedu | ( read X ; echo $X )
magedu
[root@centos8 ~]#echo mage wang zhang | ( read X Y Z; echo $X $Y $Z )
mage wang zhang
[root@centos8 ~]#echo mage wang zhang | while read X Y Z; do echo $X $Y $Z;done
mage wang zhang
cat while_read_diskcheck.sh
#!/bin/bash
WARNING=80
MAIL=root@wangxiaochun.com
while true;do
df |sed -nr "//dev/sd/s#([^ ]+) . ([0-9]+)%.#\1 \2#p"|while read
DEVICE USE;do
if [ $USE -gt $WARNING ] ;then
echo "$DEVICE will be full,use:$USE" | mail -s "DISK WARNING" $MAIL
fi
done
sleep 10
done
cat while_read_check_dos.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
范例:查看/sbin/nologin的shell类型的用户名和UID
4.2.5 循环 until
格式:
说明:
进入条件: CONDITION 为false
退出条件: CONDITION 为true
范例:
#Date: 2020-01-03
#FileName: while_read_check_dos.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
MAX=3
lastb | sed -rn '/ssh:/s@. ([0-9.]{1,3}{3}[0-9]{1,3}) .*@\1@p'|sort |uniq -c
|while read count ip ;do
if [ $count -gt $MAX ];then
iptables -A INPUT -s $ip -j REJECT
fi
done
cat while_read_passwd.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: while_read_passwd.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
while read line ;do
if [[ "$line" =~ /sbin/nologin$ ]] ;then
echo $line | cut -d: -f1,3
fi
done < /etc/passwd
until COMMANDS; do COMMANDS; done
until CONDITION; do
循环体
done
[root@centos8 ~]#sum=0;i=1;until ((i>100));do let sum+=i;let i++;done;echo $sum
5050
无限循环
4.2.6 循环控制语句 continue
continue [N]:提前结束第N层的本轮循环,而直接进入下一轮判断;最内层为第1层
格式:
范例:
until false; do
循环体
Done
while CONDITION1; do
CMD1
...
if CONDITION2; then
continue
fi
CMDn
...
done
[root@centos8 script40]#cat continue_for.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: continue_for.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
for ((i=0;i<10;i++));do
for((j=0;j<10;j++));do
[ $j -eq 5 ] && continue 2
echo $j
done
echo ---------------------------
done
[root@centos8 script40]#bash continue_for.sh
0 1 2 3 4 0 1 2 3 4
4.2.7 循环控制语句 break
break [N]:提前结束第N层整个循环,最内层为第1层
格式:
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
范例:
范例:
while CONDITION1; do
CMD1
...
if CONDITION2; then
break
fi
CMDn
...
done
[root@centos8 script40]#cat break_for.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: continue_for.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
for ((i=0;i<10;i++));do
for((j=0;j<10;j++));do
[ $j -eq 5 ] && break
echo $j
done
echo ---------------------------
done
[root@centos8 script40]#cat break_for.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: continue_for.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
for ((i=0;i<10;i++));do
for((j=0;j<10;j++));do
[ $j -eq 5 ] && break 2
echo $j
done
echo ---------------------------
done
[root@centos8 script40]#bash break_for.sh
范例:
0 1 2 3 4
[root@centos8 script40]#cat menu.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: menu.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
sum=0
COLOR='echo -e \033[1;31m'
COLOR2='echo -e \033[1;32m'
END="\033[0m"
while true;do
echo -e "\033[33;1m\c"
cat <<-EOF
- 鲍鱼
- 满汉全席
- 龙虾
- 燕窝
- 帝王蟹
- 点菜结束,结帐
EOF
echo -e "\033[0m"
read -p "请点菜(1-6): " MENU
case $MENU in
1|4)
$COLOR'菜价: $10'$END
let sum+=10
;;
3|5)
$COLOR'菜价: $20'$END
let sum+=20
;;
2)
$COLOR'菜价: $200000'$END
let sum+=200000
;;
6)
$COLOR2"你点的菜总价格是 $$sum"$END
break
;;
)
echo "点错了,没有这道菜"
范例:
4.2.8 循环控制 shift 命令
shift [n] 用于将参量列表 list 左移指定次数,缺省为左移一次。
参量列表 list 一旦被移动,最左端的那个参数就从列表中删除。while 循环遍历位置参量列表时,常用到
shift
范例:doit.sh
;;
esac
$COLOR2"你点的菜总价格是 $$sum"$END
done
[root@centos8 script40]#cat guess.sh
#!/bin/bash
#
#*******************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: guess.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
NUM=$[RANDOM%10]
while read -p "输入 0-9 之间的数字: " INPUT ;do
if [ $INPUT -eq $NUM ];then
echo "恭喜你猜对了!"
break
elif [ $INPUT -gt $NUM ];then
echo "数字太大了,重新猜!"
else
echo "数字太小了,重新猜!"
fi
done
#!/bin/bash
# Name: doit.sh
# Purpose: shift through command line arguments
# Usage: doit.sh [args]
while [ $You can't use 'macro parameter character #' in math mode# -gt 0 ] # or
(( $# > 0 ))
do
echo $*
shift
done
./doit.sh a b c d e f g h
范例:示例:shift.sh
范例:
练习
#!/bin/bash
#step through all the positional parameters
until [ -z "$1" ]
do
echo "$1"
shift
done
echo
./shfit.sh a b c d e f g h
[root@centos8 ~]#vim shift_batch_user.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: shift_batch_user.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
if [ $# -eq 0 ];then
echo "Usage: basename $0
user1 user2 ..."
exit
fi
while [ "$1" ];do
if id $1 &> /dev/null;then
echo $1 is exist
else
useradd $1
echo "$1 is created"
fi
shift
done
echo "All user is created"
[root@centos8 script40]#bash shift_batch_user.sh
Usage: shift_batch_user.sh user1 user2 ...
[root@centos8 script40]#bash shift_batch_user.sh tom alice jack
tom is exist
alice is exist
jack is created
All user is created
1、每隔3秒钟到系统上获取已经登录的用户的信息;如果发现用户hacker登录,则将登录时间和主机记
录于日志/var/log/login.log中,并退出脚本
2、随机生成10以内的数字,实现猜字游戏,提示比较大或小,相等则退出
3、用文件名做为参数,统计所有参数文件的总行数
4、用二个以上的数字为参数,显示其中的最大值和最小值
4.2.9 循环与菜单 select
格式:
说明:
select 循环主要用于创建菜单,按数字顺序排列的菜单项显示在标准错误上,并显示 PS3 提示符,
等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入菜单列表中的某个数字,会将对应的WORD值赋值给NAME变量
用户输入被保存在内置变量 REPLY 中
select 是个无限循环,因此要用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c
退出循环
select 经常和 case 联合使用
与 for 循环类似,可以省略 in list,此时使用位置参量
范例:
select NAME [in WORDS ... ;] do COMMANDS; done
select NAME in list ;do
循环体命令
done
cat select.sh
#!/bin/bash
sum=0
PS3="请点菜(1-6): "
select MENU in 北京烤鸭 佛跳墙 小龙虾 羊蝎子 火锅 点菜结束;do
case $REPLY in
1)
echo $MENU 价格是 ¥100
let sum+=100
;;
2)
echo $MENU 价格是 ¥88
let sum+=88
;;
3)
echo $MENU价格是 ¥66
let sum+=66
;;
4)
echo $MENU 价格是 ¥166
let sum+=166
;;
5 函数 function
5.1 函数介绍
函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程
它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部
分
函数和shell程序区别
Shell程序在子Shell中运行
函数在当前Shell中运行。因此在当前Shell中,函数可对shell中变量进行修改
5.2 管理函数
函数由两部分组成:函数名和函数体
帮助参看:help function
5.2.1 定义函数
5)
echo $MENU 价格是 ¥200
let sum+=200
;;
6)
echo "点菜结束,退出"
break
;;
*)
echo "点菜错误,重新选择"
;;
esac
done
echo "总价格是: $sum"
#语法一:
func_name (){
...函数体...
} #
语法二:
function func_name {
...函数体...
}
#语法三:
function func_name () {
...函数体...
}
5.2.2 查看函数
5.2.3 删除函数
格式:
5.3 函数调用
函数的调用方式
可在交互式环境下定义函数
可将函数放在脚本文件中作为它的一部分
可放在只包含函数的单独文件中
调用:函数只有被调用才会执行,通过给定函数名调用函数,函数名出现的地方,会被自动替换为函数
代码
函数的生命周期:被调用时创建,返回时终止
5.3.1 交互式环境调用函数
交互式环境下定义和使用函数
范例:
范例:实现判断CentOS的主版本
#查看当前已定义的函数名
declare -F
#查看当前已定义的函数定义
declare -f
#查看指定当前已定义的函数名
declare -f func_name
#查看当前已定义的函数名定义
declare -F func_name
unset func_name
[root@centos8 ~]#dir() {
> ls -l
> }
[root@centos8 ~]#dir
total 4
-rw-------. 1 root root 1559 Nov 7 19:33 anaconda-ks.cfg
[root@centos8 ~]#centos_version() {
> sed -rn 's#^.* +([0-9]+)..*#\1#p' /etc/redhat-release
> }
[root@centos8 ~]#centos_version
8
5.3.2 在脚本中定义及使用函数
函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用,调用
函数仅使用其函数名即可
范例:
[root@centos8 ~]#cat func1.sh
#!/bin/bash
#name:func1
hello(){
echo "Hello there today's date is date +%F
"
}
echo "now going to the function hello"
hello
echo "back from the function"
[root@centos8 ~]#./func1.sh
now going to the function hello
Hello there today's date is 2019-12-18
back from the function
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: reset.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
disable_selinux(){
sed -i.bak 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
echo "SElinux已禁用,重新启动后才可生效"
}
disable_firewall(){
systemctl disable --now firewalld &> /dev/null
echo "防火墙已禁用"
}
set_ps1() {
echo "PS1='[\e[1;35m][\u@\h \W]\$[\e[0m]'" > /etc/profile.d/reset.sh
echo "提示符已修改成功,请重新登录生效"
}
set_eth(){
sed -i.bak '/GRUB_CMDLINE_LINUX=/s#"$# net.ifnames=0"#' /etc/default/grub
grub2-mkconfig -o /boot/grub2/grub.cfg &> /dev/null
echo "网络名称已修改成功,请重新启动才能生效"
}
PS3="请选择相应的编号(1-6): "
MENU='
禁用SELinux
关防火墙
修改提示符
修改网卡名
5.3.3 使用函数文件
可以将经常使用的函数存入一个单独的函数文件,然后将函数文件载入shell,再进行调用函数
函数文件名可任意选取,但最好与相关任务有某种联系,例如:functions
一旦函数文件载入shell,就可以在命令行或脚本中调用函数。可以使用delcare -f 或set 命令查看所有定
义的函数,其输出列表包括已经载入shell的所有函数
若要改动函数,首先用unset命令从shell中删除函数。改动完毕后,再重新载入此文件
实现函数文件的过程:
- 创建函数文件,只存放函数的定义
- 在shell脚本或交互式shell中调用函数文件,格式如下:
范例:
以上全实现
退出
'
select M in $MENU ;do
case $REPLY in
1)
disable_selinux
;;
2)
disable_firewall
;;
3)
set_ps1
;;
4)
set_eth
;;
5)
disable_selinux
disable_firewall
set_ps1
set_eth
;;
6)
break
;;
)
echo "请输入正确的数字"
esac
done
. filename
source filename
[root@centos8 ~]#cat functions
#!/bin/bash
#functions
范例:
hello(){
echo Run hello Function
}
hello2(){
echo Run hello2 Function
}
[root@centos8 ~]#. functions
[root@centos8 ~]#hello
Run hello Function
[root@centos8 ~]#hello2
Run hello2 Function
[root@centos8 ~]#declare -f hello hello2
hello ()
{
echo Run hello Function
}
hello2 ()
{
echo Run hello2 Function
}
[root@centos8 script40]#cat reset.sh
#!/bin/bash
#
#*******************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-03
#FileName: reset.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
. /etc/init.d/functions
disable_selinux(){
sed -i.bak 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
action "SElinux已禁用,重新启动后才可生效"
}
disable_firewall(){
systemctl disable --now firewalld &> /dev/null
action "防火墙已禁用"
}
set_ps1() {
echo "PS1='[\e[1;35m][\u@\h \W]\$[\e[0m]'" > /etc/profile.d/reset.sh
action "提示符已修改成功,请重新登录生效"
}
set_eth(){
sed -i.bak '/GRUB_CMDLINE_LINUX=/s#"$# net.ifnames=0"#' /etc/default/grub
grub2-mkconfig -o /boot/grub2/grub.cfg &> /dev/null
action "网络名称已修改成功,请重新启动才能生效"
}
PS3="请选择相应的编号(1-6): "
MENU='
5.4 函数返回值
函数的执行结果返回值:
使用echo等命令进行输出
函数体中调用命令的输出结果
函数的退出状态码:
默认取决于函数中执行的最后一条命令的退出状态码
自定义退出状态码,其格式为:
return | 从函数中返回,用最后状态命令决定返回值 |
---|---|
return 0 | 无错误返回 |
return 1-255 | 有错误返回 |
5.5 环境函数
类拟于环境变量,也可以定义环境函数,使子进程也可使用父进程定义的函数
定义环境函数:
禁用SELinux
关防火墙
修改提示符
修改网卡名
以上全实现
退出
'
select M in $MENU ;do
case $REPLY in
1)
disable_selinux
;;
2)
disable_firewall
;;
3)
set_ps1
;;
4)
set_eth
;;
5)
disable_selinux
disable_firewall
set_ps1
set_eth
;;
6)
break
;;
*)
echo "请输入正确的数字"
esac
done
查看环境函数:
5.6 函数参数
函数可以接受参数:
传递参数给函数:在函数名后面以空白分隔给定参数列表即可,如:testfunc arg1 arg2 ...
在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用$@, $*, $#等特殊变量
范例:实现进度条功能
export -f function_name
declare -xf function_name
export -f
declare -xf
[root@centos8 ~]#cat progress_chart.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-05-30
#FileName: progress_chart.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
function print_chars()
{
# 传入的第一个参数指定要打印的字符串
local char="$1"
# 传入的第二个参数指定要打印多少次指定的字符串
local number="$2"
local c
for ((c = 0; c < number; ++c)); do
printf "$char"
done
}
COLOR=32
declare -i end=50
for ((i = 1; i <= end; ++i)); do
printf "\e[1;${COLOR}m\e[80D["
print_chars "#" $i
print_chars " " $((end - i))
printf "] %3d%%\e[0m" $((i * 2))
sleep 0.1s
done
echo
5.7 函数变量
变量作用域:
普通变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量的作用
范围是当前shell脚本程序文件,包括脚本中的函数
环境变量:当前shell和子shell有效
本地变量:函数的生命周期;函数结束时变量被自动销毁
注意:
如果函数中定义了普通变量,且名称和局部变量相同,则使用本地变量
由于普通变量和局部变量会冲突,建议在函数中只使用本地变量
在函数中定义本地变量的方法
5.8 函数递归
函数递归:函数直接或间接调用自身,注意递归层数,可能会陷入死循环
递归特点:
函数内部自已调用自已
必须有结束函数的出口语句,防止死循环
范例: 无出口的递归函数调用
递归示例:
阶乘是基斯顿·卡曼于 1808 年发明的运算符号,是数学术语
一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且0和1的阶乘为1,自然数n的
阶乘写作n!
n!=1×2×3×...×n
阶乘亦可以递归方式定义:0!=1,n!=(n-1)!×n
n!=n(n-1)(n-2)...1
n(n-1)! = n(n-1)(n-2)!
范例:fact.sh
local NAME=VALUE
[root@centos8 ~]#func () { echo $i;echo "run func";let i++; func; }
[root@centos8 ~]#func
#!/bin/bash
#
fact() {
if [ $1 -eq 0 -o $1 -eq 1 ]; then
echo 1
else
echo $[$1*$(fact $[$1-1])]
fi
}
fact $1
范例: 测试递归的嵌套深度
fork 炸弹是一种恶意程序,它的内部是一个不断在 fork 进程的无限循环,实质是一个简单的递归程序。
由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资源
参考:https://en.wikipedia.org/wiki/Fork_bomb
函数实现
脚本实现
练习
- 编写函数,实现OS的版本判断
- 编写函数,实现取出当前系统eth0的IP地址
- 编写函数,实现打印绿色OK和红色FAILED
- 编写函数,实现判断是否无位置参数,如无参数,提示错误
- 编写函数,实现两个数字做为参数,返回最大值
- 编写服务脚本/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
[root@centos8 ~]#test(){
let i++
echo i=$i
test
}
[root@centos8 ~]#test
😦){ 😐:& };:
bomb() { bomb | bomb & }; bomb
cat Bomb.sh
#!/bin/bash
./$0|./$0&
stopped...”
(7)在所有模式下禁止启动该服务,可用chkconfig 和 service命令管理
说明:SCRIPT_NAME为当前脚本名
- 编写脚本/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退出
- 斐波那契数列又称黄金分割数列,因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为
“兔子数列”,指的是这样一个数列: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阶斐波那契数列
- 汉诺塔(又称河内塔)问题是源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱
子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始
按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次
只能移动一个圆盘,利用函数,实现N片盘的汉诺塔的移动步骤
6 其它脚本相关工具
6.1 信号捕捉 trap
trap 命令可以捕捉信号,修改信号原来的功能,实现自定义功能
#列出所有信号
trap -l
#进程收到系统发出的指定信号后,将执行自定义指令,而不会执行原操作
trap '触发指令' 信号
#忽略信号的操作
trap '' 信号
#恢复原信号的操作
trap '-' 信号
#列出自定义信号操作
trap -p
范例:
范例: 当脚本正常或异常退出时,也会执行finish函数
6.2 创建临时文件 mktemp
#当脚本退出时,执行finish函数
trap finish EXIT
#!/bin/bash
trap "echo 'Press ctrl+c or ctrl+\ '" int quit
trap -p
for((i=0;i<=10;i++))
do
sleep 1
echo $i
done
trap '' int
trap -p
for((i=11;i<=20;i++))
do
sleep 1
echo $i
done
trap '-' int
trap -p
for((i=21;i<=30;i++))
do
sleep 1
echo $i
done
[root@centos8 ~]#cat trap_exit.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-06
#FileName: trap_exit.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
finish(){
echo "Finish at date +%F_%T
" | tee -a /root/finish.log
}
trap finish exit
while true ;do
echo running
sleep 1
done
mktemp 命令用于创建并显示临时文件,可避免冲突
格式
常见选项:
范例:
范例:实现文件垃圾箱
6.3 安装复制文件 install
install 功能相当于cp,chmod,chown,chgrp ,mkdir 等相关工具的集合
install命令格式:
mktemp [OPTION]... [TEMPLATE]
说明:TEMPLATE: filenameXXX,X至少要出现三个
-d #创建临时目录
-p DIR或--tmpdir=DIR #指明临时文件所存放目录位置
[root@centos8 ~]#mktemp
/tmp/tmp.UogGCumh8C
[root@centos8 ~]#mktemp /tmp/testXXX
[root@centos8 ~]#tmpdir=mktemp -d /tmp/testdirXXX
[root@centos8 ~]#mktemp --tmpdir=/testdir testXXXXXX
#方法1:脚本实现
[root@centos8 ~]#cat /data/scripts/rm.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-29
#FileName: rm.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
DIR=mktemp -d /tmp/trash-$(date +%F_%H-%M-%S)XXXXXX
mv $* $DIR
echo $* is move to $DIR
[root@centos8 ~]#alias rm=/data/scripts/rm.sh
#方法2:函数实现
[root@centos8 ~]#function rm () { local trash=$(mktemp -d /tmp/trash$(date
+%F_%H-%M-%S)XXX);mv $* $trash; }
选项:
范例:
6.4 交互式转化批处理工具 expect
expect 是由Don Libes基于 Tcl( Tool Command Language )语言开发的,主要应用于自动化交互式
操作的场景,借助 expect 处理交互的命令,可以将交互过程如:ssh登录,ftp登录等写在一个脚本上,
使之自动化完成。尤其适用于需要对多台服务器执行相同操作的环境中,可以大大提高系统管理人员的
工作效率
范例: 安装expect 及mkpasswd 工具
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@centos8 ~]#install -m 700 -o wang -g admins srcfile desfile
[root@centos8 ~]#install -m 770 -d /testdir/installdir
[root@centos8 ~]#install -m 600 -o wang -g bin anaconda-ks.cfg /data/a.cfg
[root@centos8 ~]#ll /data/a.cfg
-rw------- 1 wang bin 1550 Jun 23 20:28 /data/a.cfg
[root@centos8 ~]#install -m 700 -o mage -g daemon -d /data/testdir
[root@centos8 ~]#ll -d /data/testdir
drwx------ 2 mage daemon 6 Apr 29 15:09 /data/testdir
[root@centos8 ~]#yum -y install expect
[root@centos8 ~]#rpm -ql expect|head
/usr/bin/autoexpect
/usr/bin/dislocate
/usr/bin/expect
/usr/bin/ftp-rfc
/usr/bin/kibitz
/usr/bin/lpunlock
/usr/bin/mkpasswd
/usr/bin/passmass
/usr/bin/rftp
/usr/bin/rlogin-cwd
[root@centos8 ~]#mkpasswd
mghe5J&9A
[root@centos8 ~]#mkpasswd
XhyQ67uo=
[root@centos8 ~]#mkpasswd -l 15 -d 3 -C 5
9T{htJmcA7pgCJ2
expect 语法:
常见选项:
示例:
expect中相关命令 spawn | 启动新的进程 |
---|---|
expect | 从进程接收字符串 |
send | 用于向进程发送字符串 |
interact | 允许用户交互 |
exp_continue 匹配多个字符串在执行动作后加此命令
expect最常用的语法(tcl语言:模式-动作)
单一分支模式语法:
匹配到hi后,会输出“you said hi”,并换行
多分支模式语法:
匹配hi,hello,bye任意字符串时,执行相应输出。等同如下:
expect [选项] [ -c cmds ] [ [ -[f|b] ] cmdfile ] [ args ]
-c:从命令行执行expect脚本,默认expect是交互地执行的
-d:可以调试信息
expect -c 'expect "\n" {send "pressed enter\n"}'
expect -d ssh.exp
[root@centos8 test]#expect
expect1.1> expect "hi" {send "You said hi\n"}
hahahixixi
You said hi
[root@centos8 ~]#expect
expect1.1> expect "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n"
} "bye" { send "Good bye\n" }
hehe
Hehe yourself
expect1.2> expect "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n"
} "bye" { send "Good bye\n" }
bye
Good bye
expect1.3> expect "hi" { send "You said hi\n" } "hehe" { send "Hehe yourself\n"
} "bye" { send "Good bye\n" }
hi
You said hi
expect1.4>
expect {
"hi" { send "You said hi\n"}
"hehe" { send "Hehe yourself\n"}
范例1:非交互式复制文件
范例2:自动登录
范例3:expect 变量
范例4:expect 位置参数
"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>
#!/usr/bin/expect
spawn scp /etc/redhat-release 10.0.0.7:/data
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "magedu\n" }
}
expect eof
#!/usr/bin/expect
spawn ssh 10.0.0.7
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "magedu\n" }
}
interact
#!/usr/bin/expect
set ip 10.0.0.7
set user root
set password magedu
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
interact
[root@centos8 ~]#cat expect4
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
spawn ssh $user@$ip
范例5:expect 执行多个命令
范例6:shell脚本调用 expect
范例7: shell脚本利用循环调用expect在CentOS和Ubuntu上批量创建用户
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
interact
[root@centos8 ~]#./expect4 10.0.0.7 root magedu
spawn ssh root@10.0.0.7
root@10.0.0.7's password:
Last login: Wed Apr 29 15:34:14 2020 from 10.0.0.8
[root@centos7 ~]#exit
logout
Connection to 10.0.0.7 closed.
#!/usr/bin/expect
set ip [lindex $argv 0]
set user [lindex $argv 1]
set password [lindex $argv 2]
set timeout 10
spawn ssh $user@$ip
expect {
"yes/no" { send "yes\n";exp_continue }
"password" { send "$password\n" }
}
expect "]#" { send "useradd haha\n" }
expect "]#" { send "echo magedu |passwd --stdin haha\n" }
send "exit\n"
expect eof
#./ssh4.exp 10.0.0.7 root magedu
#!/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
#./ssh5.sh 192.168.8.10 root magedu
范例:
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-01-06
#FileName: expect7.sh
#URL: http://www.magedu.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
NET=10.0.0
user=root
password=magedu
IPLIST="
7
18
101
"
for ID in $IPLIST;do
ip=$NET.$ID
expect <<EOF
set timeout 20
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
[root@centos8 scripts]#cat expect8.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-04-29
#FileName: expect8.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
NET=10.0.0
user=root
password=magedu
IPLIST="
7
18
7 数组 array
7.1 数组介绍
变量:存储单个元素的内存空间
数组:存储多个元素的连续的内存空间,相当于多个变量的集合
数组名和索引
索引的编号从0开始,属于数值索引
索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash 4.0版本之后开始支持
bash的数组支持稀疏格式(索引不连续)
7.2 声明数组
注意:两者不可相互转换
7.3 数组赋值
数组元素的赋值
(1) 一次只赋值一个元素
范例:
"
for ID in $IPLIST ;do
ip=$NET.$ID
expect <<EOF
set timeout 20
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 ARRAY_NAME
#关联数组必须先声明,再使用
declare -A ARRAY_NAME
ARRAY_NAME[INDEX]=VALUE
(2) 一次赋值全部元素
范例:
(3) 只赋值特定元素
(4) 交互式数组值对赋值
范例:
范例:
7.4 显示所有数组
显示所有数组:
weekdays[0]="Sunday"
weekdays[4]="Thursday"
ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)
title=("ceo" "coo" "cto")
num=({0..10})
alpha=({a..g})
file=( *.sh )
ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)
read -a ARRAY
[root@centos8 ~]#declare -A course
[root@centos8 ~]#declare -a course
-bash: declare: course: cannot convert associative to indexed array
[root@centos8 ~]#file=( .sh )
[root@centos8 ~]#declare -A file
-bash: declare: file: cannot convert indexed to associative array
[root@ubuntu1804 ~]#i=a
[root@ubuntu1804 ~]#j=1
[root@ubuntu1804 ~]#declare -A arr
[root@ubuntu1804 ~]#arr[$i$j]=mage
[root@ubuntu1804 ~]#j=2
[root@ubuntu1804 ~]#arr[$i$j]=wang
[root@ubuntu1804 ~]#echo ${arr[]}
wang mage
[root@ubuntu1804 ~]#echo ${arr[a1]}
mage
[root@ubuntu1804 ~]#echo ${arr[a2]}
wang
范例:
7.5 引用数组
引用特定的数组元素
范例:
引用数组所有元素
范例:
数组的长度,即数组中元素的个数
declare -a
[root@centos8 ~]#declare -a
declare -a BASH_ARGC=()
declare -a BASH_ARGV=()
declare -a BASH_COMPLETION_VERSINFO=([0]="2" [1]="7")
declare -a BASH_LINENO=()
declare -ar BASH_REMATCH=()
declare -a BASH_SOURCE=()
declare -ar BASH_VERSINFO=([0]="4" [1]="4" [2]="19" [3]="1" [4]="release"
[5]="x86_64-redhat-linux-gnu")
declare -a DIRSTACK=()
declare -a FUNCNAME
declare -a GROUPS=()
declare -a PIPESTATUS=([0]="0")
${ARRAY_NAME[INDEX]}
#如果省略[INDEX]表示引用下标为0的元素
[root@centos8 ~]#declare -a title=([0]="ceo" [1]="coo" [2]="cto")
[root@centos8 ~]#echo ${title[1]}
coo
[root@centos8 ~]#echo ${title}
ceo
[root@centos8 ~]#echo ${title[2]}
cto
[root@centos8 ~]#echo ${title[3]}
${ARRAY_NAME[]}
${ARRAY_NAME[@]}
[root@centos8 ~]#echo ${title[@]}
ceo coo cto
[root@centos8 ~]#echo ${title[]}
ceo coo cto
范例:
数组的所有下标
范例:
7.6 删除数组
删除数组中的某元素,会导致稀疏格式
删除整个数组
范例:
7.7 数组数据处理
数组切片:
${#ARRAY_NAME[]}
${#ARRAY_NAME[@]}
[root@centos8 ~]#echo ${#title[]}
3
${!ARRAY_NAME[]}
${!ARRAY_NAME[@]}
[root@centos8 ~]#declare -a title=([0]="ceo" [1]="coo" [2]="cto")
[root@centos8 ~]#echo ${!title[@]}
0 1 2
[root@centos8 ~]#echo ${!title[]}
0 1 2
unset ARRAY[INDEX]
[root@centos8 ~]#echo ${title[]}
ceo coo cto
[root@centos8 ~]#unset title[1]
[root@centos8 ~]#echo ${title[]}
ceo cto
unset ARRAY
[root@centos8 ~]#unset title
[root@centos8 ~]#echo ${title[*]}
[root@centos8 ~]#
范例:
向数组中追加元素:
范例:
7.8 关联数组
注意:关联数组必须先声明再调用
范例:
${ARRAY[@]:offset:number}
${ARRAY[]:offset:number}
offset #要跳过的元素个数
number #要取出的元素个数
#取偏移量之后的所有元素
{ARRAY[@]:offset}
{ARRAY[]:offset}
[root@centos8 ~]#num=({0..10})
[root@centos8 ~]#echo ${num[]:2:3}
2 3 4
[root@centos8 ~]#echo ${num[]:6}
6 7 8 9 10
ARRAY[${#ARRAY[*]}]=value
ARRAY[${#ARRAY[@]}]=value
[root@centos8 ~]#num[${#num[@]}]=11
[root@centos8 ~]#echo ${#num[@]}
12
[root@centos8 ~]#echo ${num[@]}
0 1 2 3 4 5 6 7 8 9 10 11
declare -A ARRAY_NAME
ARRAY_NAME=([idx_name1]='val1' [idx_name2]='val2‘...)
[root@centos8 ~]#name[ceo]=mage
[root@centos8 ~]#name[cto]=wang
[root@centos8 ~]#name[coo]=zhang
[root@centos8 ~]#echo ${name[ceo]}
zhang
[root@centos8 ~]#echo ${name[cto]}
zhang
[root@centos8 ~]#echo ${name[coo]}
zhang
[root@centos8 ~]#echo ${name}
zhang
[root@centos8 ~]#declare -A name
-bash: declare: name: cannot convert indexed to associative array
[root@centos8 ~]#unset name
[root@centos8 ~]#declare -A name
[root@centos8 ~]#name[ceo]=mage
范例:关联数组
范例: 显示关联数组的所有下标
7.9 范例
范例:生成10个随机数保存于数组中,并找出其最大值和最小值
范例:编写脚本,定义一个数组,数组中的元素对应的值是/var/log目录下所有以.log结尾的文件;统计
出其下标为偶数的文件中的行数之和
[root@centos8 ~]#name[cto]=wang
[root@centos8 ~]#name[coo]=zhang
[root@centos8 ~]#echo ${name[coo]}
zhang
[root@centos8 ~]#echo ${name[ceo]}
mage
[root@centos8 ~]#echo ${name[cto]}
wang
[root@centos8 ~]#echo ${name[]}
mage wang zhang
[root@centos8 ~]#declare -A student
[root@centos8 ~]#student[name1]=lijun
[root@centos8 ~]#student[name2]=ziqing
[root@centos8 ~]#student[age1]=18
[root@centos8 ~]#student[age2]=16
[root@centos8 ~]#student[gender1]=m
[root@centos8 ~]#student[city1]=nanjing
[root@centos8 ~]#student[gender2]=f
[root@centos8 ~]#student[city2]=anhui
[root@centos8 ~]#student[gender2]=m
[root@centos8 ~]#student[name50]=alice
[root@centos8 ~]#student[name3]=tom
[root@centos8 ~]#for i in {1..50};do echo student[name$i]=${student[name$i]};
done
[root@centos8 ~]#declare -A title=([ceo]=mage [coo]=zhang [cto]=wang)
[root@centos8 ~]#echo ${!title[@]}
ceo cto coo
#!/bin/bash
declare -i min max
declare -a nums
for ((i=0;i<10;i++));do
nums[$i]=$RANDOM
[ $i -eq 0 ] && min=${nums[0]} && max=${nums[0]}&& continue
[ ${nums[$i]} -gt $max ] && max=${nums[$i]} && continue
[ ${nums[$i]} -lt $min ] && min=${nums[$i]}
done
echo "All numbers are ${nums[]}"
echo Max is $max
echo Min is $min
范例: 告警邮件
练习
- 输入若干个数值存入数组中,采用冒泡算法进行升序或降序排序
- 将下图所示,实现转置矩阵 matrix.sh
1 2 3 1 4 7
4 5 6 ===> 2 5 8
7 8 9 3 6 9
- 打印杨辉三角形
8 字符串处理
8.1 字符串切片
#!/bin/bash
#
declare -a files
files=(/var/log/.log)
declare -i lines=0
for i in $(seq 0 $[${#files[]}-1]); do
if [ $[$i%2] -eq 0 ];then
let lines+=$(wc -l ${files[$i]} | cut -d' ' -f1)
fi
done
echo "Lines: $lines"
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-02-31
#FileName: mail_list.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
mail_list=(
lbtooth@qq.com
29308620@qq.com
)
send_mail() {
for mail in ${mail_list[*]};do
echo "FBI Warning" | mail -s "Warning" $mail
done
}
send_mail
8.1.1 基于偏移量取字符串
范例:
#返回字符串变量var的字符的长度,一个汉字算一个字符
${#var}
#返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,到最后的部分,
offset的取值在0 到 ${#var}-1 之间(bash4.2后,允许为负值)
${var:offset}
#返回字符串变量var中从第offset个字符后(不包括第offset个字符)的字符开始,长度为number的部分
${var:offset:number}
#取字符串的最右侧几个字符,取字符串的最右侧几个字符, 注意:冒号后必须有一空白字符
${var: -length}
#从最左侧跳过offset字符,一直向右取到距离最右侧lengh个字符之前的内容,即:掐头去尾
${var:offset:-length}
#先从最右侧向左取到length个字符开始,再向右取到距离最右侧offset个字符之间的内容,注意:-length
前空格,并且length必须大于offset
${var: -length:-offset}
[root@centos8 script40]#str=abcdef我你他
[root@centos8 script40]#echo ${#str}
9
[root@centos8 script40]#echo ${str:2}
cdef我你他
[root@centos8 script40]#echo ${str:2:3}
cde
[root@centos8 script40]#echo ${str:-3}
abcdef我你他
[root@centos8 script40]#echo ${str: -3}
我你他
[root@centos8 script40]#echo ${str:2:-3}
cdef
[root@centos8 script40]#echo ${str: -2:-3}
-bash: -3: substring expression < 0
[root@centos8 script40]#echo ${str: -3:-2}
我
[root@centos8 script40]#echo ${str:-3:-2}
abcdef我你他
[root@centos8 script40]#echo ${str: -3:-2}
我
[root@centos8 script40]#echo ${str: -5:-2}
ef我
8.1.2 基于模式取子串
范例:
范例:
范例:
8.2 查找替换
#其中word可以是指定的任意字符,自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字
符串开头至第一次出现word字符串(含)之间的所有字符,即懒惰模式,以第一个word为界删左留右
${var#word}
#从var变量的值中删除以word开头的部分
${var#word}
#同上,贪婪模式,不同的是,删除的是字符串开头至最后一次由word指定的字符之间的所有内容,即贪婪模
式,以最后一个word为界删左留右
${var##word}
${var##word}
[root@centos8 ~]#file="var/log/messages"
[root@centos8 ~]#echo ${file#/}
log/messages
[root@centos8 ~]#echo ${file##/}
messages
#其中word可以是指定的任意字符,功能:自右而左,查找var变量所存储的字符串中,第一次出现的word,
删除字符串最后一个字符向左至第一次出现word字符串(含)之间的所有字符,即懒惰模式,以从右向左的第一
个word为界删右留左
${var%word}
${var%word}
#同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符,即贪婪模式,以从右向
左的最后一个word为界删右留左
${var%%word}
${var%%word}
[root@centos8 ~]#file="var/log/messages"
[root@centos8 ~]#echo ${file%/}
var/log
[root@centos8 ~]#echo ${file%%/}
var
[root@centos8 ~]#url=http://www.magedu.com:8080
[root@centos8 ~]#echo ${url##:}
8080
[root@centos8 ~]#echo ${url%%:}
http
8.3 查找并删除
8.4 字符大小写转换
8.5 变量扩展
范例:
#查找var所表示的字符串中,第一次被pattern所匹配到的字符串,以substr替换之,懒惰模式
${var/pattern/substr}
#查找var所表示的字符串中,所有能被pattern所匹配到的字符串,以substr替换之,贪婪模式
${var//pattern/substr}
#查找var所表示的字符串中,行首被pattern所匹配到的字符串,以substr替换之
${var/#pattern/substr}
#查找var所表示的字符串中,行尾被pattern所匹配到的字符串,以substr替换之
${var/%pattern/substr}
#删除var表示的字符串中第一次被pattern匹配到的字符串,懒惰模式
${var/pattern}
#删除var表示的字符串中所有被pattern匹配到的字符串,贪婪模式
${var//pattern}
#删除var表示的字符串中所有以pattern为行首匹配到的字符串
${var/#pattern}
#删除var所表示的字符串中所有以pattern为行尾所匹配到的字符串
${var/%pattern}
#把var中的所有小写字母转换为大写
${var^^}
#把var中的所有大写字母转换为小写
${var,,}
#扩展以所有prefix开头的变量
${!prefix}
${!prefix@}
[root@centos8 ~]#file1=a.txt
[root@centos8 ~]#file2=b.txt
[root@centos8 ~]#file3=c.txt
[root@centos8 ~]#echo ${!file}
file1 file2 file3
[root@centos8 ~]#echo ${!file@}
file1 file2 file3
9 高级变量
9.1 高级变量赋值
范例:
范例:
9.2 高级变量用法-有类型变量
Shell变量一般是无类型的,但是bash Shell提供了declare和typeset两个命令用于指定变量的类型,两
个命令是等价的
[root@centos8 ~]#title=ceo
[root@centos8 ~]#name=${title-mage}
[root@centos8 ~]#echo $name
ceo
[root@centos8 ~]#title=
[root@centos8 ~]#name=${title-mage}
[root@centos8 ~]#echo $name
[root@centos8 ~]#unset title
[root@centos8 ~]#name=${title-mage}
[root@centos8 ~]#echo $name
mage
[root@centos8 ~]#title=ceo
[root@centos8 ~]#name=${title:-mage}
[root@centos8 ~]#echo $name
ceo
[root@centos8 ~]#title=
[root@centos8 ~]#name=${title:-mage}
[root@centos8 ~]#echo $name
mage
[root@centos8 ~]#unset title
[root@centos8 ~]#name=${title:-mage}
[root@centos8 ~]#echo $name
mage
9.3 变量间接引用
9.3.1 eval命令
eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。该命令适用于那些一次扫描无法实
现其功能的变量,该命令对变量进行两次扫描
范例:
declare [选项] 变量名
选项:
-r 声明或显示只读变量
-i 将变量定义为整型数
-a 将变量定义为数组
-A 将变量定义为关联数组
-f 显示已定义的所有函数名及其内容
-F 仅显示已定义的所有函数名
-x 声明或显示环境变量和函数,相当于export
-l 声明变量为小写字母 declare -l var=UPPER
-u 声明变量为大写字母 declare -u var=lower
-n make NAME a reference to the variable named by its value
[root@centos8 ~]# CMD=whoami
[root@centos8 ~]# echo $CMD
whoami
[root@centos8 ~]# eval $CMD
root
[root@centos8 ~]# n=10
[root@centos8 ~]# echo {0..$n}
{0..10}
[root@centos8 ~]# eval echo {0..$n}
0 1 2 3 4 5 6 7 8 9 10
[root@centos8 ~]#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=a
[root@centos8 ~]#j=1
[root@centos8 ~]#$i$j=hello
-bash: a1=hello: command not found
[root@centos8 ~]#eval $i$j=hello
[root@centos8 ~]#echo $i$j
a1
[root@centos8 ~]#echo $a1
9.3.2 间接变量引用
如果第一个变量的值是第二个变量的名字,从第一个变量引用第二个变量的值就称为间接变量引用
variable1的值是variable2,而variable2又是变量名,variable2的值为value,间接变量引用是指通过
variable1获得变量值value的行为
bash Shell提供了两种格式实现间接变量引用
范例:
范例:
hello
variable1=variable2
variable2=value
#示例:
i=1
$1=wang
#方法1
#变量赋值
eval tempvar=$$variable1
#显示值
eval echo $$variable1
eval echo '$'$variable1
#方法2
#变量赋值
tempvar=${!variable1}
#显示值
echo ${!variable1}
[root@centos8 ~]#ceo=name
[root@centos8 ~]#name=mage
[root@centos8 ~]#echo $ceo
name
[root@centos8 ~]#echo $$ceo
33722ceo
[root@centos8 ~]#echo $$
33722
[root@centos8 ~]#echo $$ceo
$name
[root@centos8 ~]#eval echo $$ceo
mage
[root@centos8 ~]#eval tmp=$$ceo
[root@centos8 ~]#echo $tmp
mage
[root@centos8 ~]#echo ${!ceo}
mage
范例: 生成位置变量
范例: 批量创建用户
[root@server ~]# N1=N2
[root@server ~]# N2=wangxiaochun
[root@server ~]# eval NAME=$$N1
[root@server ~]# echo $NAME
wangxiaochun
[root@server ~]# NAME=${!N1}
[root@server ~]# echo $NAME
wangxiaochun
[root@centos7 ~]#cat test.sh
#!/bin/bash
for i in {1..3};do
echo ${!i}
#eval echo $$i
done
[root@centos7 ~]#bash test.sh a b c
a b c
[root@centos8 ~]#cat create_user.sh
#!/bin/bash
#
#********************************************************************
#Author: wangxiaochun
#QQ: 29308620
#Date: 2020-12-30
#FileName: create_user.sh
#URL: http://www.wangxiaochun.com
#Description: The test script
#Copyright (C): 2020 All rights reserved
#********************************************************************
n=$#
[ $n -eq 0 ] && { echo "Usage: basename $0
username..." ; exit 2; }
for i in eval echo {1..$n}
;do
user=${!i}
id $user &> /dev/null && echo $user is exist || { useradd $user; echo $user
is created; }
done
[root@centos8 ~]#bash create_user.sh hehe xixi haha
hehe is created
xixi is created
haha is created
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了