从零开始的Linux学习日志(3)

vim文本编辑器

1.vim文本编辑器的三种模式

vim文本编辑器,简单的讲就是一个能够查看、修改文件的编辑器,用途的话多种多样,比如修改txt文件内容,配置服务参数等等。刘遄老师在他的书中有一句话令我印象很深——“在Linux中一切都是文件”。所以vim文本编辑器基本上就可以配置所有Linux系统的参数了。
在Linux系统中,我们可以通过输入命令vim 文件来进入vim编辑器。编辑器拥有三种模式,分别为命令模式、输入模式、末行模式。

模式功能
命令模式可以控制光标的移动,对文本进行复制、粘贴、删除和查找的操作
输入模式可以正常的对文件进行修改
末行模式可以保存、退出文件,或设置编辑环境
冒号:键
a,i,o键
ESC键
ESC键
命令模式
末行模式
输入模式

由上图可以看到,输入模式无法直接切换到末行模式,需要先按ESC切换到命令模式,再按才能切换到末行模式进行保存和退出。此外,? / 也能从命令模式进入末行模式。

2.命令模式的常用命令

命令作用
dd剪切光标所在的整行内容
5dd剪切从光标以下(包括该行)的5行内容
yy复制光标所在的整行
5yy复制光标及以下的5行内容
n显示搜索命令定位到的下一个字符串
N显示搜索命令定位到的上一个字符串
u撤销上一步操作
p将之前复制或剪切的内容粘贴到光标后面

搜索命令是末行模式通过命令符进行对关键字的搜索,下面会讲到。

3.末行模式的常用命令

命令作用
:q退出vim文本编辑器
:w保存
:q!强制退出(不保存当前修改)
:wq!强制保存退出
:set nu显示行号(行号不会作为文件内容)
:set nonu取消显示行号
:命令执行该命令
:整数跳转到该行
: s/x/y把光标所在行第一个x替换成y
: s/x/y/g把光标所在所有x替换成y
:%s/x/y/g把全文的x都替换为y
?字符串全文从下至上搜索该字符串
/字符串全文从上至下搜索该字符串

4.vim使用实例——配置主机名称

在Linux系统中,主机名大部分都储存在/etc/hostname文件中,只要修改该文件的内容就可以修改主机名了。
首先我们用vim文本编辑器打开/etc/hostname

[root@RHEL Desktop]# vim /etc/hostname

用vim编辑器打开/etc/hostname后,先按i进入输入模式,将内容修改为RHEL7,再按ESC进入命令模式,然后按:进入末行模式,输入:wq!保存并退出。
在这里插入图片描述
此时主机名就已经成功修改为RHEL7了,我们可以用hostname命令检查是否成功。

[root@zyh Desktop]# hostname
RHEL7

修改成功。

思考:除了使用vim之外是否还有其他方法能够实现主机名称的配置?这里立刻就想到了昨天学习的输出重定向,是否可以使用 命令 > 文件 的输出重定向,将新的主机名直接以直接覆盖的方式直接修改 hostname 文件。

[root@zyh Desktop]# echo "RHEL" > /etc/hostname
[root@zyh Desktop]# hostname
RHEL

实验证明我们的猜想是正确的。

5.vim使用实例——配置网卡信息

在RHEL 7中,网卡配置文件的前缀则以ifcfg开始,加上网卡名称共同组成了网卡配置文件的名字,例如ifcfg-eno16777736。网卡配置文件都放在/etc/sysconfig/network-scripts中。
首先,我们先用cd命令进入/etc/sysconfig/network-scripts。可以用昨天学的通配符查看一下以ifcfg开头的网卡配置文件。

[root@zyh Desktop]# cd /etc/sysconfig/network-scripts/
[root@zyh network-scripts]# ls ifcfg*
ifcfg-eno16777736  ifcfg-lo

然后我们用vim ifcfg-eno16777736,用vim文本编辑器打开网卡配置文件ifcfg-eno16777736。将其中的参数修改如下面所示。

设备类型: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

有时候我们经常会感觉文件、路径的名字太长太难输入,其实可以灵活运用tab键来让系统 自动补全你要输入的内容,比如,你要输入网卡配置文件ifcfg-eno16777736,只要手动输入ifcfg-eno后,按下tab系统就会帮你自动补全接下来的内容,前提是前缀为ifcfg-enod的文件在该文件夹中是唯一的。

