1/81 shell shell变量 shell的变量 常量 固定的字符或字符串 不能变 所有被赋值的字符串都被称为常量 = 赋值符号 变量 值可以发生变化 y=123 变量赋值,把=右边的内容赋值到等号左边 变量名称:只能由字母、数字和下划线组成 不能以数字开头 见名知意(变量就是会变化的量) 变量的类型: 1.自定义变量 2.环境变量 3.位置变量 4.特殊变量 预定义变量 说明:shell脚本中定义变量是无需指定变量类型的。shell脚本中的变量类型有变量的值来决定。如果值是 数字,其类型自动识别成"整型";如果值用" "双引号、字母就自动识别成字符型。 C、java、数据库中常见的变量类型有整型int、浮点型float、字符型char等。 1.自定义变量 局部变量 定义变量? 变量名=变量的内容

a=80

只对当前shell生效 子shell不生效 如何引用变量?

echo $a

查看所有变量(包含自定义变量和环境变量) #set 取消变量?

unset a

完成整测试:a=80 ; echo $a ; unset a ; echo $a 2.环境变量 也称作全局(global)变量 用来指定操作系统运行环境的一些参数 在父shell里面设置的变量在他的子shell里面生效的话,说明这个变量拥有继承性,我们可以把拥有继承性 的变量称为环境变量,环境变量都可以在env查看到 2/81 查看环境变量 env 常用的环境变量(环境变量名通常用大写字母) 输出环境变量的值: echo $HOSTNAME HOSTNAME=client.qf.com //表示当前主机名 SHELL=/bin/bash //表示当前shell的类型 HISTSIZE=1000 //表示当前历史记录的条数 USER=root //表示当前登陆的用户 PWD=/root //表示当前路径 LANG=zh_CN.UTF-8 //表示当前使用的语言 HOME=/root //表示当前用户的家目录 PS1='[\u@\h \W]$ ' //表示一级提示符 PS2='> ' //表示二级提示符 UID=0 //表示当前用户的uid MAIL=/var/spool/mail/root //表示当前用户的邮箱位置 PATH=/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin 以:分 隔 存放命令的目录 表示使用命令不需要加路径使用 凡是在path路径下的命令可以在任何路径下执行

echo $RANDOM //产生0-32767的随机数

31888

echo $(($RANDOM%10)) //产生0-9的随机数

echo $(($RANDOM%100+1)) //产生0-100的随机数

练习A:采用 命令的逻辑执行功能显示当前用户的身份判断,判断,如果uid的值为0时就提示'root user', 否则提示'not root user'。脚本中要用UID这个环境变量。 [ $UID -eq 0 ] && echo 'root user.' || echo 'not root user.' 练习B:采用 命令的逻辑执行功能显示当前用户的身份判断,如果USER的值为root时就提示'root user',否 则提示'not root user'。脚本中要用USER这个环境变量。 [ $USER == "root" ] && echo 'root user.' || echo 'not root user.' PATH环境变量:作用是记录系统查找命令文件默认路径的变量。在windows、Linux中都有PATH环境变 量。当用户输入某个命令回车后,系统会自动到当前目录和PATH环境变量所设置的目录下查找这个命令文 件,如果有此命令,就执行,否则提示"未找到命令...". 例:执行如下操作,熟悉PATH环境变量的功能。 echo $PATH lsblk xxx AP=$PATH echo $AP PATH=/:/etc 临时修改PATH环境变量的值为/、/etc目录 lsblk 提示“未找到命令...” exit 重新登录,再次执行lsblk看结果。 win7/10的cmd命令行查看PATH环境变量的值: echo %PATH% 修改PATH 用:隔开 PATH=$PATH:/命令所在目录的路径 安装apache软件 3/81 apachectl 命令所在位置/usr/local/bin/apachectl 想在系统任意位置使用apachectl 两种方法 1.将/usr/local/apachectl命令拷贝到/bin PATH定义的目录下 2.设置环境变量 临时设置 1)PATH=$PATH:/usr/local/apache/bin 自定义变量 export PATH 把自定义变量转为环境变量 2)export PATH=$PATH:/usr/local/apache/bin 直接设置环境变量 永久设置 写到4个环境变量的配置文件(shell 脚本) 开机电脑自动读取配置文件内容 /etc/profile /etc/bashrc ~/.bash_profile ~/.bashrc 适用范围 /etc 对所有用户生效 ~/ 对当前用户生效 登陆shell的类型 登陆shell 4个环境变量的配置都读 敲了登陆用户名就是登陆shell 非登陆shell 只读2个bashrc文件 没有就是非登陆 例1: [root@client Desktop]# url=www.baidu.com.cn [root@client Desktop]# vim test.sh #!/bin/bash #test 自定义变量和环境变量的作用范围 echo $url echo $USER echo $UID echo $SHELL 测试: [root@client Desktop]# bash test.sh root 0/bin/bash [root@client Desktop]# . test.sh www.baidu.com.cn root 0/bin/bash 例2: [root@client Desktop]# vim test.sh #!/bin/bash #test 自定义变量和环境变量的作用范围 export url=www.baidu.com.cn echo $url echo $USER 4/81 echo $UID echo $SHELL 测试: [root@client Desktop]# bash test.sh www.baidu.com.cn root 0/bin/bash [root@client Desktop]# . test.sh www.baidu.com.cn root 0/bin/bash 3.位置变量,也称位置参数 作用:是将命令执行是输入的某个值传递到脚本内部使用,脚本内部用$1~${n}来接收这些参数。 $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11}…… 例3: [root@client Desktop]# vim test.sh #!/bin/bash echo "欢迎使用$0脚本" echo "第1个位置参数是$1" echo "第2个位置参数是$2" echo "第3个位置参数是$3" echo "第4个位置参数是$4" echo "第5个位置参数是$5" echo "第6个位置参数是$6" echo "第7个位置参数是$7" echo "第8个位置参数是$8" echo "第9个位置参数是$9" echo "第10个位置参数是${10}" echo "$0运行时的位置参数有$@" echo "$0运行时的位置参数有$" echo "$0脚本的PID是$$" echo "$0脚本运行时的位置参数共$#个" 测试: [root@client Desktop]# bash test.sh sdf qq dd ccc dsd dhjg 66 55 44 33 22 11 00 练习:编写一个名称为/sh/add_users.sh的脚本,要求用 add_users.sh tom jack lucy的方式运行脚 本,在脚本中使用位置变量$@来接收用户名tom jack lucy信息,批量创建这3个用户,并查询用户的id 信息。 vim /sh/add_users.sh 脚本内容如下 #!/bin/bash echo $@ for i in $@ do useradd $i id $i done 5/81 #以调试方式运行脚本: sh -x add_users.sh tom jack lucy 例:用read命令的-a数组选项来实现输入多个用户名,用for循环批量创建这些用户。 #!/bin/bash read -p '请输入多个用户名:' -a USERS echo "您输入了${#USERS[@]} 个用户名:${USERS[@]}" for i in ${USERS[@]} do useradd $i id $i done 4.预定义变量(必须记住) $? 上一个命令的返回值 0 正确执行 非0都是错误执行 $0 脚本名 $$ 当前进程的PID $ 所有的参数 $@ $# 参数的个数 [root@client Desktop]# echo $$ //查看当前shell的进程号 3424 影响bash shell的其他文件 bash登陆和欢迎信息(通常用于打广告) /etc/issue 登陆前显示的信息(本地登陆) ctrl alt f2 /etc/issue.net 登陆前显示的信息(网络登陆) /etc/motd 登陆后显示的信息 例0:修改本地登录前显示的信息。 [root@client Desktop]# vim /etc/issue 在文件最后添加如下内容 welcome to qf edu. 然后,到虚拟机里面的界面用exit退出登录,看登录提示界面是否多了'welcome to qf edu.'内容。 例1:修改网络登录前显示的信息。 [root@client Desktop]# vim /etc/ssh/sshd_config 在文件最后添加如下内容 Banner /etc/issue.net [root@client Desktop]# systemctl restart sshd 或 service sshd restart [root@client Desktop]# vim /etc/issue.net Red Hat Enterprise Linux Server release 7.6 (Santiago) Kernel \r on an \m fei root yonghu jinzhi denglu 添加此行内容即可 测试 [root@today ~]# ssh 192.168.11.11 Red Hat Enterprise Linux Server release 7.6(Santiago) Kernel \r on an \m fei root yonghu jinzhi denglu root@192.168.11.11's password: 6/81 例2: [root@client ~]# cat /etc/motd +-------------------------------+ | | | 你当前登陆的是网站服务器! | | 小心你的操作 | | | +-------------------------------+ 测试: [root@today ~]# ssh 192.168.11.11 root@192.168.11.11's password: Last login: Thu Apr 27 12:00:16 2017 from 192.168.11.11 +-------------------------------+ | | | 你当前登陆的是网站服务器! | | 小心你的操作 | | | +-------------------------------+ 变量的定义方式: 1.显示赋值 变量名=变量内容 示例: IPADDR=192.168.1.251 school="Hangzhou qianfeng" today=date +%F //``和$() 叫做命令替换(命令替换) [root@client ~]# today=date +%F [root@client ~]# echo $today 2017-06-08 [root@client ~]# jintian=$(date +%F) [root@client ~]# echo $jintian 2017-06-08 2.read 从键盘读入变量值 read -p "提示信息:" 变量名 [root@client ~]# read -p "请输入银行卡帐号:" num 请输入银行卡帐号:4445555666 [root@client ~]# echo $num 4445555666 [root@client ~]# read -p "请输入银行卡密码:" pass 请输入银行卡密码:111222 [root@client ~]# echo "帐号$num 密码$pass" >> /tmp/pass.txt [root@client ~]# cat /tmp/pass.txt 帐号4445555666 密码111222 -p 指定提示信息 -t 指定超时时间 默认单位:秒 -n 指定字符个数 -a 数组名 将输入的值赋给这个数组名 例1: 7/81 创建用户,提示输入用户名,依据输入的用户名去创建这个用户,创建前先判断用户是否存在,存在提示 用户已创建,不存在创建此用户,提示创建完成 #!/bin/bash read -t 30 -p "请输入你的用户名:" name useradd $name &>/dev/null && echo "用户$name创建完成" || echo "用户$name已存在" 例2: 测试本机是否能与输入的ip地址通信,能通信输出ip is up,不能通信 输出ip is down。 #!/bin/bash read -p "请输入ip地址:" ipaddress ping -c 3 $ipaddress &>/dev/null && echo "ip is up" ||echo "ip is down"

ping -c 3 192.168.1.251

