目录
前言
1.shell的简介
2.shell的工作流程
3.shell的类型
Shell基础环境
编写一个shell脚本
脚本执行
shell基础命令
Date命令
历史命令
自动补全以及别名
重定向及管道
shell脚本中的变量
1.引用命令
2.与用户交互
3常见内置变量
4常见的系统环境变量
5.数学运算
Shell字符串和数组
Shell字符串
1.获取字符串长度:
2.字符串拼接
3.字符串截取
4.字符串替换
shell数组
1.获取数组元素的值:
2.获取数组长度
3.数组拼接、合并
4.数组的赋值
5.数组的删除
6.数组切片
shell流程控制
If语句
1.不带有else
2. 带有else(相当于否则的意思)
3.带有elif(相当于再则的意思)
4.嵌套(if语句里再添加if语句)
5.多个条件
6.if逻辑判断
7.shell中的case判断
Shell中的循环
1. for循环
2.转义字符
2.1 符号的介绍与对比
2.2单引号和双引号的区别
.2.3 转义符
3.While循环
4.Shell中的中断和继续
4.1 continue(继续)
4.2 break (终止)
Shell中的函数
Shell中正则表达式
1.基础正则:
2.常用命令
3.三剑客之grep
4.三剑客之sed
5.三剑客之awk
前言
1.shell的简介
Shell 是一个应用程序,它连接了用户和 Linux 内核,让用户能够更加高效、安全、低成本地使用 Linux 内核,这就是 Shell 的本质。然而Shell本身并不是内核的一部分,它只是站在内核的基础上编写的一个应用程序,但是 Shell 也有着它的特殊性,就是开机立马启动,并呈现在用户面前;用户通过 Shell 来使用 Linux,不启动 Shell 的话,用户就没办法使用 Linux。
Shell 也是一种脚本语言,是系统命令的集合,可以使用逻辑判断、循环等语法,可以自定义函数,我们编写完源码后不用编译,直接运行源码即可。
Shell脚本是在Linux的shell中运行的,所以称为shell脚本。本质上,shell脚本就是一些命令的集合。shell脚本可以实现自动化运维,所以能帮助我们很方便的管理服务器;比如我们可以指定一个任务计划,定时的去执行某个shell脚本已满足需求
Shell,中文翻译为“壳”(相对于kernel“核”),是用于保护操作系统内核的工具。操作系统的核心kernel管理整个计算机硬件相关部分,因此这部分是需要被保护的!为了保护内核,隔离用户与内核,我们引入了Shell的概念,用户若想与操作系统的内核打交道必须通过Shell进行沟通。
2.shell的工作流程
下面通过一个简单的示例来说明Shell的工作。例如,当我们需要让计算机播放音乐,我们必须需要以下几样东西:
硬件:如果需要电脑播放音乐,必须有“声卡”这个设备,否则无法发声
管理程序:操作系统需要支持这个设备并且具有这个设备的驱动程序
应用程序:用户使用软件(或某些指令)让电脑发出声音
Shell工作的流程是:
用户在命令行提示符下键入命令(播放音乐),开始与Shell交互
Shell将用户的指令转化为内核能够理解的指令并传递给内核
内核做出相应的操作(调用声卡驱动程序等),直至控制相关的硬件设备(声卡发声)
Shell将运行结果反馈给用户(成功/失败)
简单来说,Shell接收用户发出的指令并且传递给内核Kernel,内核再进行后续的工作。这样,用户无需也不能直接访问内核,不仅大大方便了用户使用操作系统,也隔离了用户与内核,内核被Shell保护。
3.shell的类型
1.Bourne Shell(简称sh):由AT&T贝尔实验室的Bourne开发,是Unix系统上的第一个Shell程序,一经问世就成为了工业标准。现在几乎所有的Unix/Linux系统都支持它。不过sh的功能较薄弱,且没有历史记录等重要功能,因此目前大多数操作系统将其作为应急Shell使用。
//注意:在Ubuntu中,出于执行效率的考虑,sh已经更改为dash(即sh是dash的软链接)
2.C Shell(简称csh):由加利福尼亚大学伯克利分校研发,最初的研发目的是为了改进sh的缺点。由于其Shell脚本的风格接近C语言因此最初受到广大C语言用户喜爱。不过由于其健壮性较弱,目前的应用并不十分广泛
3.Korn Shell(简称ksh):由David Korn开发,最初是为了解决sh的用户交互问题以及改进csh的“怪异的”脚本编程风格。使用ksh需要许可证,因此应用并不广泛。
4.Bourne Again Shell(简称bash):由AT&T贝尔实验室的Bourne开发,sh的增强版。随着bash的不断完善,它已经成为了最流行的shell。
5.Debian Almquist Shell(简称dash):比bash小,只需占用较小的磁盘空间,而且需要的库更少。不过相对于bash功能也更少。
查看自己的终端的Shell类型:指令 echo $SHELL
Shell基础环境
第一行一定是:#! /bin/bash。该命令说明,该文件使用的是bash语法,如果不设置该行,则该脚本不会被执行。以#开头的行作为解释说明。Shell脚本通常以sh为后缀,用于区分这是一个shell脚本。
编写一个shell脚本
[root@localhost ~]# ls
anaconda-ks.cfg
[root@localhost ~]# vi 1.sh
#!/bin/bash
#创建文本1.txt
touch /tmp/1.txt
#赋予权限600
chmod 600 /tmp/1.txt
#改名为2.txt
mv /tmp/1.txt /tmp/2.txt
脚本执行
这里介绍脚本的4种执行方法,工作目录执行(需赋予脚本执行权限)、绝对路径执行、sh执行(无需设定权限,直接通过sh或bash调用)和shell环境执行(使用.或source在当前shell环境中执行)。
- 工作目录执行,指的是执行脚本时,先进入到脚本所在的目录(此时,称为工作目录),然后使用 ./脚本方式执行
[root@localhost ~]# ./1.sh
-bash: ./1.sh: 权限不够
上述说到使用工作目录需要给予脚本执行权限
[root@localhost ~]# ll
总用量 8
-rw-r--r--. 1 root root 128 10月 8 13:27 1.sh
-rw-------. 1 root root 1257 9月 23 17:20 anaconda-ks.cfg
[root@localhost ~]# chmod 755 1.sh
[root@localhost ~]# ./1.sh
可以看到脚本执行成功了
- 绝对路径执行,指的是直接从根目录/到脚本目录的绝对路径
[root@localhost ~]# /root/1.sh
3. sh执行,指的是用脚本对应的sh或bash来接着脚本执行
[root@localhost ~]# sh 1.sh
4.shell环境执行,指的是在当前的shell环境中执行,可以使用 . 接脚本 或 source 接脚本
[root@localhost ~]# source 1.sh
mv:是否覆盖"/tmp/2.txt"? y
查看脚本的执行过程
[root@localhost ~]# bash -x 1.sh
+ touch /tmp/1.txt
+ chmod 600 /tmp/1.txt
+ mv /tmp/1.txt /tmp/2.txt
查看脚本是否有语法错误
[root@localhost ~]# bash -n 1.sh
shell基础命令
Date命令
1.显示年月日
三种方法
[root@localhost ~]# date +%Y-%m-%d
2024-10-08
[root@localhost ~]# date +%y-%m-%d
24-10-08
[root@localhost ~]# date +%F
2024-10-08
2.显示时分秒
两种方法
[root@localhost ~]# date +%T
15:04:36
[root@localhost ~]# date +%H:%M:%S
15:04:52
3.显示星期
date +%w #一周中的第几天
date +%W #一年中的第几周
4.时间戳
使用命令date +%s 显示从 1970 年 1 月 1 日 00:00:00 到目前为止的秒数。
[root@localhost ~]# date +%s
1728371644
使用date -d @1728371644显示输入描述前的时间
5. 显示一个小时之前/之后
date -d "+1 hour" #一个小时后
date -d "-1 hour" #一个小时前
6. 表示一天之前/之后
date -d "+1day" #一天后
date -d "-1 day" #一天前
历史命令
当我们在linux中执行命令时,执行过的每一条命令都会被保存到家目录的.bash_history文件中,需要注意的是:只有当用户正常退出当前shell时,在当前shell中运行的命令才会保存至.bash_history文件中
History命令
查看所有历史命令列表:
退出终端这些历史命令会被清除
查看指定历史命令:
通过管道的形式来查看指定历史的命令
清除历史命令:
History命令更多的参数操作可以参考history命令手册
通过man history 命令实现
自动补全以及别名
1.自动补全:
在命令行输入命令或者文件名/目录名时,只需要填写前面几个文字后,按下键盘上面的“Tab”键,即可自动补全。当你填写的文件名有多个在同一目录时,按两下键盘的“Tab”键,会把有部分相同之处的都显示出来
2.别名:
别名的作用:别名是Shell中的一个功能,它可以让你为常用的命令设置一个简短易记的替代名称。当你输入这个别名时,Shell会自动替换为对应的命令,从而简化命令的输入和记忆。
别名的语法:在Shell中,创建别名的语法为:alias 别名='命令'。其中,别名是你要设置的简短名称,命令则是你想要关联的完整命令。
临时创建别名:
只需要刷新一下shell解释器就会恢复原本的命令
删除别名:
unalias ls
永久别名:
如果你希望别名在每次启动Shell时都可用,可以将别名添加到Shell的配置文件中。常见的配置文件有.bashrc(Bash)和.zshrc(Zsh)。你可以使用文本编辑器打开对应的配置文件,在文件末尾添加别名的定义。例如,在.bashrc中添加别名ls:
[root@localhost ~]# vi .bashrc
# .bashrc
alias ls='ll'
重定向及管道
1.重定向:
重定向又分为输出重定向、输入重定向、追加重定向。与python中open函数打开文件的w(写),r(读),a(追加)对应。
- 输出重定向>:若是指定文件不存在则创建一个文件并指向该文件。若是指定文件存在则先清空该文件,再指向该文件
查看要输出的文件,将它写入1.txt,不存在则自动创建
输入重定向及追加重定向操作与下面类似
- 输入重定向<:从指定文件读取数据
- 追加重定向>>:若是指定文件不存在则创建一个文件并指向该文件。若是指定文件存在则直接指向该文件,不会进行清空
2.管道:
管道是可以串联多条命令的,每条命令的结果输出,都作为输入,导入下一条命令。
简单来说就是前面的命令限定范围,后面的命令在这个范围里进行该命令特定的动作
比如我下面的这条命令,即在查看1.sh这个范围里,通过查询echo这个关键字,找到在1.sh里的具有echo关键字的关键行
shell脚本中的变量
在shell脚本中使用变量可以节省时间并且使我们的脚本更加专业,所以当我们编写一个脚本时,就可以使用变量来代替某个使用频繁并且长度很长的字符串。变量的格式:“变量名=变量的值”。
1.引用命令
当我们引用某个命令的结果时,可以使用变量替代
示例两种形式(效果一样):
[root@localhost ~]# a=`date +%w`
[root@localhost ~]# echo $a
2
[root@localhost ~]# a=$(date +%w)
[root@localhost ~]# echo $a
2
2.与用户交互
这里相当于把用户交互时写的值赋予给变量n
[root@localhost ~]# read -p "请输入一个数字:" n
请输入一个数字:10
[root@localhost ~]# echo $n
10
由于没有创造一个变量接收值,系统默认变量REPLY(英文 :回答)
[root@localhost ~]# read -p "请输入一个数字:"
请输入一个数字:100
[root@localhost ~]# echo $REPLY
100
3常见内置变量
变量 | 含义 |
$0 | 脚本名 |
$1~$9 | 位置参数1~9 |
${10} | 位置参数10 |
$# | 位置参数的个数 |
“$*” | 所有位置参数(整体作为单个字符串) |
“$@” | 所有位置参数(每个作为单独字符串) |
${#*} | 传递到脚本中的命令行参数的个数 |
$? | 返回值,用于判断前一命令是否执行成功,0为成功,1则失败 |
$$ | 脚本进程的PID |
$- | 传递到脚本中的标识 |
$_ | 之前命令的最后一个参数 |
$! | 运行在后台的最后一个作业的进程ID(PID) |
编辑脚本:
[root@localhost ~]# vi variable.sh
#!/bin/bash
echo "$1"
echo "第二个参数是$2"
echo "第三个参数是$3"
echo "本脚本一共有$#个参数"
echo "所有位置参数(作为单个字符串)为:"$*""
echo "所有位置参数每个作为单独字符串)为:"$@""
echo "$0"
echo "脚本中的命令行参数的个数为:${#*}"
echo "脚本中的标识为:$-"
echo "命令的最后一个参数为:$_"
执行脚本:
判断上一命令是否执行成功
[root@localhost ~]# echo $?
0
查看脚本pid
[root@localhost ~]# echo $$
2101
[root@localhost ~]# ps
PID TTY TIME CMD
2101 pts/0 00:00:00 bash
/0 00:00:00 ps
4常见的系统环境变量
#Shell常见的环境变量,主要是在程序运行时需要设置,环境变量详解如下:
PATH 命令所示路径,以冒号为分割;
HOME 打印用户家目录;
SHELL 显示当前Shell类型;
USER 打印当前用户名;
ID 打印当前用户id信息;
PWD 显示当前所在路径;
TERM 打印当前终端类型;
HOSTNAME 显示当前主机名;
PS1 定义主机命令提示符的;
HISTSIZE 历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间;
RANDOM 随机生成一个 0 至 32767 的整数;
HOSTNAME 主机名
这里不过多赘述举一些例子展示
5.数学运算
创建一个脚本
[root@localhost ~]# vi sum.sh
#!/bin/bash
a=1
b=2
sum=$[$a+$b] #还可以采用sum=$(($a+$b))这种写法
echo "$a+$b=$sum"
执行脚本
Shell字符串和数组
Shell字符串
定义:
字符串可以由单引号' '包围,也可以由双引号" "包围,也可以不用引号。
三种形式的区别:
1.不被引号包围的字符串:不被引号包围的字符串中出现变量时也会被解析;字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析。
2.由单引号包围的字符串:任何字符都会原样输出,在其中使用变量是无效的;字符串中不能出现单引号,对单引号进行转义也不行。
3.由双引号" "包围的字符串: 如果其中包含了某个变量,那么该变量会被解析,得到该变量的值,而不是原样输出;字符串中可以出现双引号。
1.获取字符串长度:
格式:${#字符串名}
[root@localhost ~]# str1="1234567"
[root@localhost ~]# echo ${#str1}
7
-
2.字符串拼接
将两个字符串并排放在一起就能实现拼接。$str1$str2这种写法不允许变量之间有空格,但是只要加上””就可以
[root@localhost ~]# str2="891011"
[root@localhost ~]# str3=$str1$str2
[root@localhost ~]# echo $str3
1234567891011
-
3.字符串截取
Shell截取字符串通常有两种方式:从指定位置开始截取和从指定字符(子字符串)开始截取。
- 从左边开始计数时,起始数字是0(这符合程序员思维);从右边开始计数时,起始数字是1(这符合常人思维)。计数方向不同,起始数字也不同。
- 不管从哪边开始计数,截取方向都是从左到右。且截取的原则为[ ),即左闭右开
使用指定位置从左边开始截取:
[root@localhost ~]# echo ${str1:3:1}
4
[root@localhost ~]# echo ${str1:3:2}
45
使用指定位置从右边开始截取:
[root@localhost ~]# echo ${str1:0-1:2}
7
[root@localhost ~]# echo ${str1:0-2:2}
67
使用字符指定从左边开始截取:
使用#号可以截取指定字符(或者子字符串)右边的所有字符。
*是通配符的一种,表示任意长度的字符串。*字符3连起来使用的意思是:忽略左边的所有字符,直到遇见字符3(3字符不会被截取)。
[root@localhost ~]# echo ${str1#*3}
4567
使用字符指定从右边开始截取:
使用%号可以截取指定字符(或者子字符串)左边的所有字符。
注意*的位置,因为要截取字符3左边的字符,而忽略3右边的字符,所以*应该位于3的右侧。
[root@localhost ~]# echo ${str1%3*}
12
-
4.字符串替换
格式:${字符串/要替换的字符/替换的字符}
[root@localhost ~]# str4="hello shell"
[root@localhost ~]# echo ${str4/shell/world}
hello world
shell数组
概述:
bash支持一维数组(不支持多维数组),并且没有限定数组的大小。数组是相同类型的元素按一定顺序排列的集合。 类似与 C 语言,数组元素的索引由 0 开始编号。获取数组中的元素要利用索引,索引可以是整数或算术表达式,其值应大于或等于 0。
定义:
在 Shell 中,用括号来表示数组,数组元素用“空格”符号分割开
格式:数组名=(元素1 元素2 元素3 元素n)
1.获取数组元素的值:
${数组名[索引]}
[root@localhost ~]# array1=(aa bb cc dd)
[root@localhost ~]# echo ${array1[0]}
aa
[root@localhost ~]# echo ${array1[1]}
bb
[root@localhost ~]#
2.获取数组长度
利用@或*,可以将数组扩展成列表,然后使用#来获取数组元素的个数。
[root@localhost ~]# echo ${#array1[@]}
4
[root@localhost ~]# echo ${#array1[*]}
4
3.数组拼接、合并
Shell数组拼接(数组合并),将两个数组连接成一个数组。拼接数组的思路是:先利用@或*,将数组扩展成列表,然后再合并到一起。
[root@localhost ~]# array3=(${array2[@]} ${array1[@]})
[root@localhost ~]# echo ${array3[@]}
ee ff gg hh aa bb cc dd
4.数组的赋值
利用索引对指定元素进行赋值
[root@localhost ~]# echo ${array1[@]}
aa bb cc dd
[root@localhost ~]# array1[1]=20
[root@localhost ~]# echo ${array1[@]}
aa 20 cc dd
5.数组的删除
利用命令unset 对数组索引指定的元素进行删除
[root@localhost ~]# echo ${array1[@]}
aa 20 cc dd
[root@localhost ~]# unset array1[1]
[root@localhost ~]# echo ${array1[@]}
aa cc dd
6.数组切片
格式:${数组名[@]:索引开始:索引结束}
[root@localhost ~]# echo ${array3[@]}
ee ff gg hh aa bb cc dd
[root@localhost ~]# echo ${array3[@]:1:4}
ff gg hh aa
shell流程控制
If语句
脚本中常见的逻辑判断运算符:
-f 判断文件是否存在 eg: if [ -f filename ];
-d 判断目录是否存在 eg: if [ -d dir ];
-eq 等于,应用于整型比较 equal;
-ne 不等于,应用于整型比较 not equal;
-lt 小于,应用于整型比较 letter;
-gt 大于,应用于整型比较 greater;
-le 小于或等于,应用于整型比较;
-ge 大于或等于,应用于整型比较;
-a 双方都成立(and) 逻辑表达式 –a 逻辑表达式;
-o 单方成立(or) 逻辑表达式 –o 逻辑表达式;
-z 空字符串;
-x 是否具有可执行权限
|| 单方成立;
&& 双方都成立表达式。
1.不带有else
基础结构:
if 判断语句; then
command
fi
编辑脚本
[root@localhost ~]# vi if1.sh
#!/bin/bash
a=10
if [ $a -gt 4 ] #这里的gt为英文单词greater than(大于)
then
echo ok
fi
执行脚本:
2. 带有else(相当于否则的意思)
基础结构:
if 判断语句 ; then
command
else
command
fi
编写脚本if2.sh
[root@localhost ~]# vi if2.sh
#!/bin/bash
a=10
if [ $a -gt 4 ]
then
echo ok
else
echo "not ok"
fi
执行脚本
3.带有elif(相当于再则的意思)
编辑脚本if3.sh
[root@localhost ~]# vi if3.sh
#!/bin/bash
a=3
if [ $a -gt 4 ]
then
echo ok
elif [ $a -gt 8 ]
then
echo "very ok"
else
echo "not ok"
fi
执行脚本:
4.嵌套(if语句里再添加if语句)
编辑脚本if4.sh
[root@localhost ~]# vi if4.sh
#!/bin/bash
a=10
if [ $a -gt 4 ]
then
if [ $a -lt 20 ]
then
echo "ok"
else
echo "very ok"
fi
else
echo "not ok"
fi
执行脚本:
5.多个条件
[root@localhost ~]# vi if5.sh
#!/bin/bash
read -p "请输入小明的数学成绩:" a
read -p "请输入小李的数学成绩:" b
if [ $a -gt 60 ] && [ $a -lt 90 ]
then
echo "优秀"
if [ $b -lt 60 ]
then
echo "小明对小李说:“:别灰心,下次争取及格”"
else
echo "小李对小明说:“哈哈,我终于及格了”"
fi
elif [ $a -gt 90 ]
then
echo "非常优秀"
else
echo "不合格"
fi
执行脚本:
6.if逻辑判断
shell脚本中if经常用于判断文档的属性,比如判断是普通文件还是目录,判断文件是否有读、写、执行权限等。If常用选项如下:
-e:判断文件或目录是否存在。
-d:判断是不是目录以及是否存在。
-f:判断是不是普通文件以及是否存在。
-r:判断是否有读权限。
-w:判断是否有写权限。
-x:判断是否可执行。
-h: file hard link(链接文件)
-L :file link(链接文件)
-b :file 块设备文件
-c :file 字符设备文件
-p :file 管道文件
-S :file socket套接字文件
-t :file 文件与终端相关联
-N :file文件最后一次读取后被修改过
-s :file 文件大小不为0,文件存在且非空
-z:判断是否为空字符串
-n:判断是否为非空字符串
注意:root用户对文件的读写比较特殊,即使一个文件没有给root用户读或者写的权限,root也可以读或者写。
这里举一些常见的参数的例子:
[root@localhost ~]# vi test.sh
#!/bin/bash
if [ -d /etc ]; then
if [ -f if1.sh ]; then
if [ -r if1.sh ]; then
if [ ! -w if1.sh ]; then # !-W 表示数学中的非,即本为ture,非本则为false
echo "文件不具有写权限"
else
echo "文件具有写权限"
fi
echo "文件具有读权限"
else
echo "文件不具有读权限"
fi
echo "文件存在"
else
echo "文件不存在"
fi
echo "目录存在"
else
echo "目录不存在"
fi
执行脚本
7.shell中的case判断
case判断的基础格式如下:
case 变量 in
value1) #不限制value的个数
command
;; #一个分支的结束
value2)
command
;;
*) #此处*代表其他值
command
;;
esac
在Shell脚本中,case语句是一种多路选择结构,它允许一个变量等于多个值时分别执行不同的操作。case语句以case关键字开始,以esac(case的反写)关键字结束。
为了让我们能够更加清晰的理解case逻辑判断,接下来我们编写一个脚本来进行实验:
[root@localhost ~]# vi case.sh
#!/bin/bash
read -p "Please input a number:" n
if [ -z "$n" ]
then
echo "Please input a number."
exit 1
fi
if [ $n -lt 60 ] && [ $n -ge 1 ]
then
tag=1
elif [ $n -ge 60 ] && [ $n -lt 80 ]
then
tag=2
elif [ $n -ge 80 ] && [ $n -lt 90 ]
then
tag=3
then
tag=4
else
tag=0
fi
case $tag in #$tag匹配为1,输出not ok
1)
echo "not ok"
;;
2)
echo "ok"
;;
3)
echo "very ok"
;;
4)
echo "very good"
;;
*) #$tag匹配除前面1,2,3,4以外的数。
elif [ $n -ge 90 ] && [ $n -le 100 ]
echo "The number range is 0-100."
;;
esac
执行脚本:
Shell中的循环
1. for循环
基础结构如下:
for 变量名 in 循环条件;
do
command
done
这里我们写一个99乘法表
[root@localhost ~]# vi for.sh
#!/bin/bash
for ((i=1;i<=9;i++ ));do #定义i的初始值为1,且这个值不大于9,每次循环加1
for (( j=1;j<=$i;j++ ));do
echo -n -e "$j*$i=$(( $j * $i ))\t" #-n 表示不换行打印,\t表示制表符,属于转义字符,-e的作用就是使转义字符能够被解释
done
echo
done
这里不执行过程了,直接执行结果
这里既然提到了转义字符,那就进行讲解一下吧
2.转义字符
2.1 符号的介绍与对比
美元符号 $:主要用于引用变量值,例如定义变量MXS=xiaoming,引用时,需要用 $MXS;
\反斜杠:主要是用于对特定的字符实现转义,保留原有意义,例如echo “\$MXS”结果会打印$MXS,而不会打印xiaoming;
单引号' ':单引号又称为强引,不具有变量置换的功能,所有的任意字符还原为字面意义,实现屏蔽Shell元字符的功能;有些时候跟反斜杠的用法相似
双引号" ":双引号又称为弱引,具有变量置换的功能,保留$(使用变量前导符), \(转义符), `(反向引号)元字符的功能;
反向引号``:反引号,位于键盘Tab键上面一行的键,用作命令替换(相当于$(…))。
2.2单引号和双引号的区别
变量展开:
- 单引号字符串中的变量不会被展开,将原样输出。例如,echo ‘Hello $name’ 输出结果为 “Hello $name”。
- 双引号字符串中的变量会被展开为其对应的值。例如,echo “Hello $name”,如果变量 name 的值为 “xiaoming”,则输出结果为 “Hello xiaoming”。
转义字符的处理:
- 在单引号字符串中,转义字符(例如 \n、\t)仅被视为普通字符,不会被特殊处理。
- 在双引号字符串中,转义字符会被解释,并按照其含义进行替换。例如,echo “Hello\tWorld” 输出结果为 “Hello World”,其中 \t 被解释为制表符。
.2.3 转义符
转义符在shell脚本中用于解决特殊字符的处理问题。当需要在字符串中插入具有特殊含义的字符时,可以使用转义符来取消其特殊含义,将其视为普通字符。
在shell脚本中,常见的转义符是反斜杠(\),其后跟着需要进行转义的字符。
常用的转义符
\n:换行符
\t:制表符
\":双引号
\':单引号
\\:反斜杠
\$:美元符号
```:反引号
3.While循环
基础结构:
while 条件; do
command
done
用while循环制作99乘法表
[root@localhost ~]# vi while.sh
#!/bin/bash
i=1
while (( $i<=9 ))
do
j=1
while (( $j<=$i ))
do
echo -ne "$i*$j=$((i * j))\t"
let j++ # let为赋值表达式,即j++ 《=》j=j+1
done
let i++
echo "" # 这步操作在于换行
done
执行脚本
我们知道while循环是死循环,会一直重复执行,会造成内存的损失,于是就出现了3个命令break(跳出整个循环)和continue(跳出本次循环),exit(跳出整个脚本)
4.Shell中的中断和继续
4.1 continue(继续)
当在shell脚本中使用continue时,结束的不是整个循环,而是本次循环。忽略continue之下的代码,直接进行下一次循环。
[root@localhost ~]# vi continue.sh
#!/bin/bash
for i in `seq 1 5 ` #``为命令的替换,把命令seq 1 5 的结果赋值给i,seq 1 5 表示从1取到5
do
echo $i
if [ $i == 3 ]
then
continue #此处continue表示若 $i == 3 则结束本次循环
fi
echo $i
done
执行脚本:
4.2 break (终止)
[root@localhost ~]# vi break.sh
#!/bin/bash
for i in `seq 1 5 ` #``为命令的替换,把命令seq 1 5 的结果赋值给i,seq 1 5 表示从1取到5
do
echo $i
if [ $i == 3 ]
then
break #此处continue表示若 $i == 3 则结束整个循环
fi
echo $i
done
执行代码:
Shell中的函数
shell脚本中的函数就是先把一段代码整理到了一个小单元中,并给这个小单元命名,当我们用到这段代码时直接调用这个小单元的名字就可以了,这样很方便,省时省力。但我们需要注意,在shell脚本中,函数一定要写在前面,因为函数要被调用的,如果还未出现就被调用就会出错。
执行Shell函数,直接写函数名即可,无需添加其他内容
函数必须先定义,再执行,Shell脚本自上而下加载
函数体内定义的变量,称之为局部变量
函数内,使⽤local关键字,定义局部变量
函数体内需要添加return语句,作⽤是退出函数,且赋予返回值给调⽤该函数的程序
return语句和exit不同
return:结束函数的执⾏,返回⼀个(退出值、返回值)
exit:结束Shell环境,返回⼀个(退出值、返回值)给当前的shell
Shell 函数优缺点
Shell 函数在脚本编写中既有优点也有缺点。以下是关于 Shell 函数的一些优缺点:
优点:
代码重用:Shell 函数允许你将一段代码块封装起来,并在脚本的多个地方重复使用。这减少了代码冗余,提高了脚本的可维护性。
模块化:通过将脚本的不同部分划分为不同的函数,你可以实现代码的模块化。这有助于组织代码,使得每个函数都专注于执行特定的任务。
简化复杂操作:对于复杂的命令或命令序列,你可以将它们封装成一个函数,并通过一个简单的调用来执行。这使得脚本更加简洁易读。
参数化:Shell 函数可以接受参数,这使得函数更加灵活,可以根据不同的需求执行不同的操作。
错误处理:你可以在函数中编写错误处理逻辑,以便在出现问题时能够优雅地处理并继续执行脚本。
可维护性:通过定义函数,你可以将相关的代码组织在一起,并为函数提供一个描述性的名称。这有助于其他开发人员理解脚本的结构和功能,提高了脚本的可维护性。
缺点:
性能开销:尽管这通常不是一个大问题,但频繁地调用小函数可能会导致一些性能开销,尤其是在处理大量数据时。这是因为函数调用本身涉及到一些额外的步骤,如参数传递和堆栈操作。
依赖外部环境:Shell 函数依赖于它们被执行的外部环境。如果脚本在不同的环境中运行,或者环境变量和路径设置发生变化,函数的行为可能会受到影响。
调试困难:与完整的编程语言相比,Shell 脚本的调试工具可能相对有限。当函数出现问题时,调试可能会变得相对困难,尤其是在复杂的脚本中。
功能限制:Shell 脚本本身的功能相对有限,尤其是在处理复杂的数据结构和算法时。虽然可以通过调用外部程序或工具来扩展其功能,但这可能会增加额外的复杂性和依赖性。
函数有两种格式:
基础格式:
函数名() #定义函数
{
函数体
}
函数名 #函数的调用
标准格式:
function 函数名() {
函数体(即命令序列)
[return 返回值] # 返回值是可选的,用于从函数中返回一个值
}
函数名
编辑一个可以打印第一、第二个参数、参数的个数及脚本名的函数脚本
[root@localhost ~]# vi function.sh
#/bin/bash
input()
{
echo $1 $2 $# $0 # 函数的参数:$1 $2 $#是参数的个数 $0则是脚本的名字
}
input 1 a b # 传参和调用形势类似于在命令行中给一个脚本传入参数
执行脚本
Shell中正则表达式
概述
正则表达式是你所定义的模式模板, Linux工具可以用它来过滤文本。 Linux 工具(比如sed编辑器或gawk程序)
能够在处理数据时使用正则表达式对数据进行模式匹配。如果数据匹配模式,它就会被接受并进一步处理;
如果数据不匹配模式,它就会被滤掉。
它主要用于字符串的分割,匹配、査找及替换操作。即正则表达式是一种文本模式,该模式描述在搜索文本时要匹配的一个或多个字符串
简单来说就是通过一些特殊字符的排序,用以删除、查找、替换一行或者多行文字字符串的程序。
1.基础正则:
基础正则常见元字符(支持的工具:grep、egrep、sed、awk)
\ :转义字符,用于取消特殊符号的含义,例:\! 、\n、\$等
^ :匹配字符串开始的位置,例:^a、^the、^#、^[a-z]
$ :匹配字符串结束的位置,例: word$、 ^$匹配空行
*:匹配除\n之外的任意的一个字符,例: lo.*k、lo.k、l..k
.*:匹配任意长度的字符
+:匹配前面的字符出现过最少一次
\{n\} : 匹配前面一个字符n次,例: lo\{2\}k、 '[0-9]\{2\}'匹配两位数字
\{n,\} : 匹配前面一个字符不少于n次,例: lo\{2,\}k、 '[0-9]\{2,\}'匹配两位及两位以上数字
\{n,m\} : 匹配前面一个字符n到m次,例: lo\{2,3\}k、 '[0-9]\{2,3\}'匹配两位到三位数字
注: egrep、 awk使用{n}、{n,}、 {n, m}匹配时“{}"前不用加“\”
2.常用命令
Sort排序:
以行对文件进行排序
可以通过linux自带的man手册去查看更多的命令
-f | 忽略大小写,会将小写字母都转换为大写字母来进行比较 |
-b | 忽略每行前面的空格 |
-n | 按照数字进行排序 |
-r | 反向排序 |
-u | 等同于uniq,表示相同的数据仅显示一行 |
-t | 指定字段分隔符,默认使用[Tab]键分隔 |
-k | 指定排序字段 |
-o<输出文件> | 将排序后的结果转存至指定文件 |
-h | 友好显示 |
相信强悍的学习能力举一个例子就够了
查看一些常用命令可用 命令 –help
- tac:倒序打印文件
- rev:反向打印每一行
- cut:字符切割,常用选项-d 分割,-f输出第几段
- tr:替换或删除字符
- seq:打印序列化数字
- uniq:去重 -c 打印出现次数、-u :打印不重复的行
3.三剑客之grep
概念:
grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。egrep是grep的扩展,支持更多的re元字符, fgrep就是fixed grep或fast grep,它们把所有的字母都看作单词,也就是说,正则表达式中的元字符表示回其自身的字面意义,不再特殊。linux使用GNU版本的grep。它功能更强,可以通过-G、-E、-F命令行选项来使用egrep和fgrep的功能。
参数:
- -i:忽略大小写
- -c:统计匹配到字符串的次数
- -n:顺便输出行号
- -v:反向选择,显示没有匹配到的内容
- -o:只显示匹配到的串
- -A:显示匹配到的字符后面的n行
- -B:显示匹配到的字符前面的n行
- -C:显示前后各n行
这里举一个-v参数的实例即可:
4.三剑客之sed
概念:
sed是一种流编辑的文本处理工具, * 工作模式:将当前处理的行存储在临时缓冲区(模式空间),对缓冲区中的内容利用制定的动作进行处理,完成后输出到屏幕,接着反复重复执行此操作完成整改文件的处理
注:默认情况下所有sed命令都是在模式空间内执行的,因此输入的文件并不会发生任何变化,
除非是用重定向存储输出或者sed -i
参数:
-n | 不输出模式空间内容,即不自动打印,加p恢复自动打印 |
-e | 多点编辑 |
-f | 从指定文件中读取编辑脚本 |
-r -E | 使用扩展正则表达式 |
-i | 备份文件并原处编辑 |
Sed命令操作:
s:替换,替换指定字符
d:删除,删除选定的行
a:增加,在当前行下面增加一行指定内容
i:插入,在选定行上面插入一行指定内容
c:替换,将选定行替换为指定内容
Y:字符转换,转换前后的字符长度必须相同
P:打印,如果同时指定行,表示打印指定行;如果不指定行,则表示打印所有内容;如果有非打印字符,则以ASCII码输出。其通常与"-n"选项一起使用
=:打印行号
l: 打印数据流中的文本和不可打印的ASCII字符(比如结束符$、制表符\t)
修饰符:
g: 全局替换
i: 忽略字符大小写
sed的格式:
一般是sed -参数 操作命令 文件路径
1 打印输出的全部内容
进入交互模式,输出一行,终端自动打印一行
[root@localhost ~]# sed ""
1
1
2
2
3
3
4
4
^C
2打印文件指定内容:
-n是参数,p是命令操作,通常一起使用
P前面可以加数字,指定第几行,也可以加关键字打印具有关键字的行。
3插入指定内容:
-i为参数,a为操作命令,意思为当前行的下一行进行插入,6a即是在第7行插入
4替代操作:
Linux中会经常关闭selinux,这里修改selinux开机不自启配置文件
5.三剑客之awk
概述:
awk是一种处理文本文件的语言,是一个强大的文本分析工具,可以在无交互的模式下实现复杂的文本操作,相较于sed常作用于一整个行的处理,awk则比较倾向于一行当中分成数个字段来处理,因为awk相当适合小型的文本数据
awk的格式:awk -参数 ‘{操作命令 字符串/内建变量}’
打印字符串需要加双引号
awk常见内建变量:
FS:列分隔符,指定每行文本的字段分隔符,默认为空格或制表位,与-F作用相同
NF:当前处理的行的字段个数
NR :当前处理的行的行号(序数)
$0:当前处理的行的整行内容
$n:当前处理行的第n个字段(第n列)
FILENAME 被处理的文件名
RS:行分隔符。awk从文件上读取资料时,将根据RS的定义把资料切割成许多条记录,而awk一次仅读入一条记录,以进行处理。预设值是’\n’
$NF:最后一段
$(NF-1):倒数第二段
1.打印字符串
原本文件具有多少行,他就会把它全部打印下来
2.打印磁盘已经使用情况
$n表示打印那一列
3. awk根据$n已经NR提取字段
NR表示要处理的行数,NR==9表示第九行
4. awk根据选项-F指定分隔符
-F=FS,通过指定分隔符,不指定默认为空格,将提取的字段打印
5.awk根据关键字提取所在行
/root/表示需要查询的关键字为root,以:作为分隔符。
其余几个内建变量与上述操作大致相同