目录
[1. Vim文本编辑器](#1. Vim文本编辑器)
[1.1 编写简单文档](#1.1 编写简单文档)
[1.2 配置主机名称](#1.2 配置主机名称)
[1.3 配置网卡信息](#1.3 配置网卡信息)
[1.4 配置软件仓库](#1.4 配置软件仓库)
[2. 编写Shell脚本](#2. 编写Shell脚本)
[2.1 编写简单的脚本](#2.1 编写简单的脚本)
[2.2 接收用户的参数](#2.2 接收用户的参数)
[2.3 判断用户的参数](#2.3 判断用户的参数)
[3. 流程控制语句](#3. 流程控制语句)
[3.1 if条件测试语句](#3.1 if条件测试语句)
[3.2 for条件循环语句](#3.2 for条件循环语句)
[3.3 while条件循环语句](#3.3 while条件循环语句)
[3.4 case条件测试语句](#3.4 case条件测试语句)
[4. 计划任务服务程序](#4. 计划任务服务程序)
前言
悟已往之不谏,知来者之可追。实迷途其未远,觉今是而昨非。舟遥遥以轻飏,风飘飘而吹衣。问征夫以前路,恨晨光之熹微。
本系列依照《Linux就该这么学》第二版随书学习练习操作,将一些课本上不顺畅的地方,全部以最简方式免费开源展示给大家,资源大家可以自行百度,学习起来我们既要多巴胺也要内啡肽。
我们继续开垦,万稳万当,不如一默,分内事分内做,少应承多沉默,博观而约取,厚积而薄发,这次咱们憋个大的。莫文蔚的阴天,周杰伦的晴天,都不如你爱学习的每一天,送上一首天王的<周杰伦-晴天>,希望生活中的每天都是元气满满的一天,本章网络血难调,找了好多答案,习惯了centos7的网络配置了,不太喜欢没有netwoke,不过配置好了还是一样用。
1. Vim文本编辑器
在Linux系统中一切都是文件,而配置一个服务就是在修改其配置文件的参数,Vim编辑器中设置了3种模式---命令模式、末行模式和编辑模式,每种模式分别又支持多种不同的命令快捷键。
命令模式:控制光标移动,可对文本进行复制、粘贴、删除和查找等工作。
输入模式:正常的文本录入。
末行模式:保存或退出文档,以及设置编辑环境。
在每次运行Vim编辑器时,默认进入命令模式,此时需要先切换到输入模式后再进行文档编写工作。而每次在编写完文档后需要先返回命令模式,然后再进入末行模式,执行文档的保存或退出操作。在Vim中,无法直接从输入模式切换到末行模式。
命令模式中最常用命令
|-----|-----------------------------|
| 命令 | 作用 |
| dd | 删除(剪切)光标所在整行 |
| 5dd | 删除(剪切)从光标处开始的5行 |
| yy | 复制光标所在整行 |
| 5yy | 复制从光标处开始的5行 |
| n | 显示搜索命令定位到的下一个字符串 |
| N | 显示搜索命令定位到的上一个字符串 |
| u | 撤销上一步的操作 |
| p | 将之前删除(dd)或复制(yy)过的数据粘贴到光标后面 |
末行模式主要用于保存或退出文件,以及设置Vim编辑器的工作环境,还可以让用户执行外部的Linux命令或跳转到所编写文档的特定行数。要想切换到末行模式,在命令模式中输入冒号
末行模式中最常用命令
|---------------|-----------------------|
| 命令 | 作用 |
| :w | 保存 |
| :q | 退出 |
| :q! | 强制退出(放弃对文档的修改内容) |
| :wq! | 强制保存退出 |
| :set nu | 显示行号 |
| :set nonu | 不显示行号 |
| :命令 | 执行该命令 |
| :整数 | 跳转到该行 |
| :s/one/two | 将当前光标所在行的第一个one替换成two |
| :s/one/two/g | 将当前光标所在行的所有one替换成two |
| :%s/one/two/g | 将全文中的所有one替换成two |
| ?字符串 | 在文本中从下至上搜索该字符串 |
| /字符串 | 在文本中从上至下搜索该字符串 |
1.1 编写简单文档
编写脚本文档
[root@localhost ~]# vim test.txt
打开文档后,默认进入的是Vim编辑器的命令模式。
使用a、i、o三个键从命令模式切换到输入模式,a键与i键分别是在光标后面一位和光标当前位置切换到输入模式,而o键则是在光标的下面再创建一个空行。
在编写完之后,要想保存并退出,必须先敲击键盘的Esc键从输入模式返回命令模式,然后再输入":wq!"切换到末行模式才能完成保存退出操作。
1.2 配置主机名称
在Linux系统中,主机名大多保存在/etc/hostname文件中,将文件内容改为"weihongbin"
第1步:使用Vim编辑器修改/etc/hostname主机名称文件。
第2步:把原始主机名称删除后追加"weihongbin"。注意,使用Vim编辑器修改主机名称文件后,要在末行模式下执行":wq!"命令才能保存并退出文档。
第3步:保存并退出文档,然后使用hostname命令检查是否修改成功。
[root@localhost ~]# vim /etc/hostname
[root@localhost ~]# systemctl restart systemd-hostnamed
[root@localhost ~]# hostname
weihongbin
1.3 配置网卡信息
名称为ifcfg-ens160的网卡设备,将其配置为开机自启动,并且IP地址、子网、网关等信息由人工指定(动态网卡转为静态网卡)。
第1步:首先切换到/etc/sysconfig/network-scripts目录中(存放着网卡的配置文件)。
第2步:使用Vim编辑器修改网卡文件ifcfg-ens160,逐项写入下面的配置参数并保存退出。由于每台设备的硬件及架构是不一样的,因此请读者使用ifconfig命令自行确认各自网卡的默认名称。
踩坑大集锦
提前先查一下自己的虚拟网络是什么网关,不要跟我写的一样导致ping: www.baidu.com: Name or service not known连不上网,选择虚拟网络编辑器
进入虚拟网络编辑器,取消DHCP,同时选择NAT设置,将网关改成192.168.227.2
修改vm8的网关,搜索控制面板\网络和 Internet\网络连接,选择vm8,右击属性,选IPV4,属性
配置一下IP地址,和默认网关,IP地址选192.168.227.1,默认网关选192.168.227.2,dns首选8.8.8.8
这时候我们看一下我们的本机主机,通过win+R命令,输入cmd进入命令符,输入ipconfig
配置完成,然后看一下以下这几个概念
设备类型:TYPE=Ethernet
地址分配模式:BOOTPROTO=static
网卡名称:NAME=ens160
是否启动:ONBOOT=yes
IP地址:IPADDR=192.168.227.10
子网掩码:NETMASK=255.255.255.0
网关地址:GATEWAY=192.168.227.1
DNS地址:DNS1=192.168.227.1
DNS地址:DNS2=8.8.8.8
第3步:重启网络服务并测试网络是否连通。
进入到网卡配置文件所在的目录,然后编辑网卡配置文件,在其中填入下面的信息(红色为修改或添加部分),默认我们的虚拟机是192.168.227.10,你们也可以设置其他的:
[root@localhost ~]# cd /etc/sysconfig/network-scripts/
[root@localhost network-scripts]# vim ifcfg-ens160
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=``static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=ens160
UUID=83230184-678e-4b11-b50c-20e37b235a70
DEVICE=ens160
ONBOOT=yes
IPADDR=192.168.227.10
NETMASK=255.255.255.0
GATEWAY=192.168.227.2
DNS1=192.168.227.1
DNS2=8.8.8.8
重启reboot(如果你现在是在用xshell连接建议先断开连接后重新接入新的ip地址再试)
不想重启可以执行:
systemctl restart NetworkManager
或nmcli connection reload ens160
[root@weihongbin ~]# ping 192.168.227.10
PING 192.168.227.10 (192.168.227.10) 56(84) bytes of data.
64 bytes from 192.168.227.10: icmp_seq=1 ttl=64 time=0.080 ms
64 bytes from 192.168.227.10: icmp_seq=2 ttl=64 time=0.048 ms
[root@localhost network-scripts]# ping www.baidu.com
PING www.a.shifen.com (220.181.38.149) 56(84) bytes of data.
64 bytes from 220.181.38.149 (220.181.38.149): icmp_seq=1 ttl=128 time=5.71 ms
64 bytes from 220.181.38.149 (220.181.38.149): icmp_seq=2 ttl=128 time=5.28 ms
64 bytes from 220.181.38.149 (220.181.38.149): icmp_seq=3 ttl=128 time=5.72 ms
1.4 配置软件仓库
软件仓库是一种能进一步简化RPM管理软件的难度以及自动分析所需软件包及其依赖关系的技术,搭建并配置软件仓库的大致步骤如下所示
第1步:进入/etc/yum.repos.d/目录中(因为该目录存放着软件仓库的配置文件,红色为添加字段)。
第2步:使用Vim编辑器创建一个名为rhel8.repo的新配置文件(文件名称可随意,但后缀必须为.repo),逐项写入下面的配置参数并保存退出。
仓库名称:具有唯一性的标识名称,不应与其他软件仓库发生冲突。
描述信息(name):可以是一些介绍性的词,易于识别软件仓库的用处。
仓库位置(baseurl):软件包的获取方式,可以使用FTP或HTTP下载,也可以是本地的文件(需要在后面添加file参数)。
是否启用(enabled):设置此源是否可用;1为可用,0为禁用。
是否校验(gpgcheck):设置此源是否校验文件;1为校验,0为不校验。
公钥位置(gpgkey):若上面的参数开启了校验功能,则此处为公钥文件位置。若没有开启,则省略不写。
[root@weihongbin yum.repos.d]# vim rhel8.repo
[BaseOS]
name=BaseOS
baseurl=file:///media/cdrom/BaseOS
enabled=1
gpgcheck=0
[AppStream]
name=AppStream
baseurl=file:///media/cdrom/AppStream
enabled=1
gpgcheck=0
第3步:按配置参数中所填写的仓库位置挂载光盘,并把光盘挂载信息写入/etc/fstab文件中(红色添加)。
[root@weihongbin yum.repos.d]# mkdir -p /media/cdrom
[root@weihongbin yum.repos.d]# mount /dev/cdrom /media/cdrom
mount: /media/cdrom: WARNING: device write-protected, mounted read-only.
[root@weihongbin yum.repos.d]# vim /etc/fstab
#
# /etc/fstab
# Created by anaconda on Mon Nov 6 11:06:38 2023
#
# Accessible filesystems, by reference, are maintained under '/dev/disk/'.
# See man pages fstab(5), findfs(8), mount(8) and/or blkid(8) for more info.
#
# After editing this file, run 'systemctl daemon-reload' to update systemd
# units generated from this file.
#
UUID=147464a6-27ee-477f-8dfd-0c157a0aabc7 / xfs defaults 0 0
UUID=b7107860-5e6f-4ff5-abb3-880ab7e6caca /boot xfs defaults 0 0
UUID=1396ecbf-4d87-4e65-898b-28048721d05e none swap defaults 0 0
/dev/cdrom /media/cdrom iso9660 defaults 0 0
第4步:修改以下配置网址,使用"dnf install httpd -y"命令检查软件仓库是否已经可用。
[root@localhost yum.repos.d]# sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
[root@localhost yum.repos.d]# sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
[root@localhost yum.repos.d]# yum makecache
[root@localhost ~]# dnf install httpd -y
完成配置仓库,安装源相当于官方应用商店,三方源就相当于官方以外的应用商店。
这里要着重聊一下,通过阿里系的也可以配置仓库:阿里云镜像
##配置Linux软件安装源
curl -s -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
##配置第三方源epel
curl -s -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
2. 编写Shell脚本
Shell脚本命令的工作方式有下面两种。
交互式(Interactive):用户每输入一条命令就立即执行。
批处理(Batch):由用户事先编写好一个完整的Shell脚本,Shell会一次性执行脚本中诸多的命令。
通过查看SHELL变量可以发现,当前系统已经默认使用Bash作为命令行终端解释器
[root@localhost ~]# echo $SHELL
/bin/bash
2.1 编写简单的脚本
查看当前所在工作路径并列出当前目录下所有的文件及属性信息,第一行的脚本声明(#!)用来告诉系统使用哪种Shell解释器来执行该脚本;第二行的注释信息(#)是对脚本功能和某些命令的介绍信息,第三、四行的可执行的Linux命令。
[root@localhost ~]# vim example.sh
#! /bin/bash
#for example by weihongbin
pwd
ls -alh
[root@localhost ~]# bash example.sh
/root
total 2.1G
dr-xr-x---. 17 root root 4.0K Nov 15 14:05 .
dr-xr-xr-x. 18 root root 254 Nov 8 15:40 ..
-rw-r--r--. 1 root root 560M Nov 8 15:53 560
也可以用./
来执行bash文件
2.2 接收用户的参数
Linux系统中的Shell脚本语言内设了用于接收参数的变量,变量之间使用空格间隔,
对应的是当前
脚本程序的名称,0对应的是当前Shell脚本程序的名称,0对应的是当前Shell脚本程序的名称,#对应的是总共有几个参数,
对应的是所有位置的参数值,∗对应的是所有位置的参数值,*对应的是所有位置的参数值,?对应的是显示上一次命令的执行返回值,而
、1、1、2、$3......则分别对应着第N个位置的参数值
[root@localhost ~]# vim example.sh
#! /bin/bash
#for example by weihongbin
echo "当前脚本名称为$0"
echo "总共有$#个参数,分别是$*。"
echo "第1个参数为$1,第5个为$5。"
[root@localhost ~]# bash example.sh one two three four five six
当前脚本名称为example.sh
总共有6个参数,分别是one two three four five six。
第1个参数为one,第5个为five。
2.3 判断用户的参数
按照测试对象来划分,条件测试语句可以分为4种:
文件测试语句;
逻辑测试语句;
整数值比较语句;
字符串比较语句。
文件测试即使用指定条件来判断文件是否存在或权限是否满足等情况的运算符
文件测试所用参数
|-----|---------------|
| 操作符 | 作用 |
| -d | 测试文件是否为目录类型 |
| -e | 测试文件是否存在 |
| -f | 判断是否为一般文件 |
| -r | 测试当前用户是否有权限读取 |
| -w | 测试当前用户是否有权限写入 |
| -x | 测试当前用户是否有权限执行 |
使用文件测试语句来判断/etc/fstab是否为一个目录类型的文件,然后通过Shell解释器的内设$?变量显示上一条命令执行后的返回值。如果返回值为0,则目录存在;如果返回值为非零的值,则意味着它不是目录,这个目录不存在:
[root@localhost ~]# [ -d /etc/fstab ]
[root@localhost ~]# echo $?
1
再使用文件测试语句来判断/etc/fstab是否为一般文件,如果返回值为0,则代表文件存在,且为一般文件:
[root@localhost ~]# [ -f /etc/fstab ]
[root@localhost ~]# echo $?
0
Shell终端中逻辑"与"的运算符号是&&,它表示当前面的命令执行成功后才会执行它后面的命令,因此可以用来判断/dev文件是否存在,若存在则输出Exist字样
[root@localhost ~]# [ -e /dev ] && echo "Exist"
Exist
Linux系统中的运算符号为||,表示当前面的命令执行失败后才会执行它后面的命令,因此可以用来结合系统环境变量USER来判断当前登录的用户是否为非管理员身份:
[root@localhost ~]# [ $USER = root ] || echo "user"
[root@localhost ~]# su - centos8
Last login: Wed Nov 15 10:38:34 CST 2023 on tty2
[centos8@localhost ~]$ [ $USER = root ] || echo "user"
user
Linux系统中的运算符号是一个叹号(!),它表示把条件测试中的判断结果取相反值,判断当前用户是否为一个非管理员的用户。由于判断结果因为两次否定而变成正确,因此会正常地输出预设信息:
[root@localhost ~]# [ ! $USER = root ] || echo "administrator"
administrator
&&是逻辑"与",只有当前面的语句执行成功的时候才会执行后面的语句。
||是逻辑"或",只有当前面的语句执行失败的时候才会执行后面的语句。
!是逻辑"非",代表对逻辑测试结果取反值;之前若为正确则变成错误,若为错误则变成正确。
先判断当前登录用户的USER变量名称是否等于root,然后用逻辑"非"运算符进行取反操作,效果就变成了判断当前登录的用户是否为非管理员用户。最后若条件成立,则会根据逻辑"与"运算符输出user字样;若条件不满足,则会通过逻辑"或"运算符输出root字样,而只有在前面的&&不成立时才会执行后面的||符号。
[root@localhost ~]# [ ! $USER = root ] && echo "user" || echo "root"
root
使用规范的整数比较运算符来进行操作。
可用的整数比较运算符
|-----|---------|
| 操作符 | 作用 |
| -eq | 是否等于 |
| -ne | 是否不等于 |
| -gt | 是否大于 |
| -lt | 是否小于 |
| -le | 是否等于或小于 |
| -ge | 是否大于或等于 |
使用free -m命令查看内存使用量情况(单位为MB),然后通过"grep Mem:"命令过滤出剩余内存量的行,再用awk '{print $4}'命令只保留第4列。
[root@localhost ~]# free -m | grep Mem:
Mem: 1790 1139 87 33 563 465
[root@localhost ~]# free -m | grep Mem: | awk '{print $4}'
86
输出结果赋值给一个变量,以方便其他命令进行调用:
[root@localhost ~]# freemem=`free -m | grep Mem: | awk '{print $4}'` && echo $freemem
86
使用整数运算符来判断内存可用量的值是否小于1024,若小于则会提示"Insufficient Memory"(内存不足)的字样:
[root@localhost ~]# [ $freemem -lt 1024 ] && echo "Insufficient Memory"
Insufficient Memory
字符串比较语句用于判断测试字符串是否为空值,或两个字符串是否相同。
常见字符串比较运算符
|-----|-------------|
| 操作符 | 作用 |
| = | 比较字符串内容是否相同 |
| != | 比较字符串内容是否不同 |
| -z | 判断字符串内容是否为空 |
通过判断String变量是否为空值,进而判断是否定义了这个变量:
[root@localhost ~]# [ -z $String ] && echo $?
0
当前语系的环境变量值LANG不是英语(en.US)时,则会满足逻辑测试条件并输出"Not en.US"(非英语)的字样:
[root@localhost ~]# [ ! $LANG = "en.US" ] && echo "Not en.US"
Not en.US
3. 流程控制语句
尽管此时可以通过使用Linux命令、管道符、重定向以及条件测试语句来编写最基本的Shell脚本,但是这种脚本并不适用于生产环境。原因是它不能根据真实的工作需求来调整具体的执行命令,也不能根据某些条件实现自动循环执行。通俗来讲,就是不能根据实际情况做出调整。通常脚本都是从上到下一股脑儿地执行,效率是很高,但一旦某条命令执行失败了,则后面的功能全都会受到影响。
通过if、for、while、case这4种流程控制语句来学习编写难度更大、功能更强的Shell脚本。
3.1 if条件测试语句
if语句分为单分支结构、双分支结构、多分支结构;其复杂度随着灵活度一起逐级上升。
使用单分支的if条件语句来判断/media/cdrom目录是否存在,若不存在就创建这个目录,反之则结束条件判断和整个Shell脚本的执行。
[root@localhost ~]# vim mkcdrom.sh
#! /bin/bash
DIR="/etc/mkcdrom"
if [! -d $DIR]
then
mkdir -p $DIR
fi
使用ls命令验证/media/cdrom目录是否已经成功创建:
[root@localhost ~]# bash mkcdrom.sh
[root@localhost ~]# ls -ld /media/cdrom
dr-xr-xr-x. 7 root root 2048 Nov 13 2021 /media/cdrom
if条件语句的双分支结构由if、then、else、fi关键词组成,它进行一次条件匹配判断,如果与条件匹配,则去执行相应的预设命令;
使用双分支的if条件语句来验证某台主机是否在线,然后根据返回值的结果,要么显示主机在线信息,要么显示主机不在线信息。这里的脚本主要使用ping命令来测试与对方主机的网络连通性,而Linux系统中的ping命令不像Windows一样尝试4次就结束,因此为了避免用户等待时间过长,需要通过-c参数来规定尝试的次数,并使用-i参数定义每个数据包的发送间隔,以及使用-W参数定义等待超时时间,$?变量显示上一条命令执行后的返回值。
[root@localhost ~]# vim chkhost.sh
#! /bin/bash
ping -c 3 -i 0.2 -W 3 $1 &> /dev/null
if [ $? -eq 0 ]
then
echo "Host $1 is On-line."
else
echo "Host $1 is Off-line."
fi
变量,作用是显示上一次命令的执行返回值。若前面的那条语句成功执行,则?变量,作用是显示上一次命令的执行返回值。若前面的那条语句成功执行,则?变量,作用是显示上一次命令的执行返回值。若前面的那条语句成功执行,则?变量会显示数字0,反之则显示一个非零的数字(可能为1,也可能为2,取决于系统版本)。因此可以使用整数比较运算符来判断$?变量是否为0,从而获知那条语句的最终判断情况。192.168.227.10这个ip看你们能连通哪个就用哪个。
[root@localhost ~]# bash chkhost.sh 192.168.227.10
Host 192.168.227.10 is On-line.
[root@localhost ~]# bash chkhost.sh 192.168.227.11
Host 192.168.227.11 is Off-line.
if条件语句的多分支结构由if、then、else、elif、fi关键词组成,它进行多次条件匹配判断,这多次判断中的任何一项在匹配成功后都会执行相应的预设命令,使用多分支的if条件语句来判断用户输入的分数在哪个成绩区间内,然后输出如Excellent、Pass、Fail等提示信息,Linux系统中,read是用来读取用户输入信息的命令,能够把接收到的用户输入信息赋值给后面的指定变量,-p参数用于向用户显示一些提示信息。
只有当用户输入的分数大于等于80分且小于等于100分时,表现不错;若分数不满足该条件(即匹配不成功),则继续判断分数是否大于等于60分且小于等于79分,如果是,则输出直接放弃字样;若两次都落空(即两次的匹配操作都失败了),则输出直接放弃字样,在输入大于100或小于0的分数时,给予Error报错字样的提示。:
[root@localhost ~]# vim chkscore.sh
#! /bin/bash
read -p "输入你得成绩(0-100):" grade
if [ $grade -gt 100 ] && [ $grade -lt 0 ] ; then
echo "请正确填写你的成绩!"
elif [ $grade -ge 80 ] && [ $grade -le 100 ] ; then
echo "$grade 分,表现不错!"
elif [ $grade -ge 60 ] && [ $grade -le 79 ] ; then
echo "$grade 分,继续努力!"
else
echo "$grade 分,直接放弃!"
fi
验证结果:您输入的有误,
[root@localhost ~]# bash chkscore.sh
输入你得成绩(0-100):1000
请正确填写你的成绩!
[root@localhost ~]# bash chkscore.sh
输入你得成绩(0-100):99
99 分,表现不错!
[root@localhost ~]# bash chkscore.sh
输入你得成绩(0-100):61
61 分,继续努力!
[root@localhost ~]# bash chkscore.sh
输入你得成绩(0-100):1
1 分,直接放弃!
3.2 for条件循环语句
for循环语句允许脚本一次性读取多个信息,然后逐一对信息进行操作处理。当要处理的数据有范围时,使用for循环语句
使用for循环语句从列表文件中读取多个用户名,然后为其逐一创建用户账户并设置密码。首先创建用户名称的列表文件users.txt,每个用户名称单独一行。读者可以自行决定具体的用户名称和个数:
[root@localhost ~]# vim users.txt
[root@localhost ~]# cat users.txt
weihongbin01
weihongbin02
weihongbin03
编写Shell脚本addusers.sh。在脚本中使用read命令读取用户输入的密码值,然后赋值给PASSWD变量,并通过-p参数向用户显示一段提示信息,告诉用户正在输入的内容即将作为账户密码。在执行该脚本后,会自动使用从列表文件users.txt中获取到所有的用户名称,然后逐一使用"id用户名"命令查看用户的信息,并使用$?判断这条命令是否执行成功,也就是判断该用户是否已经存在。
[root@localhost ~]# vim addusers.sh
#! /bin/bash
read -p "请输入批量创建的用户名密码 : " PASSWD
``for UNAME in `cat users.txt```
do
id $UNAME &> /dev/null
if [ $? -eq 0 ]
then
echo "$UNAME , 该用户已存在!"
else
useradd $UNAME
echo "$PASSWD" | passwd --stdin $UNAME &> /dev/null
echo "$UNAME , 创建成功!"
fi
done
/dev/null是一个被称作Linux黑洞的文件,把输出信息重定向到这个文件等同于删除数据(类似于没有回收功能的垃圾箱),可以让用户的屏幕窗口保持简洁。在Linux系统中,/etc/passwd是用来保存用户账户信息的文件。如果想确认这个脚本是否成功创建了用户账户,可以打开这个文件,看其中是否有这些新创建的用户信息。
[root@localhost ~]# bash addusers.sh
请输入批量创建的用户名密码 : 123
weihongbin01 , 创建成功!
weihongbin02 , 创建成功!
weihongbin03 , 创建成功!
从文本中自动读取主机列表,然后自动逐个测试这些主机是否在线。
创建一个主机列表文件ipaddrs.txt:
[root@localhost ~]# vim ipaddrs.txt
[root@localhost ~]# cat ipaddrs.txt
192.168.227.10
192.168.227.11
192.168.227.12
双分支if条件语句与for循环语句相结合,让脚本从主机列表文件ipaddrs.txt中自动读取IP地址(用来表示主机)并将其赋值给HLIST变量,从而通过判断ping命令执行后的返回值来逐个测试主机是否在线。
[root@localhost ~]# vim CheckHosts.sh
#!/bin/bash
iplist=$(cat ~/ipaddrs.txt)
for IP in $iplist
do
ping -c 3 -i 0.2 -W 3 $IP &> /dev/null
if [ $? -eq 0 ]
then
echo "Host $IP is On-line."
else
echo "Host $IP is Off-line."
fi
done
脚本中出现的"$(命令)"是一种完全类似于转义字符中反引号`命令`的Shell操作符,检验如下:
[root@localhost ~]# bash CheckHosts.sh
Host 192.168.227.10 is On-line.
Host 192.168.227.11 is Off-line.
Host 192.168.227.12 is Off-line.
3.3 while条件循环语句
while条件循环语句是一种让脚本根据某些条件来重复执行命令的语句,它的循环结构往往在执行前并不确定最终执行的次数,完全不同于for循环语句中有目标、有范围的使用场景。while循环语句通过判断条件测试的真假来决定是否继续执行命令,若条件为真就继续执行,为假就结束循环。
使用多分支的if条件测试语句与while条件循环语句,编写一个用来猜测数值大小的脚本Guess.sh。该脚本使用$RANDOM变量来调取出一个随机的数值(范围为0~32767),然后将这个随机数对1000进行取余操作,并使用expr命令取得其结果,再用这个数值与用户通过read命令输入的数值进行比较判断。这个判断语句分为3种情况,分别是判断用户输入的数值是等于、大于还是小于使用expr命令取得的数值。
[root@localhost ~]# vim Guess.sh
#!/bin/bash
PRICE=$(expr $RANDOM % 1000)
TIMES=0
echo "商品实际价格为0-999之间,猜猜看是多少?"
while true
do
read -p "请输入您猜测的价格数目:" INT
let TIMES++
if [ $INT -eq $PRICE ] ; then
echo "恭喜您答对了,实际价格是 $PRICE"
echo "您总共猜测了 $TIMES 次"
exit
elif [ $INT -gt $PRICE ] ; then
echo "太高了!"
else
echo "太低了!"
fi
done
当条件为true(真)的时候,while语句会一直循环下去,只有碰到exit才会结束
3.4 case条件测试语句
case条件测试语句和switch语句的功能非常相似!case语句是在多个范围内匹配数据,若匹配成功则执行相关命令并结束整个条件测试;如果数据不在所列出的范围内,则会去执行星号(*)中所定义的默认命令。
使用case条件测试语句和通配符,编写脚本Checkkeys.sh,提示用户输入一个字符并将其赋值给变量KEY,然后根据变量KEY的值向用户显示其值是字母、数字还是其他字符。
[root@localhost ~]# vim Checkkeys.sh
#! /bin/bash
read -p "请输入要判断的字符:" key
case "$key" in
[a-z]|[A-Z])
echo "字母"
;;
[0-9])
echo "数字"
;;
*)
echo "特殊字符"
esac
[root@localhost ~]# bash Checkkeys.sh
请输入要判断的字符:1
数字
[root@localhost ~]# bash Checkkeys.sh
请输入要判断的字符:$
特殊字符
[root@localhost ~]# bash Checkkeys.sh
请输入要判断的字符:a
字母
4. 计划任务服务程序
计划任务分为一次性计划任务与长期性计划任务
一次性计划任务:今晚23:30重启网站服务。
长期性计划任务:每周一的凌晨3:25把/home/wwwroot目录打包备份为backup.tar.gz。
一次性计划任务只执行一次,一般用于临时的工作需求。可以用at命令实现这种功能,只需要写成"at时间"的形式就行。如果想要查看已设置好但还未执行的一次性计划任务,可以使用at -l命令;要想将其删除,可以使用"atrm任务序号"
at命令参数及其作用
|----|-------------|
| 参数 | 作用 |
| -f | 指定包含命令的任务文件 |
| -q | 指定新任务名称 |
| -l | 显示待执行任务列表 |
| -d | 删除指定待执行任务 |
| -m | 任务执行后给用户发邮件 |
在使用at命令来设置一次性计划任务时,默认采用的是交互式方法,将系统设置为在今晚23:30自动重启网站服务
[root@localhost ~]# at 23:30
warning: commands will be executed using /bin/sh
at> systemctl restart httpd
at>`` 按下+键来结束编写计划任务
job 1 at Wed Nov 15 23:30:00 2023
[root@localhost ~]# at -l
1 Wed Nov 15 23:30:00 2023 a root
便捷利用管道符处理:
[root@localhost ~]# echo "systemctl restart httpd" | at 23:30
warning: commands will be executed using /bin/sh
job 2 at Wed Nov 15 23:30:00 2023
[root@localhost ~]# at -l
1 Wed Nov 15 23:30:00 2023 a root
2 Wed Nov 15 23:30:00 2023 a root
使用atrm命令删除其中一条:
[root@localhost ~]# atrm 1
[root@localhost ~]# at -l
2 Wed Nov 15 23:30:00 2023 a root
用户激活该脚本后再开始倒计时执行,使用"at now +2 MINUTE"的方式进行操作,表示2分钟(MINUTE)后执行这个任务,也可以将其替代成小时(HOUR)、日(DAY)、月(MONTH)等词汇:
[root@localhost ~]# echo "systemctl restart httpd" | at now +2 MINUTE
warning: commands will be executed using /bin/sh
job 3 at Wed Nov 15 16:35:00 2023
长期执行,创建、编辑计划任务的命令为crontab -e,查看当前计划任务的命令为crontab -l,删除某条计划任务的命令为crontab -r。另外,如果您是以管理员的身份登录的系统,还可以在crontab命令中加上-u参数来编辑他人的计划任务。
crontab命令参数及作用
|----|--------|
| 参数 | 作用 |
| -e | 编辑计划任务 |
| -u | 指定用户名称 |
| -l | 列出任务列表 |
| -r | 删除计划任务 |
分、时、日、月、星期 命令,使用crond服务设置任务的参数格式,有些字段没有被设置,则需要使用星号(*)占位
使用crond设置任务参数字段说明
|----|------------------------|
| 字段 | 说明 |
| 分钟 | 取值为0~59的整数 |
| 小时 | 取值为0~23的任意整数 |
| 日期 | 取值为1~31的任意整数 |
| 月份 | 取值为1~12的任意整数 |
| 星期 | 取值为0~7的任意整数,其中0与7均为星期日 |
| 命令 | 要执行的命令或程序脚本 |
在每周一、三、五的凌晨3:25,都需要使用tar命令把某个网站的数据目录进行打包处理,使其作为一个备份文件。我们可以使用crontab -e命令来创建计划任务,为自己创建计划任务时无须使用-u参数。crontab --e命令的具体实现效果和crontab -l命令的结果如下所示:
[root@localhost ~]# crontab -e
no crontab for root - using an empty one
crontab: installing new crontab
[root@localhost ~]# crontab -l
25 3 * * 1,3,5 /usr/bin/tar -czvf backup.tar.gz /home/wwwroot
除了用逗号(,)来分别表示多个时间段,例如"8,9,12"表示8月、9月和12月。还可以用减号(-)来表示一段连续的时间周期(例如字段"日"的取值为"12-15",则表示每月的12~15日)。还可以用除号(/)表示执行任务的间隔时间(例如"*/2"表示每隔2分钟执行一次任务),所有命令一定要用绝对路径的方式来写,如果不知道绝对路径,请用whereis命令进行查询,加粗部分就是绝对路径。
[root@localhost ~]# whereis tar
tar:
/usr/bin/tar/usr/include/tar.h /usr/share/man/man5/tar.5.gz /usr/share/man/man1/tar.1.gz /usr/share/info/tar.info-1.gz /usr/share/info/tar.info-2.gz /usr/share/info/tar.info.gz
注意事项:
在crond服务的配置参数中,一般会像Shell脚本那样以#号开头写上注释信息,这样在日后回顾这段命令代码时可以快速了解其功能、需求以及编写人员等重要信息。
计划任务中的"分"字段必须有数值,绝对不能为空或是*号,而"日"和"星期"字段不能同时使用,否则就会发生冲突。
使用crontab -e命令进入编辑界面,删除里面的文本信息,使用crontab -r命令直接进行删除:
[root@localhost ~]# crontab -r
[root@localhost ~]# crontab -l
no crontab for root