-c 指定数量 ping 3次自动断开 例3: 使用read截获银行卡的账户和密码 #!/bin/bash #使用read截获银行卡的账户和密码 read -p "please input bank card account:" account stty -echo //隐藏显示 read -p "please input bank card passwd:" -n 6 -t 60 passwd stty echo //恢复正常 echo echo "account:$account passwd:$passwd" >> /tmp/bank.txt echo "account:$account passwd:$passwd" |mail -s "hello success" jim@192.168.1.250 3.变量置换 变量“内容”的删除和替换: ======“内容”的删除======== [root@client ~]# url=www.sina.com.cn [root@client ~]# echo ${#url} 获取变量值的长度 15 [root@client ~]# echo ${url} 标准查看 www.sina.com.cn [root@client ~]# echo ${url#.} 从前向后匹配,最短匹配 sina.com.cn [root@client ~]# echo ${url##.} 从前向后匹配,最长匹配 贪婪匹配(找到最后一个.) cn [root@client ~]# url=www.sina.com.cn [root@client ~]# echo ${url} www.sina.com.cn [root@client ~]# echo ${url%.} 从后向前匹配,最短匹配 www.sina.com [root@client ~]# echo ${url%%.} 从后向前匹配,最长匹配 贪婪匹配(找到最前面一个.) www ========变量的替换============== [root@client tmp]# url=www.sina.com.cn [root@client tmp]# [root@client tmp]# echo ${url/sina/baidu} www.baidu.com.cn 8/81 [root@client tmp]# echo ${url} www.sina.com.cn [root@client tmp]# echo ${url/n/N} 匹配一个替换 www.siNa.com.cn [root@client tmp]# echo ${url//n/N} 贪婪匹配 www.siNa.com.cN =======变量的替代============ ${变量名-新的变量值} 变量没有被赋值:会使用“新的变量值”替代 变量有被赋值(包括空值):不会被替代 [root@client tmp]# unset var1 [root@client tmp]# unset var2 [root@client tmp]# unset var3 [root@client tmp]# var2=111 [root@client tmp]# var3= 如果变量没有被赋值,则显示aaaa [root@client tmp]# echo ${var1-aaaa} aaaa 如果变量值有赋值,则不显示222 [root@client tmp]# echo ${var2-222} 111 如果变量值有赋值,值为空,则不显示333 [root@client tmp]# echo ${var3-333} ${变量名:-新的变量值} 变量没有被赋值(包括空值):都会使用“新的变量值”替代 变量有被赋值:不会被替代 [root@client tmp]# unset var1 [root@client tmp]# unset var2 [root@client tmp]# unset var3 [root@client tmp]# [root@client tmp]# var2= [root@client tmp]# var3=111 如果变量没有被赋值,则显示aaaa [root@client tmp]# echo ${var1:-aaaa} aaaa 如果变量有赋值,值为空,则显示aaaa [root@client tmp]# echo ${var2:-aaaa} aaaa 如果变量有赋值,则不显示aaaa [root@client tmp]# echo ${var3:-aaaa} 111 ${变量名+新的变量值} [root@client tmp]# unset var1 9/81 [root@client tmp]# unset var2 [root@client tmp]# unset var3 [root@client tmp]# var2=aaaa [root@client tmp]# var3= 如果变量没有被赋值,则不显示新的值 [root@client tmp]# echo ${var1+222} 如果变量有赋值,则显示新的值 [root@client tmp]# echo ${var2+222} 222 如果变量有赋值,值为空,则显示新的值 [root@client tmp]# echo ${var3+222} 222 ${变量名:+新的变量值} [root@client tmp]# unset var1 [root@client tmp]# unset var2 [root@client tmp]# unset var3 [root@client tmp]# [root@client tmp]# var2=aaaa [root@client tmp]# var3= 如果变量没有被赋值,则不显示新的值 [root@client tmp]# echo ${var1:+222} 如果变量有赋值,则显示新的值 [root@client tmp]# echo ${var2:+222} 222 如果变量有赋值,值为空,则不显示新的值 [root@client tmp]# echo ${var3:+222} ${变量名=新的变量值} [root@client tmp]# unset var1 [root@client tmp]# unset var2 [root@client tmp]# unset var3 [root@client tmp]# var2=aaaa [root@client tmp]# var3= 如果变量没有被赋值,则显示新的值 [root@client tmp]# echo ${var1=123} 123 如果变量有赋值,则不显示新的值 [root@client tmp]# echo ${var2=123} aaaa 如果变量有赋值,值为空,则不显示新的值 [root@client tmp]# echo ${var3=123} 10/81 ${变量名:=新的变量值} [root@client tmp]# unset var1 [root@client tmp]# unset var2 [root@client tmp]# unset var3 [root@client tmp]# var2=aaaa [root@client tmp]# var3= 如果变量没有被赋值,则显示新的值 [root@client tmp]# echo ${var1:=123} 123 如果变量有赋值,则不显示新的值 [root@client tmp]# echo ${var2:=123} aaaa 如果变量有赋值,值为空,则显示新的值 [root@client tmp]# echo ${var3:=123} 123 ${变量名:num1} ${变量名:num1:num2} PS1环境变量 默认的PS1环境变量值设置: echo $PS1 显示如下信息 PS1='[\u@\h \W]$ ' 说明:man bash 然后/PS1查找PS1关键字,大约在1555行,有如下的解释 \u 当前登录的用户名 \h 当前的主机名 #设置新的PS1环境变量值: PS1='[\u@\h \W-qf-edu]$ ' echo $PS1 显示如下信息 [root@node11 ~-qf-edu] 练习:将PS1环境变量分别设置成如下效果,看命令提示有何不同。 echo $PS1 PS1='[\u@\h \W]$ ' 系统默认提示符 PS1='[\t \u@\h \w ]$' PS1='[\t-qf_edu \u@\h \W]$ ' 11/81 提问:在百度上查如何将PS1提示符设置成彩色字。根据网上的方法测试一下。 附录: 允许通过插入一些反斜杠转义的特殊字符来定制这些提示字符串,这些字符被如下解释: \a 一个 ASCII 响铃字符 (07) \d 日期,格式是 "星期 月份 日" (例如,"Tue May 26") \D{format} format 被传递给 strftime(3),结果被插入到提示字符串中; 空的 format 将使用语言环境特定的时间格式。花括号是必需的 \e 一个 ASCII 转义字符 (033) \h 主机名,第一个 `.' 之前的部分 \H 主机名 \j shell 当前管理的作业数量 \l shell 的终端设备名的基本部分 \n 新行符 \r 回车 \s shell 的名称, $0 的基本部分 (最后一个斜杠后面的部分) \t 当前时间,采用 24小时制的 HH:MM:SS 格式 \T 当前时间,采用 12小时制的 HH:MM:SS 格式 @ 当前时间,采用 12小时制上午/下午 (am/pm) 格式 \A 当前时间,采用 24小时制上午/下午格式 \u 当前用户的用户名 the username of the current user \v bash 的版本 (例如,2.00) \V bash 的发行编号,版本号加补丁级别 (例如,2.00.0) \w 当前工作目录 \W 当前工作目录的基本部分 ! 此命令的历史编号 # 此命令的命令编号 $ 如果有效 UID 是 0,就是 #, 其他情况下是 $ \nnn 对应八进制数 nnn 的字符 \ 一个反斜杠 [ 一个不可打印字符序列的开始,可以用于在提示符中嵌入终端控制序列 ] 一个不可打印字符序列的结束 变量值的处理 3.变量置换 变量的值(即内容)删除和替换: ======“内容”的删除======== #给变量url赋上www.sina.com.cn这个值。 [root@client ~]# url=www.sina.com.cn [root@client ~]# echo $url 或 echo ${url} 标准查看(获取变量的值) www.sina.com.cn [root@client ~]# echo ${#url} 获取变量值的长度(即变量值的字符数) 15 12/81 #以下是用#号删除匹配到的关键字左侧的内容。 [root@client ~]# echo ${url#.} 从前向后匹配,最短匹配(删除操作) 想想先来后到这个词 sina.com.cn 理解:删除左边第一个点和左侧的所有内容 [root@client ~]# echo ${url##.} 从前向后匹配,最长匹配 贪婪匹配(找到最后一个.) cn 理解:删除最右侧第一个点和这个点左侧的所有内容 #以下是用%号删除匹配到的关键字右侧的内容。 [root@client ~]# url=www.sina.com.cn [root@client ~]# echo ${url} www.sina.com.cn [root@client ~]# echo ${url%.} 从后向前匹配,最短匹配 www.sina.com 理解:删除右边第一个点和右侧的所有内容 [root@client ~]# echo ${url%%.} 从后向前匹配,最长匹配 贪婪匹配(找到最前面一个.) www 理解:删除左边第一个点和这个点右侧的所有内容 练习:执行url=http://www.baidu.com:8080/music/index.html,然后完成以下操作。 1.输出变量url的值。 答:echo $url 2.输出变量url的值的长度(即字符数)是多少。 答: echo ${#url} 3.仅输出变量url值中的http关键词。 答: echo ${url%%:} 4.仅输出变量url值中的index.html关键词。 答: echo ${url##/} 5.仅输出变量url值中的域名。 答: echo ${url%:} | awk -F/ '{print $NF}' 6.仅输出变量url值中的端口号。 答: echo ${url##:} | awk -F/ '{print $1}' 附加练习: 仅输出变量url值中的域名: echo $url | awk -F: '{print $2}' |sed 's@/@@' 练习:编写一个/sh/input.sh脚本,要求提示用户输入一个完整的网址(如http://www.163.com:80/ index.php),然后分别用echo输出用户输入的这个网址,显示"协议名称是:" ,"主页是:","域名是:","端 口号是:"。 vim /sh/input.sh 基本内容如下 #!/bin/bash read -p '输入一个完整的网址(如http://www.163.com:80/index.php):' url echo "您输入的完整网址是: $url" echo "协议名称是: ${url%%:}" echo "主页是: ${url##/}" echo "域名是: $(echo $url | awk -F [:/] '{print $4}') " echo "端口号是: $(echo $url | awk -F [:/] '{print $5}') " #域名和端口号的信息可以采用如下代码实现: #d_name=$(echo $url | awk -F [:/] '{print $4}') #port=$(echo $url | awk -F [:/] '{print $5}') #echo "域名是: ${d_name} " #echo "端口号是: $port " 附加思考: 请在学习完if、test、while、正则表达式之后,对/sh/input.sh脚本做优化,优化内容是判断用户输入的 网址格式是否正确,如果正确就输出相关的信息,否则提示用户重新输入。 ========变量的替换============== [root@client tmp]# url=www.sina.com.cn.nh [root@client tmp]# echo ${url/sina/baidu} www.baidu.com.cn 13/81 [root@client tmp]# echo ${url} www.sina.com.cn [root@client tmp]# echo ${url/n/N} 匹配一个替换 www.siNa.com.cn [root@client tmp]# echo ${url//n/N} 贪婪匹配(整行替换) www.siNa.com.cN.hN 注意:以上对变量值的内容做删除、替换之后,变量的原始值是不发生改变。 例:执行如下操作。熟悉变量值的内容删除、替换等操作。 url=www.sina.com.cn.nh a=${url//n/N} b=${url##.} c=${url%%.} echo $a echo $b echo $c echo $url =======变量的替代============ 要点说明:以下是分别用-、+、=、:等符号来对变量的原始值做判断后进行修改或不修改处理。 ${变量名-新的变量值} 变量没有被赋值:会显示“新的变量值” 变量有被赋值(包括空值):显示原值,不显示新值 [root@client tmp]# unset var1 取消/删除var1这个变量 [root@client tmp]# unset var2 [root@client tmp]# unset var3 [root@client tmp]# var2=111 [root@client tmp]# var3= 如果变量没有被赋值,则显示aaaa [root@client tmp]# echo ${var1-aaaa} aaaa 附加测试:echo $var1 发现原值不变 如果变量值有赋值,则不显示222,但是显示变量的原值 [root@client tmp]# echo ${var2-222} 111 如果变量值有赋值,值为空,则不显示333,但是显示变量的原值(即空值) [root@client tmp]# echo ${var3-333} ${变量名:-新的变量值} 变量没有被赋值(包括空值):都会显示“新的变量值” 变量有被赋值:不会被替代 [root@client tmp]# unset var1 var2 var3 [root@client tmp]# var2=111 [root@client tmp]# var3= 如果变量没有被赋值,则显示aaaa [root@client tmp]# echo ${var1:-aaaa} 14/81 aaaa 附加测试:echo $var1 发现原值不变 如果变量有赋值,值为空,则显示aaaa [root@client tmp]# echo ${var2:-aaaa} 111 如果变量有赋值,就不显示aaaa [root@client tmp]# echo ${var3:-aaaa} aaaa ${变量名+新的变量值} [root@client tmp]# unset var1 var2 var3 [root@client tmp]# var2=aaaa [root@client tmp]# var3= 如果变量没有被赋值,就不显示新的值 [root@client tmp]# echo ${var1+222} 如果变量有赋值,就显示新的值 [root@client tmp]# echo ${var2+222} 222 如果变量有赋值,值为空,则显示新的值 [root@client tmp]# echo ${var3+222} 222 ${变量名:+新的变量值} [root@client tmp]# unset var1 unset var2 var3 [root@client tmp]# var2=aaaa [root@client tmp]# var3= 如果变量没有被赋值,就不显示新的值 [root@client tmp]# echo ${var1:+222} 如果变量有赋值,就显示新的值 [root@client tmp]# echo ${var2:+222} 222 如果变量有赋值,值为空,则不显示新的值 [root@client tmp]# echo ${var3:+222} ${变量名=新的变量值} [root@client tmp]# unset var1 var2 var3 [root@client tmp]# var2=aaaa [root@client tmp]# var3= 如果变量没有被赋值,就显示新的值,并且会将新值赋给这个变量。 [root@client tmp]# echo ${var1=123} 123 如果变量有赋值,则不显示新的值 15/81 [root@client tmp]# echo ${var2=123} aaaa 如果变量有赋值,值为空,则不显示新的值 [root@client tmp]# echo ${var3=123} ${变量名:=新的变量值} [root@client tmp]# unset var1 var2 var3 [root@client tmp]# var2=aaaa [root@client tmp]# var3= 如果变量没有被赋值,就显示新的值,并且会将新值赋给这个变量。(必知) [root@client tmp]# echo ${var1:=123} 123 附加测试:echo $var1 发现变量var1有了新值 如果变量有赋值,则不显示新的值 [root@client tmp]# echo ${var2:=123} aaaa 附加测试:echo $var2 发现原值不变 如果变量有赋值,值为空,就显示新的值,并且会将新值赋给这个变量。(必知) [root@client tmp]# echo ${var3:=123} 123 ${变量名:num1} ${变量名:num1:num2} 实例 练习:编写一个/sh/input.sh脚本,要求提示用户输入一个完整的网址(如http://www.163.com:80/ index.php),然后分别用echo输出用户输入的这个网址,显示"协议名称是:" ,"主页是:","域名是:","端 口号是:"。 vim /sh/input.sh 基本内容如下 #!/bin/bash read -p '输入一个完整的网址(如http://www.163.com:80/index.php):' url echo "您输入的完整网址是: $url" echo "协议名称是: ${url%%:}" echo "主页是: ${url##*/}" echo "域名是: $(echo $url | awk -F [:/] '{print $4}') " echo "端口号是: $(echo $url | awk -F [:/] '{print $5}') " #域名和端口号的信息可以采用如下代码实现: #d_name=$(echo $url | awk -F [:/] '{print $4}') 16/81 #port=$(echo $url | awk -F [:/] '{print $5}') #echo "域名是: ${d_name} " #echo "端口号是: $port " 例:编写一个/sh/var.sh脚本。要求提示用户输入一个IP地址,做判断测试(如果用户未输入ip),就提示 默认IP是192.168.11.5,否则显示默认IP是用户输入的这个IP值。 vim /sh/var.sh #!/bin/bash read -p 'please input ip address:' IP echo "默认IP是:${IP:=192.168.11.5}" 脚本常见案例(个人整理) 例如:用if的结构1做如下测试。 x=abc;y=abc;z=123 if [ $x = $y ];then echo yes fi .输入一个数字判断是奇数还是偶数 #!/bin/bash

read -p "输入一个整数:" num if [ $(($num % 2)) -eq 0 ] then echo "$num是偶数" else echo "$num是奇数" fi 例如:判断系统中是否存在root用户,如果存在就提示yes。 用命令的逻辑执行来实现,方法如下: id root && echo yes 用if语句来实现,写法如下: id root if [ $? -eq 0 ];then echo yes fi 例如:判断系统中是否存在/zk目录,如果存在就删除此目录且显示过程,否则创建此目录且显示过程 方法一:用命令的逻辑执行方法来实现的写法。 [ -d /zk ] && rm -rfv /zk || mkdir -pv /zk 方法二:用if语句实现的写法。 17/81 if [ -d /zk ];then rm -rfv /zk else mkdir -pv /zk fi 例如:判断系统中是否存在zk用户,如果存在就用userdel -r zk删除此用户,否则创建zk用户。 方法一:用命令的逻辑执行方法来实现的写法。 id zk && userdel -r zk || useradd zk 方法二:用if语句实现的写法。 if id zk;then userdel -r zk else useradd zk fi 例:编写一个名称为/sh/mk.sh的脚本,要求批量创建/test/a1~/test/a5这些目录,同时显示目录创建的执 行过程。 第1步,编写脚本文件。 vim /sh/mk.sh 脚本内容如下 #!/bin/bash #description: this is a mkdir script. for i in {1..5} do mkdir -pv /test/a$i done 例:编写一个名称为/sh/user.sh的脚本,要求批量创建用户u1~u5,并且在创建用户之后查用户的id号,并 且给每个用户设置初始登录密码为007。 第1步,编写脚本文件。 vim /sh/user.sh 脚本内容如下 #!/bin/bash #description: this is a useradd script. for i in {1..5} do useradd u$i id u$i echo 007 | passwd --stdin u$i done 第3步,对入门级的脚本进行如下优化。 1.在useradd创建用户之前,判断此用户是否存在,如果存在就提示user exsits,否则创建此用户并设置初 始登录密码为007. cp -av /sh/user.sh /sh/user-new.sh vim /sh/user-new.sh 脚本内容如下 #!/bin/bash #description: this is a useradd script. for i in {1..5} do if (id u$i);then echo "u$i user exsits." else 18/81 useradd u$i id u$i echo 007 | passwd --stdin u$i fi done 练习:在命令行中执行以下操作,实现输出10以内的正整数。 i=1 while [ $i -le 10 ] do echo $i let i++ 或 $[i++] 或 $((i++)) sleep 1s 等待1秒(停顿1秒) done