思考:配置网卡信息与配置主机名称不同,主机名称文件中只有主机名这么一个内容,想要修改的话除了vim还可以直接用输出重定向直接覆盖的方式来修改,但网卡信息不同,网卡信息文件中本身就有许多内容,我们配置网卡信息的时候只能修改某条参数,而不是直接覆盖整个文件,那是否还有其他方式实现这个效果呢?
第一时间想到的是结合第一天学到的trcat与第二天学到的管道符输出重定向,直接将读取文件中的目标字符串替换成某我们需要的字符串,然后再将该输出重定向到网卡配置文件中

[root@zyh network-scripts]# cat ifcfg-eno16777736 
HWADDR=00:0C:29:B9:51:20
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
PEERDNS=yes
PEERROUTES=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPV6_FAILURE_FATAL=no
NAME=eno16777736
UUID=1ef0f109-a6cc-4ce0-8ae6-19b39cc31c1c
ONBOOT=yes
IPADDR=192.168.10.10
NETMASK=255.255.255.0
GATEWAY=192.168.10.1
DNS1=192.168.10.1
[root@zyh network-scripts]# cat ifcfg-eno16777736 | tr "ONBOOT=yes" "ONBOOT=no"HWADDR=00:0C:29:B9:51:20
TYPE=Ethornot
BOOTPROTO=otatic
DEFROUTE=noo
PEERDNS=noo
PEERROUTES=noo
IPV4_FAILURE_FATAL=no
IPV6INIT=noo
IPV6_AUTOCONF=noo
IPV6_DEFROUTE=noo
IPV6_PEERDNS=noo
IPV6_PEERROUTES=noo
IPV6_FAILURE_FATAL=no
NAME=ono16777736
UUID=1of0f109-a6cc-4co0-8ao6-19b39cc31c1c
ONBOOT=noo
IPADDR=192.168.10.10
NETMASK=255.255.255.0
GATEWAY=192.168.10.1
DNS1=192.168.10.1

比较一下上下,可以很明显发现我失败了,tr命令似乎与我想象中不一样,它实际上是将目标字符串和替换字符串逐位比较,然后将不同的部分,把输入流中全部都替换了。可能没讲清楚,大概意思就是我的初衷是将 ONBOOT=yes 替换成 ONBOOT=no ,但实际中系统比较了一下两个字符串的区别,就简单的处理为将文本中的 yes 全部替换成了 noo 。(还好我先查看了一下结果,没有直接重定向到文件中去,不然就麻烦了)
这次的实验算是失败了,还需要继续思考思考,如果以后想出来的话会在后续的日志中补全的。

SHELL脚本

Shell终端解释器当作人与计算机硬件之间的“翻译官”,它作为用户与Linux系统内部的通信媒介,除了能够支持各种变量与参数外,还提供了诸如循环、分支等高级编程语言才有的控制结构特性。因为我在学习Linux之前其实就已经学过了很多种编程语言,C/C++、Python、Pascal,SQL等。所以对于这种脚本语言还算是比较熟悉的。
Shell脚本命令有两种执行方式,一种是用户输入一条就执行一条的交互式(Interactive),一种是用户先编写好一套完整的Shell脚本,Shell会一次性执行全部脚本的批处理(Batch)。用过Python官方提供的IDE的话应该很好理解这个概念,这里就不多赘述了。
查看一下环境变量SHELL,可以看到当前系统已经使用Bash作为命令行终端解释器了。

[root@zyh network-scripts]# echo $SHELL
/bin/bash

1.编写第一个SHELL脚本

首先,先用vim test.sh命令创建并进入文本编辑器,其实用什么后缀名结尾都无所谓,bash都可以编译,只是以sh结尾可以让我们更快的知道这是个shell脚本,养成良好的文件后缀名意识也是作为程序员的一个基本素养。
然后在文件中写入:

#!/bin/bash 
pwd 
ls -al

其中,第一行#!/bin/bash是告诉系统用了哪种SHELL解释器(感觉有点类似于C程序的头文件申明?);第二、三行则是两条命令。
现在我们用Bash解释器来执行一下刚才编写的SHELL脚本。

[root@RHEL Desktop]# vim test.sh
[root@RHEL Desktop]# bash test.sh
/root/Desktop
total 8
-rw-r--r--. 1 root root 22 Nov  1 14:23 test.sh
-rw-r--r--. 1 root root 59 Nov  1 12:02 test.txt

2.让SHELL脚本接受来自外部的参数

SHELL脚本当然也可以接受来自外部的参数,具体操作如下:
用vim打开test.sh,将内容修改为

#!/bin/bash
echo "first is $1."
echo "SHELL titile is $0."
echo "next is $2,$3,$4."

保存并退出后,用bah解释器执行脚本。

