4.1 Vim 文本编辑器
4.1.1 编写简单文档
Vim 之所以能得到广大厂商与用户的认可,原因在于 Vim 编辑器中设置了三种模式—命令模式、末行模式和编辑模式,每种模式分别又支持多种不同的命令快捷键,这大大提高了工作效率,而且用户在习惯之后也会觉得相当顺手。
- 命令模式:控制光标移动,可对文本进行复制、粘贴、删除和查找等工作。
- 输入模式:正常的文本录入。
- 末行模式:保存或退出文档,以及设置编辑环境。
在下表中列出了命令模式中最常用的一些命令。
命令 | 作用 |
---|---|
dd | 删除(剪切)光标所在整行 |
5dd | 删除(剪切)从光标处开始的 5 行 |
yy | 复制光标所在整行 |
5yy | 复制从光标处开始的 5 行 |
n | 显示搜索命令定位到的下一个字符串 |
N | 显示搜索命令定位到的上一个字符串 |
u | 撤销上一步的操作 |
p | 将之前删除(dd)或复制(yy)过的数据粘贴到光标后面 |
在下表中列出了末行模式中最常用的一些命令。
命令 | 作用 |
---|---|
: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 |
?字符串 | 在文本中从下至上搜索该字符串 |
/字符串 | 在文本中从上至下搜索该字符串 |
4.1.2 配置主机名称
在 Linux系统中,主机名大多保存在/etc/hostname 文件中,接下来将/etc/hostname 文件的内容修改为“linuxprobe.com”,步骤如下。
第1步:使用 Vim 编辑器修改“/etc/hostname”主机名称文件。
第2步:把原始主机名称删除后追加“linuxprobe.com”。注意,使用 Vim 编辑器修改主机名称文件后,要在末行模式下执行:wq!命令才能保存并退出文档。
第3步:保存并退出文档,然后使用 hostname 命令检查是否修改成功。
4.1.3 配置网卡信息
在 RHEL 5、RHEL 6 中,网卡配置文件的前缀为 eth,第1块网卡为 eth0,第2块网卡为 eth1;以此类推。而在 RHEL 7 中,网卡配置文件的前缀则以 ifcfg 开始,加上网卡名称共同组成了网卡配置文件的名字,例如 ifcfg-eno16777736;好在除了文件名变化外也没有其他大的区别。
现在有一个名称为 ifcfg-eno16777736 的网卡设备,我们将其配置为开机自启动,并且 IP地址、子网、网关等信息由人工指定,其步骤应该如下所示。
第1步:首先切换到/etc/sysconfig/network-scripts目录中(存放着网卡的配置文件)。
第2步:使用 Vim 编辑器修改网卡文件 ifcfg-eno16777736,逐项写入下面的配置参数并保存退出。由于每台设备的硬件及架构是不一样的,因此请读者使用 ifconfig 命令自行确认各自网卡的默认名称。
设备类型:TYPE=Ethernet
地址分配模式:BOOTPROTO=static
网卡名称:NAME=eno16777736
是否启动:ONBOOT=yes
IP 地址:IPADDR=192.168.10.10
子网掩码:NETMASK=255.255.255.0
网关地址:GATEWAY=192.168.10.1
DNS 地址:DNS1=192.168.10.1
第3步:重启网络服务并测试网络是否联通。执行重启网卡设备的命令(在正常情况下不会有提示信息),然后通过 ping 命令测试网络能否联通。由于在 Linux 系统中 ping 命令不会自动终止,因此需要手动按下Ctrl+C键来强行结束进程。
[root@linuxprobe network-scripts]# systemctl restart network
[root@linuxprobe network-scripts]# ping 192.168.10.10
PING 192.168.10.10 (192.168.10.10) 56(84) bytes of data.
64 bytes from 192.168.10.10: icmp_seq=1 ttl=64 time=0.081 ms
64 bytes from 192.168.10.10: icmp_seq=2 ttl=64 time=0.083 ms
64 bytes from 192.168.10.10: icmp_seq=3 ttl=64 time=0.059 ms
64 bytes from 192.168.10.10: icmp_seq=4 ttl=64 time=0.097 ms
^C
--- 192.168.10.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.059/0.080/0.097/0.013 ms
4.1.4 配置 Yum 软件仓库
Yum 软件仓库的作用是为了进一步简化 RPM 管理软件的难度以及自动分析所需软件包及其依赖关系的技术。可以把 Yum 想象成是一个硕大的软件仓库,里面保存有几乎所有常用的工具,而且只需要说出所需的软件包名称,系统就会自动为您搞定一切。
既然要使用 Yum 软件仓库,就要先把它搭建起来,然后将其配置规则确定好才行。搭建并配置 Yum 软件仓库的大致步骤如下所示。
第1步:进入到/etc/yum.repos.d/目录中(因为该目录存放着 Yum 软件仓库的配置文件)。
第2步:使用 Vim 编辑器创建一个名为rhel7.repo
的新配置文件(文件名称可随意,但后缀必须为.repo
),逐项写入下面加粗的配置参数并保存退出(不要写后面的中文注释)。
[rhel-media] :Yum 软件仓库唯一标识符,避免与其他仓库冲突。
name=linuxprobe:Yum 软件仓库的名称描述,易于识别仓库用处。
baseurl=file:///media/cdrom:提供的方式包括 FTP(ftp://…)、HTTP(http://…)、本地(file:///…)。
enabled=1:设置此源是否可用;1 为可用,0 为禁用。
gpgcheck=1:设置此源是否校验文件;1 为校验,0 为不校验。
gpgkey=file:///media/cdrom/RPM-GPG-KEY-redhat-release:若上面参数开启校验,那么请指定公钥文件地址。
第3步:按配置参数的路径挂载光盘,并把光盘挂载信息写入到/etc/fstab 文件中。
第4步:使用yum install httpd -y
命令检查 Yum 软件仓库是否已经可用。
进入/etc/yum.repos.d目录中后创建 Yum 配置文件:
[root@linuxprobe ~]# cd /etc/yum.repos.d/ [root@linuxprobe yum.repos.d]# vim rhel7.repo
[rhel7]
name=rhel7
baseurl=file:///media/cdro
enabled=1
gpgcheck=0
创建挂载点后进行挂载操作,并设置成开机自动挂载(详见第 6 章)。尝试使用 Yum 软件仓库来安装 Web 服务,出现Complete! 则代表配置正确:
[root@linuxprobe yum.repos.d]# mkdir -p /media/cdrom
[root@linuxprobe yum.repos.d]# mount /dev/cdrom /media/cdrom
mount: /dev/sr0 is write-protected, mounting read-only
[root@linuxprobe yum.repos.d]# vim /etc/fstab
/dev/cdrom /media/cdrom iso9660 defaults 0 0
[root@linuxprobe ~]# yum install httpd
Loaded plugins: langpacks, product-id, subscription-manager
………………省略部分输出信息………………
Dependencies Resolved
===============================================================================
Package Arch Version Repository Size
===============================================================================
Installing:
httpd x86_64 2.4.6-17.el7 rhel 1.2 M
Installing for dependencies:
apr x86_64 1.4.8-3.el7 rhel 103 k
apr-util x86_64 1.5.2-6.el7 rhel 92 k
httpd-tools x86_64 2.4.6-17.el7 rhel 77 k
mailcap noarch 2.1.41-2.el7 rhel 31 k
Transaction Summary
===============================================================================
Install 1 Package (+4 Dependent packages)
Total download size: 1.5 M
Installed size: 4.3 M
Is this ok [y/d/N]: y
Downloading packages:
-------------------------------------------------------------------------------
………………省略部分输出信息………………
Complete!
4.2 编写 Shell 脚本
Shell 脚本命令的工作方式有两种:交互式和批处理。
- 交互式(Interactive):用户每输入一条命令就立即执行。
- 批处理(Batch):由用户事先编写好一个完整的 Shell 脚本,Shell 会一次性执行脚本中诸多的命令。
查看 SHELL 变量可以发现当前系统已经默认使用 Bash 作为命令行终端解释器了:
miya@asus-x550ld:~$ echo $SHELL
/bin/bash
4.2.1 接收用户的参数
$0
:当前 Shell 脚本程序的名称
$#
:总共有几个参数
$*
:所有位置的参数值
$?
:显示上一次命令的执行返回值
$1
、$2
、$3
……:分别对应着第 N 个位置的参数值
4.2.2 判断用户的参数
Shell 脚本中的条件测试语法可以判断表达式是否成立,若条件成立则返回数字 0,否则便返回其他随机数值。
按照测试对象来划分,条件测试语句可以分为 4 种:
- 文件测试语句
- 逻辑测试语句
- 整数值比较语句
- 字符串比较语句
文件测试即使用指定条件来判断文件是否存在或权限是否满足等情况的运算符,具体的参数见下表。
运算符 | 作用 |
---|---|
-d | 测试文件是否为目录类型 |
-e | 测试文件是否存在 |
-f | 判断是否为一般文件 |
-r | 测试当前用户是否有权限读取 |
-w | 测试当前用户是否有权限写入 |
-x | 测试当前用户是否有权限执行 |
下面使用文件测试语句来判断 /etc/fstab 是否为一个目录类型的文件,然后通过 Shell 解释器的内设$?
变量显示上一条命令执行后的返回值。如果返回值为 0,则目录存在;如果返回值为非零的值,则意味着目录不存在:
miya@asus-x550ld:~$ [ -d /etc/fstab ]
miya@asus-x550ld:~$ echo $?
1
再使用文件测试语句来判断 /etc/fstab 是否为一般文件,如果返回值为 0,则代表文件存在,且为一般文件:
miya@asus-x550ld:~$ [ -f /etc/fstab ]
miya@asus-x550ld:~$ echo $?
0
逻辑语句用于对测试结果进行逻辑分析,根据测试结果可实现不同的效果。例如在 Shell终端中逻辑“与”的运算符号是&&
,它表示当前面的命令执行成功后才会执行它后面的命令,因此可以用来判断 /dev/cdrom 文件是否存在,若存在则输出 Exist 字样。
miya@asus-x550ld:~$ [ -e /dev/cdrom ] && echo "Exist"
Exist
除了逻辑“与”,还有逻辑“或”,它在 Linux 系统中的运算符号为||
,表示当前面的命令执行失败后才会执行它后面的命令,因此可以用来结合系统环境变量 USER 来判断当前登录的用户是否为非管理员身份:
miya@asus-x550ld:~$ echo $USER
miya
miya@asus-x550ld:~$ [ $USER = root ] || echo "user"
user
miya@asus-x550ld:~$ sudo su -
[sudo] password for miya:
root@asus-x550ld:~# [ $USER = root ] || echo "user"
root@asus-x550ld:~#
第三种逻辑语句是“非”,在 Linux 系统中的运算符号是一个叹号!
,它表示把条件测试中的判断结果取相反值。也就是说,如果原本测试的结果是正确的,则将其变成错误的;原本测试错误的结果则将其变成正确的。
miya@asus-x550ld:~$ [ ! $USER = root ] && echo "administrator"
administrator
下面这个示例的执行顺序是,先判断当前登录用户的USER
变量名称是否等于 root,然后用逻辑运算符“非”进行取反操作,效果就变成了判断当前登录的用户是否为非管理员用户了。最后若条件成立则会根据逻辑“与”运算符输出 user 字样;或条件不满足则会通过逻辑“或”运算符输出 root 字样,而如果前面的&&
不成立才会执行后面的||
符号。
miya@asus-x550ld:~$ [ ! $USER = root ] && echo "i am not root" || echo "i am root"
i am not root
miya@asus-x550ld:~$ sudo su -
root@asus-x550ld:~# [ ! $USER = root ] && echo "i am not root" || echo "i am root"
i am root
因为等号与赋值命令符冲突,大于号和小于号分别与输出重定向命令符和输入重定向命令符冲突。因此一定要使用规范的整数比较运算符来进行操作。可用的整数比较运算符如下表所示。
运算符 | 作用 |
---|---|
-eq | 是否等于 |
-ne | 是否不等于 |
-gt | 是否大于 |
-lt | 是否小于 |
-le | 是否等于或小于 |
-ge | 是否大于或等于 |
miya@asus-x550ld:~$ [ 10 -eq 10 ]
miya@asus-x550ld:~$ echo $?
0
miya@asus-x550ld:~$ [ 10 -gt 10 ]
miya@asus-x550ld:~$ echo $?
1
miya@asus-x550ld:~$ [ 10 -ge 10 ]
miya@asus-x550ld:~$ echo $?
0
free
命令,可以用来获取当前系统正在使用及可用的内存量信息。接下来先使用 free -m
命令查看内存使用量情况(单位为 MB),然后通过 grep Mem:
命令过滤出剩余内存量的行,再用 awk '{print $4}'
命令只保留第四列,最后用 FreeMem=语句
的方式把语句内执行的结果赋值给变量。
miya@asus-x550ld:~$ free -m
total used free shared buff/cache available
Mem: 3819 1728 545 184 1545 1669
Swap: 2047 24 2023
miya@asus-x550ld:~$
miya@asus-x550ld:~$ free -m | grep Mem | awk '{print $4}'
563
miya@asus-x550ld:~$
miya@asus-x550ld:~$ FreeMem=`free -m | grep Mem | awk '{print $4}'`
miya@asus-x550ld:~$ echo $FreeMem
519
接下来,可以使用整数运算符来判断内存可用量的值是否小于 1024,若小于则会提示“Insufficient Memory”(内存不足)的字样:
miya@asus-x550ld:~$ [ $FreeMem -lt 1024 ] && echo "Insufficient Memory"
Insufficient Memory
字符串比较语句用于判断测试字符串是否为空值,或两个字符串是否相同。它经常用来判断某个变量是否未被定义(即内容为空值),理解起来也比较简单。字符串比较中常见的运算符如下表所示。
运算符 | 作用 |
---|---|
= | 比较字符串内容是否相同 |
!= | 比较字符串内容是否不同 |
-z | 判断字符串内容是否为空 |
-n | 判断字符串内容是否不为空 |
接下来通过判断 String 变量是否为空值,进而判断是否定义了这个变量:
miya@asus-x550ld:~$ [ -z $String ]
miya@asus-x550ld:~$ echo $?
0
再尝试引入逻辑运算符来试一下。当用于保存当前语系的环境变量值 LANG 不是英语(en.US)时,则会满足逻辑测试条件并输出“Not en.US”(非英语)的字样:
miya@asus-x550ld:~$ echo $LANG
en_US.UTF-8
miya@asus-x550ld:~$ [ $LANG != "en_US" ] && echo "Not en_US"
Not en_US
4.3 流程控制语句
4.3.1 if 条件测试语句
miya@asus-x550ld:~$ cat chksocre.sh
#!/bin/bash
read -p "Please Enter your score(0~100):" GRADE
if [ $GRADE -ge 85 ] && [ $GRADE -le 100 ];then
echo "GOOD JOB!"
elif [ $GRADE -ge 60 ] && [ $GRADE -le 84 ];then
echo "Pass"
elif [ $GRADE -ge 0 ] && [ $GRADE -le 59 ] ;then
echo "Failed"
else
echo "Error score"
fi
miya@asus-x550ld:~$
miya@asus-x550ld:~$ bash chksocre.sh
Please Enter your score(0~100):101
Error score
miya@asus-x550ld:~$
miya@asus-x550ld:~$ bash chksocre.sh
Please Enter your score(0~100):15
Failed
miya@asus-x550ld:~$ bash chksocre.sh
Please Enter your score(0~100):60
Pass
miya@asus-x550ld:~$ bash chksocre.sh
Please Enter your score(0~100):86
GOOD JOB!
4.3.2 for 条件循环语句
miya@asus-x550ld:~$ cat host.lst
192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.0.5
192.168.0.6
192.168.0.7
192.168.0.8
192.168.0.9
miya@asus-x550ld:~$ cat chkhost.sh
#!/bin/bash
HLIST=$(cat /home/miya/host.lst)
for IP in $HLIST
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
miya@asus-x550ld:~$
miya@asus-x550ld:~$ bash chkhost.sh
Host 192.168.0.1 is On-line.
Host 192.168.0.2 is Off-line.
Host 192.168.0.3 is Off-line.
Host 192.168.0.4 is Off-line.
Host 192.168.0.5 is Off-line.
Host 192.168.0.6 is Off-line.
Host 192.168.0.7 is Off-line.
Host 192.168.0.8 is On-line.
Host 192.168.0.9 is Off-line.
miya@asus-x550ld:~$
4.3.3 while 条件循环语句
miya@asus-x550ld:~$ cat 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 0
elif [ $INT -gt $PRICE ] ; then
echo "太高了!"
else
echo "太低了!"
fi
done
miya@asus-x550ld:~$ bash guess.sh
商品实际价格为 0-999 之间,猜猜看是多少?
请输入您猜测的价格数目:500
太低了!
请输入您猜测的价格数目:750
太低了!
请输入您猜测的价格数目:875
太高了!
请输入您猜测的价格数目:815
太高了!
请输入您猜测的价格数目:782
太低了!
请输入您猜测的价格数目:800
太低了!
请输入您猜测的价格数目:810
恭喜您答对了,实际价格是 810
您总共猜测了 7 次
miya@asus-x550ld:~$
4.3.4 case 条件测试语句
miya@asus-x550ld:~$ cat chkkeys.sh
#!/bin/bash
read -p "请输入一个字符,并按 Enter 键确认:" KEY
case "$KEY" in
[a-z]|[A-Z])
echo "您输入的是字母。"
;;
[0-9])
echo "您输入的是数字。"
;;
*)
echo "您输入的是空格、功能键或其它控制字符。"
esac
miya@asus-x550ld:~$
miya@asus-x550ld:~$ bash chkkeys.sh
请输入一个字符,并按 Enter 键确认:8
您输入的是数字。
miya@asus-x550ld:~$ bash chkkeys.sh
请输入一个字符,并按 Enter 键确认:n
您输入的是字母。
miya@asus-x550ld:~$ bash chkkeys.sh
请输入一个字符,并按 Enter 键确认:45
您输入的是空格、功能键或其它控制字符。
miya@asus-x550ld:~$
4.4 计划任务服务程序
计划任务分为一次性计划任务与长期性计划任务,大家可以按照如下方式理解。
- 一次性计划任务:可以用
at
命令实现。如今晚 11 点 30 分开启网站服务。 - 长期性计划任务:可以用
crontab
命令实现。如每周一的凌晨 3 点 25 分把/home/wwwroot 目录打包备份为backup.tar.gz。
如果想要查看已设置好但还未执行的一次性计划任务,可以使用 at -l
命令;要想将其删除,可以用 atrm 任务序号
。在使用 at
命令来设置一次性计划任务时,默认采用的是交互式方法。例如,使用下述命令将系统设置为在今晚 23:30 分自动重启网站服务。
[linuxprobe@linuxprobe ~]$ at 23:30
at > systemctl restart httpd
at > 此处请同时按下 Ctrl + D 组合键来结束编写计划任务
job 3 at Mon Apr 27 23:30:00 2017
[linuxprobe@linuxprobe ~]$ at -l
3 Mon Apr 27 23:30:00 2017 a root
可以把使用管道符,让 at
命令接收前面 echo
命令的输出信息,以达到通过非交互式的方式创建计划一次性任务的目的。
[linuxprobe@linuxprobe ~]$ echo "systemctl restart httpd" | at 23:30
job 4 at Mon Apr 27 23:30:00 2017
[linuxprobe@linuxprobe ~]$ at -l
3 Mon Apr 27 23:30:00 2017 a root
4 Mon Apr 27 23:30:00 2017 a root
如果不小心设置了两个一次性计划任务,可以使用 atrm
命令轻松删除其中一个。
[linuxprobe@linuxprobe ~]$ atrm 3
[linuxprobe@linuxprobe ~]$ at -l
4 Mon Apr 27 23:30:00 2017 a root
如果我们希望 Linux 系统能够周期性地、有规律地执行某些具体的任务,那么 Linux 系统中默认启用的 crond服务
简直再适合不过了。创建、编辑计划任务的命令为 crontab -e
,查看当前计划任务的命令为 crontab -l
,删除某条计划任务的命令为 crontab -r
。
如果以管理员的身份登录的系统,还可以在 crontab
命令中加上 -u
参数来编辑他人的计划任务。使用 crond 服务设置任务的参数格式为“分、时、日、月、星期 命令”。
字段 | 说明 |
---|---|
分 | 取值为 0~59 的整数 |
时 | 取值为 0~23 的任意整数 |
日 | 取值为 1~31 的任意整数 |
月 | 取值为 1~12 的任意整数 |
星期 | 取值为 0~7 的任意整数,其中 0 与 7 均为星期日 |
命令 | 要执行的命令或程序脚本(必须全路径) |
每周一、三、五的凌晨 3 点 25 分,使用 tar 命令把某个网站的数据目录进行打包备份:
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分钟执行一次任务)。
【注意事项】
- 在
crond服务
的配置参数中,可以像 Shell 脚本那样以#
号开头写上注释信息,这样在日后回顾这段命令代码时可以快速了解其功能、需求以及编写人员等重要信息。 - 计划任务中的“分(min)”字段必须有数值,绝对不能为空或是
*
号,而“日(day)”和“星期(week)”字段不能同时使用,否则就会发生冲突。