例:编写一个名称为/sh/while_user.sh的脚本,要求用while循环语句,批量创建用户w1~w5,并且在创建 用户之后查用户的id号,并且给每个用户设置初始登录密码为007。 第1步,编写脚本文件。 vim /sh/while_user.sh i=1 while [ $i -le 5 ] do useradd w$i && echo "w$i user added." || echo "w$i user exsits." id w$i echo 007 | passwd --stdin w$i let i++ sleep 1s done 思考:编写一个名称为/sh/del_users.sh的脚本,要求用while循环语句,批量查询用户w1~w5的id信息,然 后用userdel -r删除这些用户。 第1步,编写脚本文件。 vim /sh/del_user.sh i=1 while [ $i -le 5 ] do id w$i userdel -r w$i && echo "w$i user removed." || echo "w$i user not exsits." let i++ sleep 1s done 例如:写一个名称为/sh/cai.sh的脚本,要求提示用户输入数字,判断数字大小是否为520,如果是就提示 yes;如果大于520,就提示bigger;否则提示little。 第1步,编写/sh/cai.sh脚本文件。 mkdir -pv /sh vim /sh/cai.sh #!/bin/bash #description:this is crossword games. read -p 'Please input your number:' x if [ $x -eq 123 ];then echo 'you are right.' elif [ $x -gt 123 ];then echo 'you are bigger' 19/81 else echo 'you are little.' fi

while死循环(无限循环): while : do cmd_list循环体 done 例:执行如下while死循环语句,实现每隔2秒输出echo命令的中的文本内容。[按ctrl+c强制终止死循环] while : do echo 'I love you!' sleep 2s done 例:写一个名称为/sh/cai.sh的脚本,要求用while循环控制语句,当用户猜的数字错了就连续重复猜(即提示 用户"'Please input your number"),提示用户输入数字,判断数字大小是否为520,如果是就提示yes; 如果大于520,就提示bigger;否则提示little。 第1步,编写/sh/cai-2.sh脚本文件。 mkdir -pv /sh vim /sh/cai-2.sh #!/bin/bash #description:this is crossword games. x=0 while [ $x -ne 520 ] do read -p 'Please input your number:' x if [ $x -eq 520 ];then echo 'you are right.' break(猜对了退出死循环) elif [ $x -gt 520 ];then echo 'you are bigger' else echo 'you are little.' fi done until循环体退出循环 例:在命令行中执行如下操作,实现用until循环来输出1~10这些数。 i=1 until [ $i -gt 10 ] do echo $i let i++ done 将while语句的猜字游戏脚本/sh/cai-2.sh进行改写,用until语句来实现。 第1步,编写/sh/cai-3.sh脚本文件。 mkdir -pv /sh vim /sh/cai-3.sh #!/bin/bash #description:this is crossword games. x=0 20/81 until [ $x -eq 520 ] do read -p 'Please input your number:' x if [ $x -eq 520 ];then echo 'you are right.' elif [ $x -gt 520 ];then echo 'you are bigger' else echo 'you are little.' fi done 循环实例: 1.用for输出1~100的求和结果。 2.用for语句输出等腰直角三角形。 3.用for语句输出九九乘法口诀表。 例1:编写一个名称为/sh/100jia.sh的脚本,要用for进行循环控制,实现输出1+2+...+100的计算结果。 #!/bin/bash sum=0 for ((i=0;i<=100;i++)) do sum=$[i+sum] done echo $sum 例2:编写一个名称为/sh/3ja.sh的脚本,用for进行循环控制,实现在屏幕上显示一个5行由*号组成的等腰 直角三角形。 * **




解题思路:外层for循环控制三角形中星号的行数,内层for循环控制三角形中星号的列数。 #!/bin/bash for ((i=1;i<=5;i++)) do for ((j=1;j<=i;j++)) do echo -n "" done echo " " done 倒立的三角形 #!/bin/bash for ((i=1;i<=5;i++)) do for ((j=5;j>=i;j--)) do echo -n "" done echo done 循环分析:for循环中每次i、j变量的取值分析。 21/81 第一次循环: i=1 j=1 *换行 第二次循环: i=2 j=1 i=2 j=2 **换行 第二次循环: i=3 j=1 i=3 j=2 i=3 j=3 换行 第四、五次循环依次类推。 例3:编写一个名称为/sh/99.sh的脚本,用for进行循环控制,实现在屏幕上显示'九九乘法表口诀'。 1X1=1 1X2=2 2X2=4 1X3=3 2X3=6 3X3=9 …… 1X9=9 2X9=18 …… 9X9=81 #!/bin/bash for ((i=1;i<=9;i++)) do for ((j=1;j<=i;j++)) do echo -ne "${j}X${i}=$[ij]\t" done echo done case语句 例:编写一个名称为/sh/menu.sh的脚本,要求显示一个主菜单界面,提示用户输入功能选项,回车确认后 执行指定选项的命令操作。 第1步,根据项目需求,编写出脚本内容。 vim /sh/menu.sh 入门级脚本内容如下: echo '--------------------- 1/a.Install NFS Service 2/b.Install Vsftpd Service 3/c.Install Samba Service 4/d.Install DNS Service 22/81 5/e.Install Apache Service 6/f.Install PXE Service 7/g.Install DHCP Service 0/.Exit Shell Script ---------------------' read -p 'please input your choice:' opt case $opt in 1|a) echo 'Install NFS Service' . /sh/nfs-new.sh ;; 2|b) echo 'Install Vsftpd Service' . /sh/ftp-new.sh ;; 0|) echo 'Exit Shell Script' #exit 0 ;; esac 第2步,给脚本添加x可执行权限,测试脚本的运行。 chmod -v +x /sh/menu.sh . /sh/menu.sh 23/81 5.交互式脚本 需求:提示用户输入功能选项,选项1为执行clear、date、创建jack用户、设置jack密码功能;选项2为执 行clear、删除jack用户;如果输入其他字符则提示“未输入正确的功能选项,程序退出”,且自动退出脚 本。 vi case1.sh 代码内容如下 #!/bin/bash read -p "请输入功能选项数字代号,如1、2...:" choice case $choice in 1) clear date useradd jack echo jack | passwd --stdin jack ;; 2) clear id jack && userdel -r jack || echo "jack用户不存在" ;; *) echo "未输入正确的功能选项,程序退出" exit 1 esac 6.脚本中交互式实现 判断用户输入的字符串, 如果用户输入的字符串为start,就在/tmp下创建一个start文件; 如果用户输入的为stop,那么就删除/tmp/start文件; 如果用户输入的为restart,那么就先删除/tmp/start文件,然后创建一个start1文件; 如果用户输入其他的字符串,就输出一个帮助信息:脚本名 Usage:{start|stop|restart} read -p "请输入字符串:" strings case $strings in start) touch /tmp/start ;; stop) rm -rf /tmp/start ;; restart) if [ -e /tmp/start ] then rm -rf /tmp/start else touch /tmp/start1 fi ;; *) echo "$0 Usage:{start|stop|restart}" esac 1.超市卖水果 24/81 你输入苹果,显示 苹果 5元每斤 你输入香蕉 ,显示 香蕉 3元每斤 你输入橘子,显示 橘子 3元每斤 如果你输入的不是苹果 香蕉 橘子 就提示只能查询 苹果 香蕉 橘子 case语句#!/bin/bash 可以把红色的分别换成0,1,2或者apple|0),banana|1),orange|2) read -p "输入要查询价格的水果名:" aa case $aa in apple) echo "apple 5元每斤";; banana) echo "banana 3元每斤";; orange) echo "orange 3元每斤";; ) echo "Usage :{apple|banana|orange}" esac for语句#!/bin/bash num=(apple banana orange ) declare -a num read -p "please input fruits:" aa if [ $aa == ${num[0]} ];then echo "$aa 5元一斤“ elif [ $aa == ${num[1]} ];then echo "$aa 5元一斤" elif [ $aa == ${num[2]} ];then echo "$aa 2元一斤" else echo "Usage:{apple|banana|orange}" fi 最简单的×××,但是红球有可能重复 vim /sh/cp.sh 脚本内容如下 #!/bin/bash for i in {1..6} do red[$i]=$[$RANDOM%33+1] echo -ne "${red[$i]}\t" done echo echo "$[$RANDOM%16+1]" 25/81 初级脚本优化项目案例 编写脚本的思路: 1.根据目标需求分析需要用到哪些操作命令。 2.将操作的命令写入到shell脚本文件中。不考虑逻辑判断。(入门级) 3.运行和测试入门级的脚本。 4.对入门级的脚本进行优化,即添加条件判断if、循环(while、until、for)等逻辑控制语句。(高级脚本) 5.运行和测试高级的脚本。 做一个menu菜单 vim /sh/menu.sh 入门级脚本内容如下: #!/bin/bash echo '--------------------- 1/a.Install NFS Service 2/b.Install Vsftpd Service 3/c.Install Samba Service 4/d.Install DNS Service 5/e.Install Apache Service 6/f.Install PXE Service 7/g.Install DHCP Service 0/.Exit Shell Script ---------------------' _NFS(){ soft='nfs-utils rpcbind' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _Vsftpd(){ soft='vsftpd lftp ftp' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _Samba(){ soft='samba samba-comment samba-client' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _Httpd(){ soft='Httpd' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _DHCP(){ soft='dhcpd' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _PXE(){ soft='vsftpd dhcpd tftp-server ' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _firewalld(){ systemctl stop firewalld getenforce } _yum(){ [ -d /iso ] && echo '/iso is exists' || mkdir -pv /iso lsblk | grep iso && echo 'iso is mounted.' || mount /dev/cdrom /iso cd /etc/yum.repos.d [ -d bak ] && echo 'bak directory exsits.' || mkdir -pv bak mv -fv *.repo bak echo '[centos7.6] 26/81 name=centos 7.6 linux baseurl=file:///iso enabled=1 gpgcheck=0 ' >/etc/yum.repos.d/iso.repo mount /dev/sr0 /iso yum clean all yum repolist } _addusers(){ i=wl id $i && echo 'user is exists' || useradd $i } _DNS(){ soft='bind bind-utils' rpm -q $soft && echo "$soft exists" || yum -y install $soft } read -p '输入功能选项的数字编号:' i case $i in 1) _NFS ;; 2) _Vsftpd ;; 3) _Samba ;; 4) _Httpd ;; 5) _DHCP ;; 6)_PXE ;; 7)_firewalld ;; 8)_yum ;; 9)_addusers ;; 10)_DNS ;; *) echo 'input error shell.exit' ;; esac

例:编写一个名称为/sh/user.sh的脚本,要求批量创建用户u1~u5,并且在创建用户之后查用户的id号,并 且给每个用户设置初始登录密码为007。 第1步,编写脚本文件。 vim /sh/user.sh 脚本内容如下 #!/bin/bash 27/81 #description: this is a useradd script. for i in {1..5} do useradd u$i id u$i echo 007 | passwd --stdin u$i done 对入门级的脚本进行如下优化。 1.在useradd创建用户之前,判断此用户是否存在,如果存在就提示user exsits,否则创建此用户并设置初 始登录密码为007. cp -av /sh/user.sh /sh/user-new.sh vim /sh/user-new.sh 脚本内容如下 #!/bin/bash #description: this is a useradd script. for i in {1..5} do if (id u$i);then echo "u$i user exsits." else useradd u$i id u$i echo 007 | passwd --stdin u$i fi done 需求:编写一个名称为/sh/nfs.sh的脚本程序,要求实现查询NFS软件是否已安装(nfs-utils、rpcbind),全 自动安装(nfs-utils、rpcbind)文件共享服务,自动启动服务,自动以可读可写方式共享/share目录,自动本 地测试查看nfs共享资源。 首先,编写入门级的脚本。 第1步,编写nfs.sh脚本文件。 vim /sh/02.sh #!/bin/bash rpm -q nfs-utils rpcbind yum install -y nfs-utils rpcbind systemctl restart nfs rpcbind systemctl enable nfs rpcbind mkdir -pv /share chmod -v o+rwx /share echo '/share *(rw,no_root_squash)' > /etc/exports exportfs -rav showmount -e 127.0.0.1 优化后的脚本内容如下: cp -av /sh/nfs.sh /sh/nfs-new.sh vim /sh/nfs-new.sh #!/bin/bash rpm -q nfs-utils rpcbind > /dev/null && echo 'soft exsits' || yum install -y nfs-utils rpcbind systemctl status nfs | grep dead && systemctl restart nfs rpcbind || echo 'service running' read -p 'Input your share dir path (e.g. /etc):' dir_path [ -d $dir_path ] && echo 'dir exsits' || (mkdir -pv $dir_path;chmod -v o+rwx $dir_path) grep -q "$dir_path" /etc/exports && echo 'share exsits' || echo "$dir_path *(rw)" >> /etc/ exports exportfs -rav showmount -e 127.0.0.1 第4步,测试新脚本的运行。 . /sh/nfs-new.sh 28/81

