全网超详细shell(包含正则表达式三剑客),带你快速入门

前言

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环境中执行)。

  1. 工作目录执行,指的是执行脚本时,先进入到脚本所在的目录(此时,称为工作目录),然后使用 ./脚本方式执行
[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

可以看到脚本执行成功了

0ce0ec83dea14bed8cb3b83f827bb989.png

  1. 绝对路径执行,指的是直接从根目录/到脚本目录的绝对路径
[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          #一年中的第几周

9325ec2b390b412c9287613ac99c3773.png

4.时间戳

使用命令date +%s 显示从 1970 年 1 月 1 日 00:00:00  到目前为止的秒数。

[root@localhost ~]# date +%s

1728371644

使用date -d @1728371644显示输入描述前的时间

0ca3120e30d740e1918a41be0cdbe196.png

5. 显示一个小时之前/之后

date -d "+1 hour"    #一个小时后

date -d "-1 hour"    #一个小时前

517800767e284b859677cba0e143a0f9.png

6. 表示一天之前/之后

date -d "+1day"     #一天后

date -d "-1 day"     #一天前

265683d347cd463097022420f2eb8019.png

历史命令

当我们在linux中执行命令时,执行过的每一条命令都会被保存到家目录的.bash_history文件中,需要注意的是:只有当用户正常退出当前shell时,在当前shell中运行的命令才会保存至.bash_history文件中

History命令

查看所有历史命令列表:

退出终端这些历史命令会被清除

4110cb8a9f9a409d8e24c8b47a635b8d.png

查看指定历史命令:

通过管道的形式来查看指定历史的命令

4b2bf3bd2d50486b91a37d9aa1d909ac.png

清除历史命令:

395377247dfe4580af527942e3812245.png

History命令更多的参数操作可以参考history命令手册

通过man history 命令实现

3b4db94063aa43b5a6fe9ebaa017f429.png

自动补全以及别名

1.自动补全:

在命令行输入命令或者文件名/目录名时,只需要填写前面几个文字后,按下键盘上面的“Tab”键,即可自动补全。当你填写的文件名有多个在同一目录时,按两下键盘的“Tab”键,会把有部分相同之处的都显示出来

2.别名:

别名的作用:别名是Shell中的一个功能,它可以让你为常用的命令设置一个简短易记的替代名称。当你输入这个别名时,Shell会自动替换为对应的命令,从而简化命令的输入和记忆

别名的语法:在Shell中,创建别名的语法为:alias 别名='命令'。其中,别名是你要设置的简短名称,命令则是你想要关联的完整命令。

临时创建别名:

7b497cc5286c43b6b07fc6a2b420119b.png

只需要刷新一下shell解释器就会恢复原本的命令

5eafe1e2c8b548bca86bc45e1d241145.png

删除别名:

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. 输出重定向>:若是指定文件不存在则创建一个文件并指向该文件。若是指定文件存在则先清空该文件,再指向该文件

查看要输出的文件,将它写入1.txt,不存在则自动创建

输入重定向及追加重定向操作与下面类似

c6d44bf6e4eb40319e15e7cd632c405e.png

  1. 输入重定向<:从指定文件读取数据
  2. 追加重定向>>:若是指定文件不存在则创建一个文件并指向该文件。若是指定文件存在则直接指向该文件,不会进行清空

2.管道:

管道是可以串联多条命令的,每条命令的结果输出,都作为输入,导入下一条命令。

简单来说就是前面的命令限定范围,后面的命令在这个范围里进行该命令特定的动作

比如我下面的这条命令,即在查看1.sh这个范围里,通过查询echo这个关键字,找到在1.sh里的具有echo关键字的关键行

5eb9630fff234c278d3ca0abe8e45a03.png

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 "命令的最后一个参数为:$_"

执行脚本:

c7218df5e5ab4171ad4fed3f7db9966b.png

判断上一命令是否执行成功

[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    主机名

这里不过多赘述举一些例子展示

017baffb40e74f188b2f2d2bcd67bf78.png

5.数学运算

创建一个脚本

[root@localhost ~]# vi sum.sh

#!/bin/bash

a=1

b=2

sum=$[$a+$b]          #还可以采用sum=$(($a+$b))这种写法

echo "$a+$b=$sum"

执行脚本

5f6e89da1d314c9393e51f8c9699b371.png

Shell字符串和数组

Shell字符串

定义:

字符串可以由单引号' '包围,也可以由双引号" "包围,也可以不用引号。

三种形式的区别:

1.不被引号包围的字符串:不被引号包围的字符串中出现变量时也会被解析;字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析。

2.由单引号包围的字符串:任何字符都会原样输出,在其中使用变量是无效的;字符串中不能出现单引号,对单引号进行转义也不行。

3.由双引号" "包围的字符串: 如果其中包含了某个变量,那么该变量会被解析,得到该变量的值,而不是原样输出;字符串中可以出现双引号。

1.获取字符串长度:

格式:${#字符串名}

[root@localhost ~]# str1="1234567"

[root@localhost ~]# echo ${#str1}

7
  1. 2.字符串拼接

将两个字符串并排放在一起就能实现拼接。$str1$str2这种写法不允许变量之间有空格,但是只要加上””就可以

[root@localhost ~]# str2="891011"

[root@localhost ~]# str3=$str1$str2

[root@localhost ~]# echo $str3

1234567891011
  1. 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
  1. 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

执行脚本:

4d06a09ba4934fb4891bbeb04442320e.png

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

执行脚本

45817d831d8f4903bb28b20f8acb512f.png

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

执行脚本:

63ee92871b0a41948af0f73172ffe635.png

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

执行脚本:

2873a15fc88a4d0d88961c8fa1099ba7.png

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

执行脚本:

3ed6d3fe862148ffa0e06a7425ad5930.png

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

执行脚本

031801f231a14343b42b9389e48e7232.png

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

执行脚本:

6ba3ed75882d4390bea133a4ba8f3783.png

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

这里不执行过程了,直接执行结果

9cb73a1b19d2415690dc10e60ae635ac.png

这里既然提到了转义字符,那就进行讲解一下吧

2.转义字符

2.1 符号的介绍与对比

美元符号 $:主要用于引用变量值,例如定义变量MXS=xiaoming,引用时,需要用 $MXS;

\反斜杠:主要是用于对特定的字符实现转义,保留原有意义,例如echo “\$MXS”结果会打印$MXS,而不会打印xiaoming;

单引号' ':单引号又称为强引,不具有变量置换的功能,所有的任意字符还原为字面意义,实现屏蔽Shell元字符的功能;有些时候跟反斜杠的用法相似

双引号" ":双引号又称为弱引,具有变量置换的功能,保留$(使用变量前导符), \(转义符), `(反向引号)元字符的功能;

反向引号``:反引号,位于键盘Tab键上面一行的键,用作命令替换(相当于$(…))。

2.2单引号和双引号的区别

变量展开:

  1. 单引号字符串中的变量不会被展开,将原样输出。例如,echo ‘Hello $name’ 输出结果为 “Hello $name”。
  2. 双引号字符串中的变量会被展开为其对应的值。例如,echo “Hello $name”,如果变量 name 的值为 “xiaoming”,则输出结果为 “Hello xiaoming”。

 转义字符的处理:

  1. 在单引号字符串中,转义字符(例如 \n、\t)仅被视为普通字符,不会被特殊处理。
  2. 在双引号字符串中,转义字符会被解释,并按照其含义进行替换。例如,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

执行脚本

7f363df3a9bb4834a489b3bc05fbec6b.png

我们知道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

执行脚本:

3dfb1118b0e144deaffac3c953a28700.png

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

执行代码:

8e8f9db1ecb64a4c8d43c9fd853d4614.png

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     # 传参和调用形势类似于在命令行中给一个脚本传入参数

执行脚本

1e65a4aed0fe4a0c82c73d16e8532e41.png

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

友好显示

相信强悍的学习能力举一个例子就够了

968b68f38c2a4efb89edb6185cdad7f1.png

查看一些常用命令可用 命令 –help

8687684d086d48dfb6753944a46dc7d7.png

  • 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参数的实例即可:

167630f0bf0a4fa4b8ac2661559a3c58.png

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前面可以加数字,指定第几行,也可以加关键字打印具有关键字的行。

bc1c5ad7917c492fba0361be34ae1011.png

3插入指定内容:

-i为参数,a为操作命令,意思为当前行的下一行进行插入,6a即是在第7行插入

af8e69deb2a24f1291bff801058e71b9.png

4替代操作:

Linux中会经常关闭selinux,这里修改selinux开机不自启配置文件

489fdaab577f4512bba1d571692fd50b.png

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.打印字符串

原本文件具有多少行,他就会把它全部打印下来

c8854ddd92f4473494aea95130263226.png

2.打印磁盘已经使用情况

$n表示打印那一列

5896902b48d64583ae052379a11ee114.png

3. awk根据$n已经NR提取字段

NR表示要处理的行数,NR==9表示第九行

7b5b672242c9409e8966ecb3a8a17d6d.png

4. awk根据选项-F指定分隔符

-F=FS,通过指定分隔符,不指定默认为空格,将提取的字段打印

036534b8b15e484cbf161183a2a0e255.png

5.awk根据关键字提取所在行

/root/表示需要查询的关键字为root,以:作为分隔符。

9567294b041743ff9d29aafae0461efa.png

其余几个内建变量与上述操作大致相同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值