[root@RHEL Desktop]# vim test.sh
[root@RHEL Desktop]# bash test.sh one two three four
first is one.
SHELL titile is test.sh.
next is two,three,four.

这么一看就很明了了,文件中的 $0 代表的就是文件的标题,之后的 $1$4 则是我们比较熟悉的形参,而执行时跟在文件名后面的则是实参

3.测试语句

系统在执行mkdir语句时,会先检测是否已存在该路径的文件夹,如果已存在则会返回错误提示,即昨天学的错误输出重定向。Shell中的测试语句可以检测判断语句是否成立,成立则返回1,否则返回0。
测试语句格式:[ 条件表达式 ]。
注意,中括号左右必须有各有一个空格。例如[ -e test.txt ]因为我们曾在桌面创建过test.txt,所以这个语句的返回值就是0。
按照对象的不同,测试语句可以分为四类:文件测试语句逻辑测试语句整数比较语句字符串比较语句

文件测试语句

操作符作用
-d测试文件是否为目录类型
-e测试文件是否存在
-f测试文件是否为一般文件
-r测试当前用户是否有权限读取该文件
-w测试当前用户是否有权限写入该文件
-x测试当前用户是否有权限执行该文件

查看测试语句的返回值,可以先执行一次语句,然后用echo $?来查看执行结果。

逻辑测试语句

的话就跟我们在其他语言中学习的逻辑语言差不多。,例如[ $USER = root ]来测试当前用户是否为root。此外还有!=&&||等我们熟悉的逻辑符号。而当&&在测试语句外部时,则变成当前面的表达式为真时执行后一条表达式;||则相反。

[root@RHEL Desktop]# [ $USER != root ] && echo "user" || echo "root"
root

这条命令,先判断用户是否不是root,如果不是则执行后面的语句输出 user ,如果是,那么echo "user"这条语句不执行,即该表达式为假,就执行了下一条语句输出 root 。

整数比较语句

其实看到这个概念的时候我还在想,为什么不能直接用逻辑符号比较整数,比如[ 10 > 5 ]来比较10和5那个大,但在Linux中,>这个符号是输出重定向符,[ 10 > 5 ]这个语句其实就是先把10这个字符串输出到了5这个文件中,然后由于语句执行成功了,所以返回值为0。我执行了这条语句之后,桌面就多出了一个名字为5,内容为10的文件。判断是否相等倒是可以用=!=符号。

判断符作用
-eq判断是否相等
-nq判断是否不相等
-gt判断是否大于
-lt判断是否小于
-le判断是否小于等于
-ge判断是否大于等于
[root@RHEL Desktop]# [ 10 -eq 5 ]
[root@RHEL Desktop]# echo $?
1

不得不吐槽,Linux中真为0,假为1这个设定真的让人很不适应。
结合第一天学到的free命令,我们可以写一条用于判断内存是否不足的SHELL脚本。
首先,用free -m命令,以MB为单位显示内存的使用情况;
第二步,用grep Mem命令获得内存使用情况那行的内容;
第三步,用awk '{print $4}'命令获得第四个参数,即剩余的内存容量;
第四步,将该整数与1024比较大小来判断内存容量是否不足,不足则输出“Insufficient Memory”(内存不足)的字样。

FreeMem=`free -m | grep Mem | awk '{print $4}'`
[ $FreeMem -le 1024 ] && echo "Insufficient Memory!"

保存为Mem.sh退出后运行。

[root@RHEL Desktop]# vim Mem.sh 
[root@RHEL Desktop]# bash Mem.sh 
Insufficient Memory!

字符串比较语句

判断符作用
=判断字符串是否想等
!=判断字符串是否不相等
-z判断字符串是否为空

一般来说,可以通过判断一个变量是否为空来判断该变量是否被定义。

4.流程控制语句

SHELL脚本也有迭代、判断等其他编程语言中常见的流程控制语句,有ifcaseforwhile语句,作为一名学过三四种编程语言的学生看到这个真实倍感亲切。

if语句

shell中的if语句跟Pascal中的比较类似,基本结构为:

if [测试语句]
then 命令
else 命令
elif [测试语句]
then 命令
else 命令
fi

其中,末尾的fi是用来表示if语句结束的。因为有编程基础的话,这个语句意思基本就一目了然,就不多赘述了。

for语句

for语句的用法跟Python是一样的,可能因为是同为脚本语言吧。语法为:

for 变量名 in 取值列表
do
命令序列
done