需求:编写一个名称为/sh/ftp.sh的脚本程序,要求实现查询vsftpd软件是否已安装,全自动安装vsftpd文 件共享服务,自动启动服务,自动创建/var/ftp/dvd目录,将光盘(/dev/cdrom或/dev/sr0)挂载到/var/ftp/ dvd目录中,用lftp做访问vsftpd共享的内测(本地测试127.0.0.1)。 第1步,编写ftp.sh脚本文件。 vim /sh/ftp.sh #!/bin/bash rpm -q vsftpd lftp ftp yum install -y vsftpd lftp ftp systemctl restart vsftpd systemctl enable vsftpd mkdir -pv /var/ftp/dvd mount -v /dev/cdrom /var/ftp/dvd mount | grep ftp lftp 127.0.0.1 -e 'ls dvd;ls;bye' 第3步,对入门级的脚本ftp.sh做如下优化: 1.判断软件是否已安装,如果已安装就提示soft exsits,否则安装软件。 2.判断服务是否已启动,如果未启动就重启服务,否则提示service running。 3.提示用户输入共享用户账号。 4.判断输入的用户账号是否存在,如果存在就提示user exsits,否则创建此用户且给用户设置登录密码为 01。 5.用lftp命令采用此用户来访问共享,列出共享文件名列表。 cp -av /sh/ftp.sh /sh/ftp-new.sh vim /sh/ftp-new.sh 优化后的脚本内容如下: #!/bin/bash rpm -q vsftpd lftp ftp > /dev/null && echo 'soft exsits' ||yum install -y vsftpd lftp ftp systemctl status vsftpd | grep -q dead && systemctl restart vsftpd || echo 'service running' systemctl enable vsftpd mkdir -pv /var/ftp/dvd mount -v /dev/cdrom /var/ftp/dvd mount | grep ftp read -p 'Input your account name:' user_name id $user_name &> /dev/null && echo 'user exsits.' || (useradd $user_name;echo 01 | passwd --stdin $user_name) lftp 127.0.0.1 -u ${user_name},01 -e 'ls -a;bye' 第4步,测试新脚本的运行。 . /sh/ftp-new.sh

需求:编写一个名称为/sh/smb.sh的脚本程序,要求实现查询samba软件是否已安装,全自动安装samba 文件共享服务,自动启动smb服务,创建bk这个samba用户,bk的samba登陆密码为007,自动用samba以 smbrw为共享名称并且以可读可写方式共享/smb目录。做内测(即本地测试127.0.0.1)自动查看samba共享 资源。 第1步,编写smb.sh脚本文件。 vim /sh/smb.sh #!/bin/bash rpm -q samba samba-client samba-common yum install -y samba samba-client samba-common systemctl restart smb systemctl enable smb 29/81 useradd bk pdbedit bk -a pdbedit -L mkdir -pv /smb echo '[smbrw] comment=smbrw dir share path=/smb writeable=yes browseable=yes public=yes ' >> /etc/samba/smb.conf systemctl reload smb smbclient -L 127.0.0.1

需求:编写一个名称为/sh/apache.sh的脚本程序,要求实现查询httpd软件是否已安装,全自动安装 httpd、curl、elinks文件共享服务,自动启动httpd服务,/baidu/www目录,主页为/baidu/www/ index.html,自动用基于端口的虚拟主机技术用81端口发布/baidu/www目录的网站,虚拟主机配置文件 名为/etc/httpd/conf.d/baidu.conf。做网站的内测(即本地测试127.0.0.1)访问。 第1步,编写apache.sh脚本文件。 vim /sh/apache.sh #!/bin/bash rpm -q httpd httpd-manual yum install -y httpd httpd-manual curl elinks systemctl restart httpd systemctl enable httpd mkdir -pv /baidu/www echo 'www.baidu.com' > /baidu/www/index.html echo 'Listen 81 <VirtualHost :81> ServerAdmin 123@qq.com ServerName www.baidu.com DocumentRoot /baidu/www ErrorLog /var/log/httpd/www.baidu.com-err.log CustomLog /var/log/httpd/www.baidu.com-access.log common </VirtualHost> <Directory /baidu/www> AllowOverride None require all granted </Directory> ' > /etc/httpd/conf.d/baidu.conf systemctl reload httpd lsof -i:81 curl 127.0.0.1:81 ---yum 配置 需求:编写一个名称为/sh/yum.sh的脚本,要求自动将/dev/cdrom挂载到/iso目录中,移动/etc/ yum.repos.d/.repo到/etc/yum.repos.d/bak目录中,自动创建yum源配置文件/etc/yum.repos.d/ iso.repo,其中iso.repo文件中的baseurl路径指向/iso目录,自动测试yum源和仓库的可用性(yum clean all;yum repolist)。 脚本编写的思路: 1.根据需求分析要用到哪些命令。 2.将命令写到脚本文件中,得到第1版的入门级脚本文件。 3.测试入门级脚本的运行。 30/81 4.优化入门级脚本:在脚本中添加if逻辑控制语句,让脚本更具通用性,得到高级脚本。 5.测试高级脚本的运行。 vim /sh/yum.sh #!/bin/bash mkdir -pv /iso mount /dev/cdrom /iso cd /etc/yum.repos.d mkdir -pv bak mv -v *.repo bak echo '[centos7.6] name=centos 7.6 linux baseurl=file:///iso enabled=1 gpgcheck=0 ' > /etc/yum.repos.d/iso.repo yum clean all yum repolist 4.优化入门级脚本:在脚本中添加if逻辑控制语句,让脚本更具通用性,得到高级脚本。 cp -av /sh/yum.sh /sh/yum-new.sh vim /sh/yum-new.sh #!/bin/bash [ -d /iso ] && echo '/iso directory exsits.' || mkdir -pv /iso lsblk | grep iso && echo 'iso is mounted.' || mount /dev/cdrom /iso cd /etc/yum.repos.d [ -d bak ] && echo 'bak directory exsits.' || mkdir -pv bak mv -fv *.repo bak echo '[centos7.6] name=centos 7.6 linux baseurl=file:///iso enabled=1 gpgcheck=0 ' > /etc/yum.repos.d/iso.repo yum clean all yum repolist DNS域名解析自动部署脚本文件 #!/bin/bash rpm -q bind bind-utils yum -y install bind bind-utils systemctl restart named systemctl enable named sed -i 's/127.0.0.1/any/' /etc/named.conf sed -i 's/localhost/any/' /etc/named.conf systemctl restart named echo 'zone "qf.com" IN { type master; file "qf.com.zx"; allow-update { none; }; }; zone "5.168.192.in-addr.arpa" IN { type master; file "192.168.5.x"; allow-update { none; }; };' >/etc/named.rfc1912.zones named-checkconf cp -av /var/named/named.localhost /var/named/qf.com.zx 31/81 cp -av /var/named/named.loopback /var/named/192.168.5.x echo '$TTL 1D @ IN SOA qf.com. rname.invalid. ( 0 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum NS @ A 127.0.0.1 AAAA ::1 NS qf.com. dns A 192.168.11.11 www A 1.1.1.1 ftp A 1.1.1.2 http A 1.1.1.3 web CNAME www.qf.com.' >/var/named/qf.com.zx echo '$TTL 1D @ IN SOA dns.qf.com. rname.invalid. ( 0 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum NS @ A 127.0.0.1 AAAA ::1 PTR localhost. NS dns.qf.com. dns A 192.168.11.11 1 PTR www.qf.com. 2 PTR http.qf.com. 3 PTR ftp.qf.com.' >/var/named/192.168.5.x systemctl restart named nslookup www.qf.com 192.168.11.11 nslookup http.qf.com 192.168.11.11 nslookup ftp.qf.com 192.168.11.11 nslookup 192.168.5.1 192.168.11.11 nslookup 192.168.5.3 192.168.11.11 nslookup 192.168.5.2 192.168.11.11 32/81 优化DNS脚本 #!/bin/bash rpm -q bind bind-utils && echo 'soft is exists' || yum -y install bind bind-utils systemctl status named | grep dead && (systemctl restart named && systemctl enable named) || echo 'service is running' [ -d /etc/named.conf ] && sed -i 's/127.0.0.1/any/' /etc/named.conf [ -d /etc/named.conf ] && sed -i 's/localhost/any/' /etc/named.conf systemctl restart named [ -d /etc/named.rfc.1912.zones ] && echo 'zone "qf.com" IN { type master; file "qf.com.zx"; allow-update { none; }; };' >/etc/named.rfc.1912.zones cd /var/named [ -d named.localhost ] && mkdir -pv qf.com.zx [ -d qf.com.zx ] && echo '$TTL 1D @ IN SOA qf.com. rname.invalid. ( 33/81 0 ; serial 1D ; refresh 1H ; retry 1W ; expire 3H ) ; minimum NS @ A 127.0.0.1 AAAA ::1 NS qf.com. dns A 192.168.11.11 www A 1.1.1.1 ftp A 1.1.1.2 http A 1.1.1.3 web CNAME www.qf.com.' >/var/named/qf.com.zx systemctl restart named nslookup www.qf.com 192.168.11.11 nslookup http.qf.com 192.168.11.11 nslookup ftp.qf.com 192.168.11.11 34/81 作业 1.打印圣诞树 *










1 #!/bin/bash 2 # 3 for ((i=1;i<=4;i++)) 4 do 5 for ((j=4;j>=i;j--)) 6 do 7 echo -n " " 8 done 9 for ((k=1;k<=2i-1;k++)) 10 do 11 echo -n "" 12 done 13 echo 14 done 15 16 for ((a=1;a<=3;a++)) 17 do 18 for ((b=3;b>=a;b--)) 19 do 20 echo -n " " 21 done 22 for ((c=1;c<=2a+1;c++)) 23 do 24 echo -n "" 25 done 26 echo 27 done 28 29 for ((f=1;f<=3;f++)) 30 do 31 for ((d=1;d<=3;d++)) 32 do 33 echo -n " " 34 done 35 for e in {1..3} 36 do 37 echo -n "*" 38 done 39 echo 40 done 35/81












1 #!/bin/bash 2 for ((a=1;a<=4;a++)) 3 do 4 for b in {1,2} 5 do 6 echo -n " " 7 done 8 for ((c=4;c>=a;c--)) 9 do 10 echo -n " " 11 done 12 for ((d=1;d<=a;d++)) 13 do 14 echo -n "" 15 done 16 for ((e=2;e<=a;e++)) 17 do 18 echo -n "" 19 done 20 echo 21 done 22 23 for ((f=1;f<=5;f++)) 24 do 25 for ((g=5;g>=f;g--)) 26 do 27 echo -n " " 28 done 29 for ((h=1;h<=f;h++)) 30 do 31 echo -n "" 32 done 33 for i in 1 34 do 35 echo -n "" 36 done 37 for ((j=1;j<=f;j++)) 38 do 39 echo -n "" 40 done 41 echo 42 done 43 44 for ((k=1;k<=3;k++)) 36/81 45 do 46 for l in {1..5} 47 do 48 echo -n " " 49 done 50 for m in {1..3} 51 do 52 echo -n "" 53 done 54 echo 55 done 1 #!/bin/bash 2 # 3 for ((i=1;i<=4;i++)) 4 do 5 for ((j=6;j>=i;j--)) 6 do 7 echo -n " " 8 done 9 for ((k=1;k<=2i-1;k++)) 10 do 11 echo -n "" 12 done 13 echo 14 done 15 16 for ((a=1;a<=5;a++)) 17 do 18 for ((b=5;b>=a;b--)) 19 do 20 echo -n " " 21 done 22 for ((c=1;c<=2a+1;c++)) 23 do 24 echo -n "" 25 done 26 echo 27 done 28 29 for ((f=1;f<=3;f++)) 30 do 31 for ((d=1;d<=5;d++)) 32 do 33 echo -n " " 34 done 35 for e in {1..3} 36 do 37 echo -n "*" 38 done 39 echo 40 done

2.计算器不输入退出就一直等待输入数字进行计算 1 #!/bin/bash 2 # 37/81 3 while read -p "请输入计算的内容:" num 4 do 5 if [[ -z $num || $num == exit ]] 6 then 7 exit 8 else 9 a=$(($num)) 10 echo $a 11 fi 12 done 1 #!/bin/bash 2 # 3 while read -p "请输入计算的内容:" num 4 do 5 num=${num:=exit} 6 if [[ $num == exit ]] 7 then 8 exit 9 else 10 a=$(($num)) 11 echo $a 12 fi 13 done 3.写一个脚本,显示如下菜单给用户: while cpu)print cpu information; disk) print disk information; mem)print memory information; quit)quit; Pleas enter your option: 根据用户输入的显示相应的信息,如果用户输入的不是以上几种就显示帮助信息,帮助信息为“Pleas enter your option:<cpu|disk|mem|quit>” 该脚本中用户的选择不区分大小写

  1. 编写脚本,计算1+2+3+4...100的和 while until 1 a=0 2 i=0 3 while [ $i -le 100 ] 4 do 5 a=$(($a+$i)) 6 let i++ 7 done 8 echo $a

1 a=0 2 i=0 3 until [ $i -gt 100 ] 4 do 5 a=$(($a+$i)) 6 let i++ 7 done 8 echo $a

38/81 1.编写脚本,如果: 根分区剩余空间小于20% 向用户root发送警告邮件,邮件的内容包含使用率相关信息 #!/bin/bash

gsyl=df -h | head -2 |tail -1 | tr -s " " | cut -d " " -f 5 | cut -d "%" -f 1 re=$((100-$gsyl)) if [ $re -lt 20 ] then echo "警告:根分区剩余空间为$re%" > /tmp/disk.txt mail -s "警告信息" root@192.168.1.251 < "/tmp/disk.txt" fi 2.输入一个数字判断是奇数还是偶数 #!/bin/bash

read -p "输入一个整数:" num if [ $(($num % 2)) -eq 0 ] then echo "$num是偶数" else echo "$num是奇数" fi 3.编写脚本,计算1+2+3+4...100的和 1 #!/bin/bash 2 # 3 num=0 4 for i in {1..100} 5 do 6 num=$(($num+$i)) 7 done 8 echo $num 4.输入两个数,求和、差、商、积、余。必须使用$1 $2 1 #!/bin/bash 2 # 3 echo "两个数的和是:echo $(($1+$2))" 4 echo "两个数的差是:echo $(($1-$2))" 5 echo "两个数的商是:echo $(($1/$2))" 6 echo "两个数的积是:echo $(($1*$2))" 7 echo "两个数的余是:echo $(($1%$2))" 5.打印下列图形


39/81




1 #!/bin/bash 2 for i in {1..4} 3 do 4 for j in {1..5} 5 do 6 echo -n "" 7 done 8 echo " " 9 done 1 #!/bin/bash 2 for ((i=1;i<=4;i++)) 3 do 4 for ((j=1;j<=5;j++)) 5 do 6 echo -n "" 7 done 8 echo " " 9 done 1 read -p "输入行数:" line 2 read -p "输入多少个*:" xing 3 for ((i=1;i<=$line;i++)) 4 do 5 for ((j=1;j<=$xing;j++)) 6 do 7 echo -n "*" 8 done 9 echo " " 10 done 6. * **






1 for ((i=1;i<=7;i++)) 2 do 3 for ((j=1;j<=i;j++)) 4 do 5 echo -n "" 6 done 7 echo " " 8 done 1 read -p "输入行数:" line 2 for ((i=1;i<=$line;i++)) 40/81 3 do 4 for ((j=1;j<=i;j++)) 5 do 6 echo -n "" 7 done 8 echo " " 9 done 7.





1 #!/bin/bash 2 for ((i=1;i<=4;i++)) 3 do 4 for ((r=4;r>=i;r--)) 5 do 6 echo -n "a" 7 done 8 for ((f=1;f<=i;f++)) 9 do 10 echo -n "" 11 done 12 for m in seq 2 $i 13 do 14 echo -n "" 15 done 16 17 echo 18 done 1 #!/bin/bash 2 for ((i=1;i<=4;i++)) 3 do 4 for ((j=4;j>=i;j--)) 5 do 6 echo -n " " 7 done 8 for ((k=1;k<=2i-1;k++)) 9 do 10 echo -n "" 11 done 12 echo 13 done 41/81 1 #!/bin/bash 2 read -p "输入行数:" num 3 for ((i=1;i<=$num;i++)) 4 do 5 for ((j=$num;j>=i;j--)) 6 do 7 echo -n " " 8 done 9 for ((k=1;k<=2i-1;k++)) 10 do 11 echo -n "" 12 done 13 echo 14 done 7./test目录下有100个文件 统一给这些文件改名,格式为:a.bak 1 #!/bin/bash 2 for i in ls /test 3 do 4 mv /test/$i /test/$i.bak 5 done 8./test目录下有a.bak aa.bak C.b.bak等以.bak结尾的文件,将这些文件有.bak改名为.txt 1 for i in ls /test/*.bak 2 do 3 mv $i ${i%.*}.txt 4 done

9.输入J计算1..100内所有奇数相加之和,输入O计算1..100内所有偶数相加之和 1 read -p "请输入J或者O:" num 2 a=0 3 num=$(echo $num | tr "a-z" "A-Z" ) 4 if [ "$num" == "J" ] 5 then 6 for i in seq 1 2 100 7 do 8 a=$(($a+$i)) 9 done 10 echo $a 11 elif [ "$num" == "O" ] 12 then 13 for i in seq 2 2 100 14 do 15 a=$(($a+$i)) 16 done 17 echo $a 18 else 19 echo "Usage:<J|O>" 20 fi

1 read -p "请输入J或者O:" num 2 a=0 3 case $num in 4 J |j) 42/81 5 for i in seq 1 2 100 6 do 7 a=$(($a+$i)) 8 done 9 echo $a 10 ;; 11 O |o) 12 for i in seq 2 2 100 13 do 14 a=$(($a+$i)) 15 done 16 echo $a 17 ;; 18 *) 19 echo "Usage:<J|O>" 10.写一个脚本,使用case和函数现实,能够对/etc/目录进行打包,打包后存储到/backup目录下并命名为 etc_年-月-日.bak的格式 显示如下菜单给用户: xz) xz compress gzip) gzip compress bzip2) bzip2 compress 根据用户指定的压缩工具使用tar进行打包压缩,输入错误就提示给用户一个帮助信息,帮助信息为“脚本 名 Usage:<xz|gzip|bzip2>” 1 #!/bin/bash 2 # 3 echo "压缩方式有以下三种:" 4 echo -e "\txz)xz compress" 5 echo -e "\tgzip) gzip compress" 6 echo -e "\tbzip2) bzip2 compress" 7 8 name=etc_date +%F.bak.tar 9 xz() { 10 tar cJf /backup/$name.xz /etc &>/dev/null 11 echo "/etc目录使用xz方式归档压缩成功" 12 } 13 14 gzip() { 15 tar czf /backup/$name.gz /etc &>/dev/null 16 echo "/etc目录使用gzip方式归档压缩成功" 17 } 18 19 bzip2() { 20 tar cjf /backup/$name.bz2 /etc &>/dev/null 21 echo "/etc目录使用bzip2方式归档压缩成功" 22 } 23 24 if [ -e /backup ] 25 then 26 if [ ! -d /backup ] 27 then 28 mv /backup /backup.bak 29 mkdir /backup 30 fi 43/81 31 else 32 mkdir /backup 33 fi 34 35 read -p "请输入压缩的方式:" ys 36 case $ys in 37 xz) 38 xz 39 ;; 40 gzip) 41 gzip 42 ;; 43 bzip2) 44 bzip2 45 ;; 46 *) 47 echo "$0 Usage:<xz|gzip|bzip2>" 48 esac 11.写一个脚本,显示如下菜单给用户: cpu)print cpu information; disk) print disk information; mem)print memory information; quit)quit; Pleas enter your option: 根据用户输入的显示相应的信息,如果用户输入的不是以上几种就显示帮助信息,帮助信息为“Pleas enter your option:<cpu|disk|mem|quit>” 1 #!/bin/bash 2 echo "可以查询的系统信息如下" 3 echo -e "\tcpu)print cpu information;" 4 echo -e "\tdisk) print disk information;" 5 echo -e "\tmem)print memory information;" 6 echo -e "\tquit)quit;" 7 8 read -p "Pleas enter your option:" ss 9 case $ss in 10 cpu) 11 cat /proc/cpuinfo 12 ;; 13 disk) 14 df -h 15 ;; 16 mem) 17 cat /proc/meminfo 18 ;; 19 quit) 20 echo "byebye" 21 ;; 22 *) 23 echo "Pleas enter your option:<cpu|disk|mem| quit>" 24 esac 1 #!/bin/bash 2 echo "可以查询的系统信息如下" 3 echo -e "\tcpu)print cpu information;" 44/81 4 echo -e "\tdisk) print disk information;" 5 echo -e "\tmem)print memory information;" 6 echo -e "\tquit)quit;" 7 8 for ((i=1;i>0;i++)) 9 do 10 read -p "Pleas enter your option:" ss 11 ss=echo $ss | tr "A-Z" "a-z" (将大写改为小写) 12 case $ss in 13 cpu) 14 cat /proc/cpuinfo 15 ;; 16 disk) 17 df -h 18 ;; 19 mem) 20 cat /proc/meminfo 21 ;; 22 quit) 23 exit 0 24 ;; 25 *) 26 echo "Pleas enter your option:<cpu|disk|mem| quit>" 27 esac 28 done shell脚本 shell学习目标 1.shell的特性 2.shell变量 3.shell条件测试 4.shell数值运算 5.流程、循环 6.正则表达式 7.sed 8.awk

cat ~/.vimrc

45/81 set nu set ts=4 set ic set ci set si set sw=4

shell脚本(script): shell脚本文件:是一种linux操作命令的集合文件。用户运行脚本文件时就会自动执行文件中的命令。

入门级(初级)脚本:脚本文件中仅包含一些操作命令,无任何逻辑判断语句。这种脚本只会按从上到下的 顺序来执行命令,如果某行命令错误会自动跳过。 高级脚本:在入门级脚本的基础上加入条件判断if、循环(for、while、until)等逻辑控制语句,让脚本更具 有通用性和可移植性。 如何提高自己的脚本编写水平:经常到网上去看一些别人写的脚本,从中取经。

计算机语言分类: 解释型语言:语法没有很严格的要求,也称为弱语言(语法要求弱)。通常有shell脚本、html网页语言、 python语言、java script、VBscript、PHP、bat批处理(Windows脚本)等。脚本程序用notepad记事本、 vi/vim、notepad++等纯文本文件编辑软件来编写即可。 编译型的语言:语法要求很严格,也称为强语言。通常有C、C++、C#、Visual Basic、java、delphi等。编 译型的语言编写的源程序代码需要通过编译成计算机能够识别的二进制文件才能够运行。例如系统中的ls、 date、lsblk等命令都是用c语言编写,然后编译成命令文件,所以我们才能直接运行这个命令。这种程序的 运行效率高。 shell脚本的运行的过程:调用脚本文件中的命令--〉shell命令解释器--〉kernel内核--〉hardware 硬件 高级语言的程序运行过程:二进制程序文件--〉kernel内核--〉hardware硬件 实例:编写一个入门级的脚本文件01.sh,要实现的功能是执行clear echo QQ:12700696、cd、ls、pwd、sleep 5s、date、lsblk命令。给01.sh添加x可执行权限,运行 01.sh脚本程序。 第1步,编写01.sh脚本文件。 mkdir /sh vim /sh/01.sh 文件内容如下 #!/bin/bash #date:2019-02-18 #Author By : jim #Decription: this is my first shell script. clear echo QQ:12700696 cd ls pwd sleep 5s date lsblk 46/81 第2步,添加可执行权限,运行脚本。 chmod -v +x /sh/01.sh . /sh/01.sh 或 source /sh/01.sh 或 /sh/01.sh 或 sh /sh/01.sh 或 bash /sh/01.sh 运行脚本并显示脚本的执行过程:sh -x /sh/01.sh 技巧: shell脚本学习的帮助文档:man bash 练习:执行如下操作,来学习bash帮助文档的使用。 man bash 分别执行如下操作,分别查看这些关键字代码的内容帮助 /if /while /until /test /&& test shell的条件测试 格式1:test 条件表达式 格式2:[ 条件表达式 ] 格式3:[[ 条件表达式 ]] 支持正则表达式 && || 给x变量赋值为1314520:x=1314520 显示变量的值:echo $x 变量:变量是用来存储某个具体的值的,值可以是数值、任意字符。程序中用变量可以让程序变得更灵 活。 查上一条命令结果的状态码:echo $? 说明:$?是系统的预定义变量,是用来存上一条命令的状态码的变量。 状态码: 成功为0 失败为非0 47/81 练习:执行如下操作,了解命令结果的状态码的值。 date echo $? xxxxx echo $? ls /kkkk echo $? date stx echo $? 条件判断的组合: -a -o -n && 逻辑与 -a 条件表达式1 && 条件表达式2 条件表达式1 -a 条件表达式2 || 逻辑或 -o 条件表达式1 || 条件表达式2 条件表达式1 -o 条件表达式2

! 非,取反 ! 条件表达式 -n 条件表达式 ==文件测试=== 根据文件类型判断 -e 判断文件是存在 例: [root@client tmp]# test -e /tmp [root@client tmp]# echo $? 存在 状态返回值为0 0[root@client tmp]# test -e /tmpdahs 不存在 状态返回值为1 [root@client tmp]# echo $? 1 -e 判断文件名是存在 -d 判断文件是存在且是为目录文件 -f 判断文件是存在且是为普通文件 -p 判断文件是存在且是为管道文件 -b 判断文件是存在且是为块设备文件 -c 判断文件是存在且是为字符设备文件 -L 判断文件是存在且是为软链接文件 -S 判断文件是存在且是为套接字文件 根据文件权限判断 -r 判断文件是存在且是有“可读权限” -w 判断文件是存在且是有“可写权限” 48/81 -x 判断文件是存在且是有“可执行权限”

[root@client tmp]# test -r a.a.pdf 有读权限 状态返回值为0 [root@client tmp]# echo $? 0[root@client tmp]# test -x a.a.pdf 无执行权限 状态返回值非0 [root@client tmp]# echo $? 1 文件内容非空白的判断 -s 判断文件是存在且文件内容非空白 [root@client tmp]# test -s /etc/passwd [root@client tmp]# echo $? 非空,有内容 状态返回值为0 0[root@client tmp]# test -s a.pdf 为空 状态返回值非0 [root@client tmp]# echo $? 1 ==数值比较=== -gt 大于 -lt 小于 -eq 等于 -ge 大于等于 -le 小于等于 -ne 不等 [root@client tmp]# test 5 -gt 3 5大于3 结果为真 状态返回码为0 [root@client tmp]# echo $? 0[root@client tmp]# test 3 -gt 3 3大于3 结果为假 状态返回码为非0 [root@client tmp]# echo $? 1 [root@client tmp]# A=5 [root@client tmp]# B=3 [root@client tmp]# test $A -gt $B [root@client tmp]# echo $? 0[root@client tmp]# test $B -gt $A [root@client tmp]# echo $? 1 ==字符串比较== 字符串一定要用引号引起来 == 等值比较 = 等值比较 [root@client tmp]# A=hello [root@client tmp]# test $A == hello 结果为真 返回值0 [root@client tmp]# echo $? 0[root@client tmp]# test $A == hell0 结果为假 返回值非0 [root@client tmp]# echo $? 1 49/81 != 不等值比较 [root@client tmp]# A=hello [root@client tmp]# test $A != hello 结果为假 返回值非0 [root@client tmp]# echo $? 1 [root@client tmp]# test $A != hell0 结果为真 返回值0 [root@client tmp]# echo $? 0=~ 判断左侧字符串或者变量是否符合右侧的模式 -z 判断字符串是空 [root@client tmp]# unset A [root@client tmp]# unset B [root@client tmp]# A=8 [root@client tmp]# test -z $A 结果为假 返回值非0 [root@client tmp]# echo $? 1 [root@client tmp]# test -z $B 结果为真 返回值0 [root@client tmp]# echo $?