为了进一步理解这个语句,接下来将用for语句编写一个能批量创建用户的SHELL脚本,为此我们需要另外几个知识。
1.id命令,id + 用户名 可以返回该用户的基本信息,如果没有该用户则会返回no such user。
2.useradd命令,看名字就能知道,是个创建用户的命令。
3.有时候,我们并不关心一条命令的返回值,比如id命令,我们这次只需要知道这个用户是否存在而并不关心它的返回值。反过来讲,如果不做处理,每次循环都写id 用户名,那当我们执行这个脚本之后,屏幕上就会刷过大量用户信息或no such user,进而看不清我们想要看到的数据。这显然是我们不期望的情况,因此我们需要将输出重定向到文件中去,如果根本就不需要看输出,那就重定向到/dev/null中(可以认为是回收站)。
3.read命令,看名称就可以知道,是读取数据的命令。
有了这些工具,我们就可以开始编写脚本了。
首先,用vim创建一个用户名称的列表文件 users.txt ,文件里每行都是一个用户名称。
然后再同个文件夹下再创建一个shell脚本 example. sh ,脚本内容如下:

#!/bin/bash
read -p "Enter the Users Passwoed:" PASSWD             #从输入流读入密码
for UNAME in `cat users.txt`                           #将users.txt中的用户名存储在变量UNAME中
do
id $UNAME &> /dev/null                                 #判断用户是否存在
if [ $? -eq 0 ]
then
echo "$UNAME Already Exists!"
else
useradd $UNAME &> /dev/null
echo "$PASSWD" | passwd --stdin $UNAME &> /dev/null    #如果不存在则创建用户并设置密码
if [ $? -eq 0 ]
then
echo "$UNAME Creat Success!"
else
echo "$UNAME Creat Failure!"
fi
fi
done

写好之后保存,然后执行。

[root@RHEL Desktop]# bash example.sh 
Enter the Users Passwoed:123
zyh Already Exists!
zhy Creat Success!
hzy Creat Success!
hyz Creat Success!
[root@RHEL Desktop]# tail -4 /etc/passwd
zyh:x:1001:1001::/home/zyh:/bin/bash
zhy:x:1002:1002::/home/zhy:/bin/bash
hzy:x:1003:1003::/home/hzy:/bin/bash
hyz:x:1004:1004::/home/hyz:/bin/bash

这就成功了。

其实一开始写的时候因为$UNAME少写了一个N,导致一直提示我创建失败,我就将iduseradd的命令错误输出重定向到桌面的文件看了一下,发现是id命令的问题,一检查就发现少写了一个N。

while语句

while语句结构为:

while 条件
do
命令序列
done

还是用一个实例来看while语句怎么用:

#!/bin/bash
COUNT=0
NUM=0
while [ $NUM -le 100 ]
do
COUNT=$[$COUNT+$NUM]
let NUM++
done
echo $COUNT

这个脚本显然是输出1加到100的和,需要注意的是给count累加那一行的写法,关于$符号的用法很有讲究,如果有机会的话以后会拿出来细细研究一番。

case语句

case选择语句的语法结构为:

case 变量名 in
模式1)
命令序列1
;;
模式2)
命令序列2
;;
……
*)
命令序列
esac

其中模式可以认为成取值列表,比如[A-Z]就是指A到Z的取值集合,后面的*)就是我们其他编程语言中case语句的defaut,在变量不符合以上任何一种模式时执行。
举个应用实例,判断一个输入的变量是数字还是字母:

#!/bin/bash
read -p "请任意输入一个字符:" KEY
case $KEY in
[a-z]|[A-Z])
echo "这个字符是字母"
;;
[0-9])
echo "这个字符是数字"
;;
*)
echo "这个字符既不是数字也不是字母"
esac

小结

本来写这个只是想记录一下自己的学习过程,并且像第一篇日志中说的那样,希望能通过边学边写日志的方式,更深入的理解自己所学的知识,但是我是真的没想到我写的日志会有人看。因为我的学习日志其实是按照我自己的基础来写的,就像今天这篇日志,上面的很多语句,因为我已经学过了其他很多的语言,所以写的就相对很简略,如果也有人是在学习Linux的过程中来看我的日志的话应该会看不懂。所以我希望如果,如果真的有人看了我的日志而感到困惑的话,可以自己去刘遄老师的书或者网站去自己学习。
因为有了读者,所以我觉得自己之前两篇跟照搬没什么区别的有点不太适合,就在这篇日志中尝试着加入了自己学习过程中的一些思考与实验,至少让我能有自信说出这篇是我原创的,每一个字都是我认认真真码上去的。另外还是再次感谢刘遄老师的网站。

参考资料来源:
《Linux就该这么学》https://www.linuxprobe.com/
Linux命令大选(手册)http://man.linuxde.net/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值