命令的逻辑执行 命令1 && 命令2 当命令1执行成功时会执行命令2 命令1 || 命令2 当命令1执行失败时会执行命令2 例: [ -d /etc ] && echo 目录已存在 || echo 目录不存在 [ -d /etck ] && echo 目录已存在 || echo 目录不存在 if语句 if条件语句: 3种结构: if结构1:单条件,单分支。如果满足if后面的条件1(即条件的结果状态码为真[即为0]),就执行then后面的 语句。 if 条件1;then command命令1 command命令2 fi if语句的简写如下(命令的逻辑与执行): 命令1 && 命令2 等同于 if 条件1;then 命令列表;fi 50/81 例如:用if的结构1做如下测试。 x=abc;y=abc;z=123 if [ $x = $y ];then echo yes fi if语句的简写如下: [ $x = $y ] && echo yes 例如:判断系统中是否存在root用户,如果存在就提示yes。 用命令的逻辑执行来实现,方法如下: id root && echo yes 用if语句来实现,写法如下: id root if [ $? -eq 0 ];then echo yes fi if结构2:单条件,双分支。如果满足if后面的条件1(即条件的结果状态码为真[即为0]),就执行then后面的 语句,否则执行else后面的语句。 if 条件1;then command命令1 command命令2 else command命令3 command命令4 fi if双分支的简写: 命令1 && 命令2 || 命令3 解释:命令1执行成功(状态码为0),就执行命令2,否则执行命令3. 例如:用if的结构2做如下测试。 x=abc;y=abc;z=123 if [ $x = $y ];then echo yes else echo no fi if语句的简写如下: [ $x = $y ] && echo yes || echo no 例如:判断系统中是否存在/zk目录,如果存在就删除此目录且显示过程,否则创建此目录且显示过程 方法一:用命令的逻辑执行方法来实现的写法。 [ -d /zk ] && rm -rfv /zk || mkdir -pv /zk 方法二:用if语句实现的写法。 if [ -d /zk ];then rm -rfv /zk else mkdir -pv /zk fi 51/81 例如:判断系统中是否存在zk用户,如果存在就用userdel -r zk删除此用户,否则创建zk用户。 方法一:用命令的逻辑执行方法来实现的写法。 id zk && userdel -r zk || useradd zk 方法二:用if语句实现的写法。 if id zk;then userdel -r zk else useradd zk fi if结构3:多条件,双分支。如果满足if后面的条件1(即条件的结果状态码为真[即为0]),就执行then后面的 语句;否则测试elif后的条件2,满足条件2就执行elif的then后面的语句;否则执行else后面的语句。 if 条件1;then command命令1 command命令2 elif 条件2;then command命令3 command命令4 else command命令5 command命令6 fi 例如:用if的结构3做如下测试。做猜数字游戏。 x=123 if [ $x -eq 123 ];then echo 'you are right.' elif [ $x -gt 123 ];then echo 'you are bigger' else echo 'you are little.' fi 例如:写一个名称为/sh/cai.sh的脚本,要求提示用户输入数字,判断数字大小是否为520,如果是就提示 yes;如果大于520,就提示bigger;否则提示little。 第1步,编写/sh/cai.sh脚本文件。 mkdir -pv /sh vim /sh/cai.sh #!/bin/bash #description:this is crossword games. read -p 'Please input your number:' x if [ $x -eq 123 ];then echo 'you are right.' elif [ $x -gt 123 ];then echo 'you are bigger' else echo 'you are little.' fi 第2步,添加x可执行权限,测试脚本的运行。 chmod -v +x /sh/cai.sh . /sh/cai.sh 52/81 shell test及案例 bash shell的帮助手册:man bash -gt大于 -ge大于或等于 -eq等于 -lt小于 -le小于或等于 -ne不等于 test 条件 语句 或 [ 条件 ] 功能:用来判断文件、权限、值(数值是否相等、是否为空)。 帮助手册:man test test练习: 项目一:字符串的长度、值的判断测试。 练习:判断字符串长度为0则为真(true,状态码为0) [root@node11 ~]# x='' [root@node11 ~]# test -z $x [root@node11 ~]# echo $? 0练习:判断字符串长度不为0则为真(true,状态码为0) [root@node11 ~]# x=1234 [root@node11 ~]# test -n $x [root@node11 ~]# echo $? 0练习:判断字符串内容相等为真(true,状态码为0) [root@node11 ~]# test abc = abc [root@node11 ~]# echo $? 0[root@node11 ~]# test abc = abcde [root@node11 ~]# echo $? 1 练习:判断字符串内容不相等为真(true,状态码为0) [root@node11 ~]# test abc != abcde [root@node11 ~]# echo $? 0项目二:整数值的大小(相等eq、不相等ne、大于gt、小于lt、大于或等于ge、小于或等于le)判断测试。 练习:执行如下操作,熟悉整数值的大小判断测试。 x=1314 y=520 z=520 test $x -eq $y echo $? test $z -eq $y echo $? test $x -ne $y 53/81 echo $? test $x -gt $y echo $? test $x -lt $y echo $? test $z -lt $x 520 < 1314 echo $? test $x -ge $y 1314 >= 520 echo $? test $z -ge $y 520 >= 520 echo $? test $y -le $x 520 <= 1314 echo $? test $y -le $z 520 <= 520 echo $? 项目三:文件类型(目录d、普通文件-、字符设备c、块设备b、软链接l、管道p、套接字s)、文件大小(大小 为0、不为0)、文件的新旧、权限(ugo、rwx、facl、3种s权限等)的判断测试。 [ -d /etc ] echo $? [ -f /etc/hosts ] echo $? [ -c /dev/tty ] echo $? [ -b /dev/sda ] echo $? [ -L /etc/rc.local ] echo $? find / -type p 在根目录及其子目录中查找类型为管道的文件 [ -p /run/dmeventd-client ] echo $? find / -type s [ -S /run/systemd/notify ] echo $? 文件权限:判断当前用户对文件是否有可读、可写、可执行权限。-r、 -w、 -x useradd ak su - ak pwd touch a1 chmod -v 0 a1 [ -r a1 ] ; echo $? chmod -v u+r a1 [ -r a1 ] ; echo $? [ -w a1 ] ; echo $? [ -x a1 ] ; echo $? touch a2 [ -t 1 ] ; echo $? 文件描述符(FD,文件在内存中的数字代号)已在终端打开了 [ -t 168 ] ; echo $? 54/81 exit 复合条件判断测试:逻辑非、逻辑与、逻辑或 [ ! abc = abcde ] ; echo $? 逻辑非 [ abc = abc -a 123 -eq 123 ] ; echo $? 逻辑与,同时满足两个条件就为真(状态码为0) [ abc = abcd -o 123 -eq 123 ] ; echo $? 逻辑或,满足其中一个条件就为真(状态码为0)

引号 单引号:单引号中的所有字符均作为普通字符处理(即原样输出),即无法调用变量的值。 双引号:双引号中会自动识别特殊字符,即自动识别调用变量的值,如$、\n换行符、\t tab键、\r回车符 等特殊字符。 例:执行如下操作,理解单引号、双引号的区别。 x=123abc 分别看以下命令输出的结果有什么不同 echo $x echo '$x' echo "$x" echo -e '${x}\n_welcome\t_linux' echo -e "${x}\n_welcome\t_linux" 说明:echo 的-e 选项是允许识别\n换行符、\t tab键、\r回车符特殊字符。

说明:${x}通常等同于$x,那么什么时候需要将变量名用{}大括号括起来呢? 答:当变量名后面紧贴着其他字符时,为了避免歧义,就需要将变量名用{}大括号括起来。 例:执行如下操作,分别看输出结果有何不同。以此来理解变量名为何需要用{}大括号括起来。 x=123abc xy=456 echo $x echo $xy echo $xy_haha 跟下一条命令对比结果 echo ${xy}haha 跟上一条命令对比结果 echo $x$xy 跟下一条命令对比结果 echo ${x}_$xy 跟上一条命令对比结果 echo ${x}y 循环语句 for语句 55/81 for语句: 功能:在满足条件的情况下,重复执行某些命令操作。 for语句结构: for i in 值1 值2 ... 值n do 命令列表 done 例:编写一个名称为/sh/mk.sh的脚本,要求批量创建/test/a1~/test/a5这些目录,同时显示目录创建的执 行过程。 第1步,编写脚本文件。 vim /sh/mk.sh 脚本内容如下 #!/bin/bash #description: this is a mkdir script. for i in {1..5} do mkdir -pv /test/a$i done 第2步,给脚本添加x可执行权限,测试脚本的运行。 chmod -v +x /sh/mk.sh . /sh/mk.sh 例:编写一个名称为/sh/user.sh的脚本,要求批量创建用户u1~u5,并且在创建用户之后查用户的id号,并 且给每个用户设置初始登录密码为007。 第1步,编写脚本文件。 vim /sh/user.sh 脚本内容如下 #!/bin/bash #description: this is a useradd script. for i in {1..5} do useradd u$i id u$i echo 007 | passwd --stdin u$i done 第2步,给脚本添加x可执行权限,测试脚本的运行。 chmod -v +x /sh/user.sh . /sh/user.sh 第3步,对入门级的脚本进行如下优化。 1.在useradd创建用户之前,判断此用户是否存在,如果存在就提示user exsits,否则创建此用户并设置初 始登录密码为007. cp -av /sh/user.sh /sh/user-new.sh vim /sh/user-new.sh 脚本内容如下 #!/bin/bash #description: this is a useradd script. for i in {1..5} do if (id u$i);then echo "u$i user exsits." else 56/81 useradd u$i id u$i echo 007 | passwd --stdin u$i fi done 第4步,测试新脚本的运行。 . /sh/user-new.sh while语句 while功能:whatis while,得到的官方解释“在条件满足时重复的执行脚本中while的do和done之间的循 环体命令”。 简单解释:当满足条件时,就进入循环。 while语法: while 条件测试 do cmd_list循环体 done =======当条件测试成立(条件测试为真),执行循环体 符合条件将一直循环 直到不符合条件(条件测试为假)停止循环 练习:在命令行中执行以下操作,实现输出10以内的正整数。 i=1 while [ $i -le 10 ] do echo $i let i++ 或 $[i++] 或 $((i++)) sleep 1s 等待1秒(停顿1秒) done

例:编写一个名称为/sh/while_user.sh的脚本,要求用while循环语句,批量创建用户w1~w5,并且在创建 用户之后查用户的id号,并且给每个用户设置初始登录密码为007。 第1步,编写脚本文件。 vim /sh/while_user.sh i=1 while [ $i -le 5 ] do useradd w$i && echo "w$i user added." || echo "w$i user exsits." id w$i echo 007 | passwd --stdin w$i let i++ sleep 1s done 第2步,给脚本添加x可执行权限,测试脚本的运行。 chmod -v +x /sh/while_user.sh . /sh/while_user.sh 57/81 思考:编写一个名称为/sh/del_users.sh的脚本,要求用while循环语句,批量查询用户w1~w5的id信息,然 后用userdel -r删除这些用户。 第1步,编写脚本文件。 vim /sh/del_user.sh i=1 while [ $i -le 5 ] do id w$i userdel -r w$i && echo "w$i user removed." || echo "w$i user not exsits." let i++ sleep 1s done 第2步,给脚本添加x可执行权限,测试脚本的运行。 chmod -v +x /sh/del_user.sh . /sh/del_user.sh

while死循环(无限循环): while : do cmd_list循环体 done 例:执行如下while死循环语句,实现每隔2秒输出echo命令的中的文本内容。[按ctrl+c强制终止死循环] while : do echo 'I love you!' sleep 2s done

例:写一个名称为/sh/cai.sh的脚本,要求用while循环控制语句,当用户猜的数字错了就连续重复猜(即提示 用户"'Please input your number"),提示用户输入数字,判断数字大小是否为520,如果是就提示yes; 如果大于520,就提示bigger;否则提示little。 第1步,编写/sh/cai-2.sh脚本文件。 mkdir -pv /sh vim /sh/cai-2.sh #!/bin/bash #description:this is crossword games. x=0 while [ $x -ne 520 ] do read -p 'Please input your number:' x if [ $x -eq 520 ];then echo 'you are right.' elif [ $x -gt 520 ];then echo 'you are bigger' else echo 'you are little.' fi done 第2步,添加x可执行权限,测试脚本的运行。 58/81 chmod -v +x /sh/cai-2.sh . /sh/cai-2.sh until until功能:直到条件满足时,就停止循环。 语法: until 条件测试 do 循环体 done =======当条件测试成立(条件测试为假),执行循环体 不符合条件将一直循环 直到符合条件(条件测试为真)停止循环 例:在命令行中执行如下操作,实现用until循环来输出1~10这些数。 i=1 until [ $i -gt 10 ] do echo $i let i++ done 思考:将while语句的猜字游戏脚本/sh/cai-2.sh进行改写,用until语句来实现。 第1步,编写/sh/cai-3.sh脚本文件。 mkdir -pv /sh vim /sh/cai-3.sh #!/bin/bash #description:this is crossword games. x=0 until [ $x -eq 520 ] do read -p 'Please input your number:' x if [ $x -eq 520 ];then echo 'you are right.' elif [ $x -gt 520 ];then echo 'you are bigger' else echo 'you are little.' fi done 第2步,添加x可执行权限,测试脚本的运行。 chmod -v +x /sh/cai-3.sh . /sh/cai-3.sh 59/81 循环实例 循环实例: 1.用for输出1~100的求和结果。 2.用for语句输出等腰直角三角形。 3.用for语句输出九九乘法口诀表。 4.用for语句实现批量创建用户、查用户id号、设置用户初始密码。 例1:编写一个名称为/sh/100jia.sh的脚本,要用for进行循环控制,实现输出1+2+...+100的计算结果。 echo '#!/bin/bash sum=0 for ((i=0;i<=100;i++)) do sum=$[i+sum] done echo $sum ' > /sh/100jia.sh chmod -v +x /sh/100jia.sh . /sh/100jia.sh 例3:编写一个名称为/sh/3ja.sh的脚本,用for进行循环控制,实现在屏幕上显示一个5行由*号组成的等腰 直角三角形。 * **




解题思路:外层for循环控制三角形中星号的行数,内层for循环控制三角形中星号的列数。 echo '#!/bin/bash for ((i=1;i<=5;i++)) do for ((j=5;j>=i;j--)) do echo -n "*" done echo done ' > /sh/3ja.sh chmod -v +x /sh/3ja.sh . /sh/3ja.sh 循环分析:for循环中每次i、j变量的取值分析。 第一次循环: 60/81 i=1 j=1 *换行 第二次循环: i=2 j=1 i=2 j=2 **换行 第二次循环: i=3 j=1 i=3 j=2 i=3 j=3 **换行 第四、五次循环依次类推。 例4:编写一个名称为/sh/3jb.sh的脚本,用for进行循环控制,实现在屏幕上显示一个5行由号组成的等腰 直角三角形。




** * echo '#!/bin/bash for ((i=1;i<=5;i++)) do for ((j=5;j>=i;j--)) do echo -n "" done echo done ' > /sh/3jb.sh chmod -v +x /sh/3jb.sh . /sh/3jb.sh 例4:编写一个名称为/sh/99.sh的脚本,用for进行循环控制,实现在屏幕上显示'九九乘法表口诀'。 1X1=1 1X2=2 2X2=4 1X3=3 2X3=6 3X3=9 …… 61/81 1X9=9 2X9=18 …… 9X9=81 echo '#!/bin/bash for ((i=1;i<=9;i++)) do for ((j=1;j<=i;j++)) do echo -ne "${j}X${i}=$[ij]\t" done echo done ' > /sh/99.sh chmod -v +x /sh/99.sh . /sh/99.sh case语句 case功能:根据变量的取值不同,执行不同的命令操作。 case语句结构: read -p 'please input your choice:' 变量名 case $变量名 in 值1) 命令1 命令2 ;; 值2) 命令3 命令4 ;; ) 命令5 命令6 ;; esac 例:编写一个名称为/sh/menu.sh的脚本,要求显示一个主菜单界面,提示用户输入功能选项,回车确认后 执行指定选项的命令操作。 第1步,根据项目需求,编写出脚本内容。 vim /sh/menu.sh 入门级脚本内容如下: echo '--------------------- 62/81 1/a.Install NFS Service 2/b.Install Vsftpd Service 3/c.Install Samba Service 4/d.Install DNS Service 5/e.Install Apache Service 6/f.Install PXE Service 7/g.Install DHCP Service 0/.Exit Shell Script ---------------------' read -p 'please input your choice:' opt case $opt in 1|a) echo 'Install NFS Service' . /sh/nfs-new.sh ;; 2|b) echo 'Install Vsftpd Service' . /sh/ftp-new.sh ;; 0|*) echo 'Exit Shell Script' #exit 0 ;; esac 第2步,给脚本添加x可执行权限,测试脚本的运行。 chmod -v +x /sh/menu.sh . /sh/menu.sh 63/81 模式匹配case 功能:根据用户输入的功能选项,执行对应功能选项的任务。 case的语法结构 case 变量 in 模式1) 命令序列1 ;; 模式2) 命令序列2 ;; 模式3) 命令序列3 ;; *) 无匹配后的命令序列 esac 5.交互式脚本 需求:提示用户输入功能选项,选项1为执行clear、date、创建jack用户、设置jack密码功能;选项2为执 行clear、删除jack用户;如果输入其他字符则提示“未输入正确的功能选项,程序退出”,且自动退出脚 本。 64/81 vi case1.sh 代码内容如下 #!/bin/bash read -p "请输入功能选项数字代号,如1、2...:" choice case $choice in 1) clear date useradd jack echo jack | passwd --stdin jack ;; 2) clear id jack && userdel -r jack || echo "jack用户不存在" ;; *) echo "未输入正确的功能选项,程序退出" exit 1 esac 6.脚本中交互式实现 判断用户输入的字符串, 如果用户输入的字符串为start,就在/tmp下创建一个start文件; 如果用户输入的为stop,那么就删除/tmp/start文件; 如果用户输入的为restart,那么就先删除/tmp/start文件,然后创建一个start1文件; 如果用户输入其他的字符串,就输出一个帮助信息:脚本名 Usage:{start|stop|restart} read -p "请输入字符串:" strings case $strings in start) touch /tmp/start ;; stop) rm -rf /tmp/start ;; restart) if [ -e /tmp/start ] then rm -rf /tmp/start else touch /tmp/start1 fi ;; *) echo "$0 Usage:{start|stop|restart}" esac 1.超市卖水果 你输入苹果,显示 苹果 5元每斤 你输入香蕉 ,显示 香蕉 3元每斤 你输入橘子,显示 橘子 3元每斤 如果你输入的不是苹果 香蕉 橘子 就提示只能查询 苹果 香蕉 橘子 #!/bin/bash 可以把红色的分别换成0,1,2或者apple|0),banana|1),orange|2) read -p "输入要查询价格的水果名:" aa 65/81 case $aa in apple) echo "apple 5元每斤";; banana) echo "banana 3元每斤";; orange) echo "orange 3元每斤";; *) echo "Usage :{apple|banana|orange}" esac 11.写一个脚本,显示如下菜单给用户: cpu)print cpu information; disk) print disk information; mem)print memory information; quit)quit; Pleas enter your option: 根据用户输入的显示相应的信息,如果用户输入的不是以上几种就显示帮助信息,帮助信息为“Pleas enter your option:<cpu|disk|mem|quit>” 1 #!/bin/bash 2 echo "可以查询的系统信息如下" 3 echo -e "\tcpu)print cpu information;" 4 echo -e "\tdisk) print disk information;" 5 echo -e "\tmem)print memory information;" 6 echo -e "\tquit)quit;" 7 8 read -p "Pleas enter your option:" ss 9 case $ss in 10 cpu) 11 cat /proc/cpuinfo 12 ;; 13 disk) 14 df -h 15 ;; 16 mem) 17 cat /proc/meminfo 18 ;; 19 quit) 20 echo "byebye" 21 ;; 22 *) 23 echo "Pleas enter your option:<cpu|disk|mem| quit>" 24 esac 66/81 技术回顾 test 检测、判断命令 test作用:检测文件类型和比较值。 检测文件类型: -e FILE 文件名存在就为真 -f FILE 文件名存在且为普通文件就为真 -d FILE 文件名存在且为目录就为真 -b FILE 文件名存在且为block块设备文件就为真 -S FILE 文件名存在且为Socket套接字文件就为真 -L FILE 文件名存在且为symbolic link 符号链接(即快捷方式)文件就为真 -c FILE 文件名存在且为char字符设备文件就为真 -p FILE 文件名存在且为pipe管道文件就为真 检测文件权限: -r FILE 当前用户对此文件可读就为真 -w FILE 当前用户对此文件可写就为真 -x FILE 当前用户对此文件可执行就为真 文件新旧检测: FILE1 -ef FILE2 文件1和文件2有相同的设备和inode索引号就为真 FILE1 -nt FILE2 文件1的mtime新于(newer than)文件2就为真 FILE1 -ot FILE2 文件1的mtime旧于(older than)文件2就为真 逻辑与、或、非: ! EXPRESSION 非,EXPRESSION表达式的值(状态码)取反,状态码0的取反值为1 EXPRESSION1 -a EXPRESSION2 逻辑与,-a左右两边表达式的值都为真就为真 EXPRESSION1 -o EXPRESSION2 逻辑或,-o左右两边表达式的值一个为真就为真 字符串检测: string1 = string2 字符串内容相同就为真(状态码为0) string1 != string2 字符串内容不相同就为真(状态码为0) -z string1 字符串长度为0就为真(状态码为0) -n string1 字符串长度不为0就为真(状态码为0) 整数检测: int1 -eq int2 相等(equal) int1 -ne int2 不相等(no equal) int1 -gt int2 大于(greater than) int1 -ge int2 大于或等于(greater or equal than) int1 -lt int2 小于(less than) int1 -le int2 小于或等于(less or equal than)

if语句: 结构1:if单分支 if 条件;then cmd_list 67/81 fi 结构2:if双分支 if 条件;then cmd_list1 else cmd_list2 fi 结构3:if多分支 if 条件1;then cmd_list1 elif 条件2;then cmd_list2 else cmd_list3 fi

for循环语句: for结构1:shell脚本专用的语法结构 for i in value1 value2 value3 do cmd_list echo $i done 例:l为矩形的长,其值固定为2,i为矩形的宽,其值为2~6,用for循环来计算矩形的面积s,输出s的值。 方法一:用$[公式]来实现计算。 l=2 for i in 2 3 4 5 6; do s=$[li]; echo $s; done 方法一:用$((公式))来实现计算。 l=2 for i in 2 3 4 5 6; do s=$((li)); echo $s; done

for结构2:C语言和shell脚本通用的语法结构 for ((i=0;i<=6;i++)) 说明:i++是i=i+1的简写,i=i+2可写成i+=2 do cmd_list echo $i done 函数 函数

完成特定功能的代码段(块) 68/81 在shell中定义函数可以使用代码模块化,便于复用(即重复使用)代码 函数必须先定义才可以使用 一、定义函数 方法一: 函数名() { 函数要实现的功能代码 } 方法二: function 函数名 { 函数要实现的功能代码 } a=789 [root@node11 ~]# function a {

echo $a } a 例:查看functions、network服务的控制脚本文件内容,其中就有函数。 cat -n /etc/rc.d/init.d/functions | more cat -n /etc/rc.d/init.d/network | more 二、函数的调用 函数名 1.函数外的参数能被函数调用 #!/bin/bash a=123 num_1() { echo $a } num_1 2.函数内的参数也能被函数调用 #!/bin/bash num_2() { a=456 } num_2 echo $a 3.使用local来隔离变量, 使参数只能在函数内调用 vim /sh/f.sh #!/bin/bash a=love num_3() { local a=789 echo "in num_3" echo $a 69/81 } num_3 echo "out of num_3" echo $a [root@today tmp]# bash /sh/f.sh in num_3 789 out of num_3 love


项目案例:以下是centos 6系统的服务管理(start启动、stop停止、restart重启、reload平滑重启、status 状态)脚本的基本框架参考代码。 #!/bin/bash

start() { touch /tmp/start } stop() { rm -rf /tmp/start } read -p "请输入字符串:" strings if [ $strings == "start" ] then start elif [ $strings == "stop" ] then stop elif [ $strings == "restart" ] then stop start else echo "$0 Usage:{start|stop|restart}" fi 作业 练习:编写一个名称为/sh/admin.sh的脚本,要求综合实现如下功能: 1.clear清屏,显示'admin menu'功能菜单。admin menu菜单内容如下: -----admin menu-----

  1. install NFS
  2. install Vsftpd
  3. Install Samba
  4. Install httpd
  5. Install DHCP 70/81
  6. Install PXE
  7. Stop Firewalld and Selinux
  8. Configuration Local Yum
  9. add Users
  10. Install DNS

2.提示用户"输入功能选项的数字编号"。 3.用case语句取判断用户输入的功能选项,来执行功能选项所对应的操作命令。 4.需要将admin menu菜单中的每个功能定义成函数,在case语句中调用不同的函数。 vim /sh/admin.sh 脚本内容如下 #!/bin/bash echo '-----admin menu----- 1.install NFS 2.install Vsftpd 3.install Samba 4.install Httpd 5.install DHCP 6.install PXE 7.Stop Firewalls and Selinux 8.Configuration Local Yum 9.add Users 10.Instsall DNS -----------------------' _NFS(){ soft='nfs-utils rpcbind' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _Vsftpd(){ soft='vsftpd lftp ftp' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _Samba(){ soft='samba samba-comment samba-client' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _Httpd(){ soft='Httpd' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _DHCP(){ soft='dhcpd' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _PXE(){ soft='vsftpd dhcpd tftp-server ' rpm -q $soft && echo "$soft exists" || yum -y install $soft } _firewalld(){ systemctl stop firewalld getenforce } _yum(){ [ -d /iso ] && echo '/iso is exists' || mkdir -pv /iso lsblk | grep iso && echo 'iso is mounted.' || mount /dev/cdrom /iso cd /etc/yum.repos.d [ -d bak ] && echo 'bak directory exsits.' || mkdir -pv bak 71/81 mv -fv *.repo bak echo '[centos7.6] name=centos 7.6 linux baseurl=file:///iso enabled=1 gpgcheck=0 ' >/etc/yum.repos.d/iso.repo yum clean all yum repolist } _addusers(){ i=wl id $i && echo 'user is exists' || useradd $i } _DNS(){ soft='bind bind-utils' rpm -q $soft && echo "$soft exists" || yum -y install $soft } read -p '输入功能选项的数字编号:' i case $i in 1) _NFS ;; 2) _Vsftpd ;; 3) _Samba ;; 4) _Httpd ;; 5) _DHCP ;; 6)_PXE ;; 7)_firewalld ;; 8)_yum ;; 9)_addusers ;; 10)_DNS ;; *) echo 'input error shell.exit' ;; esac 算术运算 72/81 1.整数运算 方法一:expr

expr 1 + 2

3 [root@client tmp]# A=156 [root@client tmp]# B=456 [root@client tmp]# expr $A + $B 612 +

* / % 取模(取余数),取除法运算后的余数。例:expr 7 % 2 方法二:$(()) + - * / % [root@client tmp]# echo $((6*9)) 54 [root@client tmp]# echo $(((9-6)9)) 27 [root@client tmp]# echo $((31%2)) 1 [root@client tmp]# sum=$((69));echo $sum 54 方法三:$[] + - * / % [root@client tmp]# echo $[456+789] 1245 方法四:let let [root@client tmp]# let num2=9+25 ;echo $num2 34 说明:let命令中,要想输出表达式的计算结果,必须把表达的结果赋值给一个变量,然后用echo 输出这 个变量的值。 Linux计算器:

bc //交互式操作

9/2 4 scale=2 //指定精度,精度就是小数点后保留几位小数 9/2 4.50 ctrl d 退出 非交互式操作 [root@client tmp]# echo "0.36+356" | bc 356.36 [root@client tmp]# echo "scale=6;10/3" |bc 3.333333 进制之间的转换 73/81 [root@client tmp]# echo "ibase=2;11111111" | bc //将二进制数转成十进制数 255 [root@client tmp]# echo "ibase=10;obase=16;11" | bc //将十进制数转成16进制数 B 说明:十六进制数由0~9、A~F这十六个元素组成。 [root@client tmp]# echo "ibase=10;obase=2;255" | bc /将十进制数转成二进制数 11111111 附录:2的幂 2的幂: 10 9 8 7 6 5 4 3 2 1 0 十进制: 1024 512 256 128 64 32 16 8 4 2 1

数组 数值: 赋值100个变量,这样要起100个变量名,数组的话使用1个名称就可以了,后跟100个值,在访 问值的时候要使用下标的方式

声明: declare -a 数组名 声明变量为数组类型 declare -i 变量名 声明变量为整数数字类型 [root@client tmp]# num=6+5 [root@client tmp]# echo $num 6+5 [root@client tmp]# declare -i num=6+5 [root@client tmp]# echo $num 11

declare -x 变量名 声明变量为环境变量 用法和export一样 declare -r 变量名 声明变量为readonly类型,只读类型,变量的内容不可改

declare -a array

declare -a array1

定义数组: 变量值称为数组的元数 方法一:一次赋一个值 数组名[下标]=值

array[0]=apple

array[1]=orange

array[2]=banana

方法二:一次赋多个值 数组名=(值1 值2 值3 ...)

array1=(tom jim jack)

查看数组 74/81

declare -a |grep arr

declare -a array='([0]="apple" [1]="orange" [2]="banana")' declare -a array1='([0]="tom" [1]="jim" [2]="jack")'

访问数组元数:

echo ${array[0]} 访问数组中的第一个元数

apple

echo ${array[*]} 访问数组中的所有元数 数组的遍历

echo ${array[@]}

echo ${#array[@]} 统计数组元数的个数

echo ${#array[*]}

echo ${!array[@]} 获取数组元数的索引

0 1 2

echo ${array[@]:1} 从数组下标1开始

orange banana

echo ${array[@]:1:2} 从数组下标1开始,访问2个元数

orange banana

declare -a | grep name

declare -a name='([0]="user1" [1]="user2" [2]="user3" [3]="user4" [4]="user5" [5]="user6")' [root@client ~]# echo ${name[@]} user1 user2 user3 user4 user5 user6 [root@client ~]# echo ${name[@]:1} user2 user3 user4 user5 user6 [root@client ~]# echo ${name[@]:3} user4 user5 user6 [root@client ~]# echo ${name[@]:2:3} user3 user4 user5 取消数组 #unset 数组名

echo ${name[@]}

user1 user2 user3 user4 user5 user6

for i in ${name[@]};do echo $i ;done

user1 user2 user3 user4 user5 user6 1.超市卖水果 你输入苹果,显示 苹果 5元每斤 你输入香蕉 ,显示 香蕉 3元每斤 你输入橘子,显示 橘子 3元每斤 如果你输入的不是苹果 香蕉 橘子 就提示只能查询 苹果 香蕉 橘子 vim /sh/fruit.sh 脚本内容如下: #!/bin/bash declare -a num num=(apple banana orange) read -p "输入要查询价格的水果名:" aa if [ $aa == ${num[0]} ] ; then 75/81 echo "$aa 5元一斤" elif [ $aa == ${num[1]} ] ; then echo "$aa 3元一斤" elif [ $aa == ${num[2]} ] ; then echo "$aa 3元一斤" else echo "Usage :{apple|banana|orange}" fi case语句 #!/bin/bash declare -a num num=(apple banana orange) read -p "input your fruits:" aa case $aa in 0) echo "apple 5元一斤" ;; 1) echo "banana 3元一斤" ;; 2) echo "orange 2元一斤" ;; *) echo "usage:{apple|banana|orange}" ;; esac ~ 例子:双色球××× red红球: 33选6 blue蓝球: 16选1

echo $RANDOM 输出一个随机数

echo $[$RANDOM%33+1]

echo $[$RANDOM%16+1]

最简单的×××,但是红球有可能重复 vim /sh/cp.sh 脚本内容如下 #!/bin/bash for i in {1..6} do red[$i]=$[$RANDOM%33+1] echo -ne "${red[$i]}\t" done echo echo "$[$RANDOM%16+1]" 如何去除红球的重复? i=1 while [ $i -le 6 ] do redtmp=$[$RANDOM%33+1] flag="yes" for j in ${red[*]} 76/81 do if [ $j -eq $redtmp ] then flag="no" break fi done if [ $flag = "yes" ] then red[$i]=$redtmp let i++ fi done for i in {1..6} do echo -n "${red[i]} " done echo echo "$[$RANDOM%16+1]"

正则表达式 正则表达式(正确的规则表达式):是用来做关键字匹配的。它是一种字符模式,是在匹配文本时,使用一 些特殊的符号,匹配用户想要的东西 正则表达式、通配符的区别:应用场合不同 通配符:是用在查找文件名时或?或[关键字]来匹配文件名中不确定的字符。ls /dev/tty[135]? 正则表达式:是用在查看文件内容时^、$、+、、?、[]、.等符号来匹配文件内容中不确定的字符。 字符模式: 普通字符:没有特殊含义的字符 a b c 元字符:具有特殊含义的字符 ^ $ * . [] shell元字符:* 通配符 由shell来解析,Shell将*解析为任意多个字符 正则表达式元字符: * 前导符 由各种执行模式匹配操作的程序来解析,比如vim(查找和替换)、 grep、egrep、sed、awk

何时用? 能够使用正则表达式的命令:vim(查找和替换)、grep、sed、awk 匹配数字:^[0-9]+$ 例:echo -e '123\n456\n7s9' | egrep '^[0-9]+$' 输出结果:123 456 匹配Mail:[a-z0-9]+@[a-z0-9]+.[a-z]+ 数字和字母@数字和字母.com xiaoming123@163.com 例:echo -e '12@qq.com\nfly@163.com\n58.com' | egrep '[a-z0-9]+@[a-z0-9]+.[a-z]+' 匹配ip地址:[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3} 例:1.2.3.4 77/81 [0-9] [0-9][0-9] [0-9][0-9][0-9] 例: echo -e '192.168.11.11\n172.16.5.3\na.b.c.d\n127.0.0.1' | egrep '[0-9]{1,3}.[0-9]{1,3}. [0-9]{1,3}.[0-9]{1,3}'

例:编写一个名称为/sh/zhz.sh的脚本,要求提示用户输入一个数字,判断用户输入的是否是数字,如果是 就提示'yes',否则提示'no'。 vim /sh/zhz.sh #!/bin/bash read -p 'input a number:' x echo $x | egrep -q '^[0-9]+$' if [ $? -eq 0 ];then echo 'yes' else echo 'no' fi

[root@client ~]# grep "abc*" /etc/passwd --color abrt:x:173:173::/etc/abrt:/sbin/nologin [root@client ~]# grep "roo*" /etc/passwd --color root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin rtkit:x:499:497:RealtimeKit:/proc:/sbin/nologin 基本正则表达式元字符 元字符 功能 例子 匹配结果 字符的匹配 . 匹配任意单个字符 /l.ve/ 匹配love、live... [] 匹配一组字符中的任意一个 /l[Oo]ve/ 匹配love、lOve [x-z] 表示匹配一段范围中的任意一个 /l[a-c]ve/ 匹配lave、lbve、lcve "^[a-Z0-9]+" 大小写字母或数字 [0-9] 数字 [a-z] 小写字母 [A-Z] 大写字母 [0-9a-z] 小写字母或数字 [^] 表示取反 /[^a-c]ove/ 匹配除了aove、bove、 cove以外的字符 次数的匹配 * 前导符(即号左边的字符) 匹配号左边的字符0个或多个 /lve/ 匹配 ve、lve、llve、lllllllllve... x{m} 匹配x出现m次。 x是字符或字符串,m是一个数字 /a{3}/ 匹配到aaa x{m,} 匹配x出现至少m次 /a{2,}/ 匹配到aa、aaa、aaaa... x{m,n} 匹配x出现m次到n次 /a{2,4}/ 匹配到aa、aaa、aaaa x{0,n} 匹配x出现最多n次 /a{0,3}/ 匹配到a、aa、aaa 位置的定位 ^ 行首定位符 /^root/ 匹配以root开头的行 $ 行尾定位符 /bash$/ 匹配以bash结尾的行 < 词首定位符 /<love/ 匹配到lovely、lover等.例:echo -e 'lovely \nalove\nlover' | grep '<love' > 词尾定位符 /love>/ 匹配到inlove等 .例:echo -e 'klove\inalove \nlover' | grep 'love>' \b /love\b/ 78/81 \ 用来转义(将字符在普通意义和特殊意义之间转换)元字符 /2.5/ 匹 配2.5 分组 (..) 将括号内的内容作为一个单位来看(并且在内存中会用1~n记录这些值),内容 可以是字串也可以是一个模式 (love)\1er 匹配loveloveer # 引用前面第#个“(”和与之对应的“)”中的模式所匹配到的内容,#至少为1 (ab)(ac)(dd) abacddacddab (ab)(ac)(dd).*\2\3\1 abacddjjjacddab

:1,$ s/(192.168.1).20/\1.50/g 将.20替换成.50 :3,9 s/(.*)/#\1/ 匹配任意一个字符开头加上# :%s/172.16.1.1/172.16.1.5/ 将172.16.1.1替换成172.16.1.5 :% s/(172.16.1.)1/\15/ 172.16.1. :% s/(172.)(16.)(1.)1/\1\2\35/g 172.16.1.1 172.16.1.5

正则表达式的组合: .* :任意字符任意次 匹配0到多个任意字符 ^$:匹配空白行 扩展正则表达式元字符 元字符 功能 例子 匹配结果 ? 表示0个或1个它前面的字符 a?d ad d aad

  • 表示1个或多个它前面的字符 a+d ad d aad aaad... | 或者 a|b a b aa () (..)(..)\1\2 x{m} 前置字符x出现了m次 x{m,} x{m,n} x{0,n} \d 匹配0~9数字(digital) ???????? POSIX字符集 表达式 功能 示例 例子 等同于 [:alnum:] 字母和数字 [[:alnum:]]+ [a-Z0~9] [:alpha:] 字母(包括大小写字母) [[:alpha:]]{4} [:lower:] 小写字母 [:upper:] 大写字母 [:digit:] 数字 [[:digit:]]? [:blank:] 空格和制表符 [[:blank:]]* [:punct:] 标点符号 [:space:] 包括换行符,回车等所有空白 grep 基本正则表达式 grep -E 或 egrep 支持扩展表达式 例: ip a | egrep '[[:alpha:]]' echo -e 'aaa\naaaaaa\naaaa\nccc\ncccc' | egrep '[[:alpha:]]{4}' 79/81 grep执行状态的返回值三种 0 :该文件中搜索到匹配行 1 :该文件中没有搜索到匹配行 2 :搜索文件不存在 思考练习: 1.如果输入小写字母,提示输入的是小写字母 如果输入大写字母,提示输入的是大写字母 如果输入的是数字,提示输入的是数字 如果输入的是其他内容,提示只能输入字母数字空白 vim /sh/char.sh 参考内容如下 #!/bin/bash read -p 'input your char:' x if echo "$x" | egrep -wq '[[:lower:]]' ;then echo 'lower word.' elif echo "$x" | egrep -wq '[[:upper:]]' ;then echo 'upper word.' elif echo "$x" | egrep -wq '[[:digit:]]*' ;then echo 'number word.' else echo 'only input word 、 number、blank.' fi 2.使用ifconfig命令查找ip地址,使用正则表达式只显示ip地址 1~254.1~254.1~254.1~254 1-9 10-99 100-199 200-249 250-254

grep "<[1-9]>|<[1-9][0-9]>|<1[0-9][0-9]>|<2[0-4][0-9]>|25[0-4]" --color /tmp/

num1.txt

grep "<[1-9][0-9]{0,1}>|<1[0-9]{2}>|<2[0-4][0-9]>|25[0-4]" --color /tmp/

num1.txt

作业

  1. 把每个数字用()括起来 :%s/([0-9])/(\1)/g :%s/([[:digit:]])/(\1)/g 80/81
  2. 匹配ip每个十进制数的范围是1~255

grep -E "<([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-4])>" /tmp/aa.txt

  1. for ping测试指定网段的主机 网段由用户输入,例如用户输入192.168.1,则ping 192.168.1.1~192.168.1.20 ping通的主机将主机的ip地址保存在/tmp/host_up.txt UP:/tmp/host_up.txt ping不通的主机将主机的ip地址保存在/tmp/host_down.txt Down:/tmp/host_down.txt vim /sh/ping.sh #!/bin/bash

/tmp/host_up.txt /tmp/host_down.txt read -p "请输入一个网段:" wd for ((i=1;i<=20;i++)) do ( ping -c 2 -W 1 "$wd".$i > /dev/null if [ $? -eq 0 ];then echo "${wd}.${i} up" | tee -a /tmp/host_up.txt else echo "${wd}.${i} down"| tee -a /tmp/host_down.txt fi )& done 4.匹配用户名是三个字符的用户 :^[^:][^:][^:]>

grep "^[^:][^:][^:]>" /tmp/test

5.删除每行的倒数第二个字符 :%s/(.)(.)$/\2/ 6.搜索包含2个o的行 o+.*o+ 7.显示/boot/grub/grub.conf中至少一个空白字符开头的行

grep "^[[:space:]]{1,}" /boot/grub/grub.conf

grep "^[[:space:]]+" /boot/grub/grub.conf

8.显示/etc/rc.d/rc.sysinit文件中,以#开头,后面跟至少一个空白字符,而后又有至少一个非空白字符的 行

grep "^#[[:space:]]{1,}[^[:space:]]{1,}" /etc/rc.d/rc.sysinit

grep "^#[[:space:]]+[^[:space:]]+" /etc/rc.d/rc.sysinit

egrep "^#[[:space:]]+[^[:space:]]+" /etc/rc.d/rc.sysinit

81/81