Shell 脚本是 Linux/Unix 系统的核心自动化工具,能够完成以下任务:
(1)批量操作:一键安装软件、批量处理文件(重命名、压缩、备份等)。
(2)系统管理:监控资源(CPU、内存、磁盘)、定时任务(cron)、日志分析。
(3)开发辅助:编译自动化、环境配置、CI/CD 流水线集成。

适用读者
(1)零基础初学者,希望掌握 Linux 基础操作。
(2)运维工程师,提升自动化运维能力。
(3)开发人员,优化本地开发环境和工作流程。

一、Shell基础概念

1.1 什么是 Shell?

定义:
Shell 是用户与操作系统内核(Kernel)之间的命令行接口,负责解析用户输入的命令并调用系统功能。

核心作用:
(1)执行命令和脚本
(2)管理进程和文件系统
(3)环境变量管理
(4)自动化任务处理

1.2 Shell 类型与选择

# 查看系统支持的 Shell
cat /etc/shells
# 典型输出:
# /bin/sh
# /bin/bash
# /usr/bin/zsh
# /bin/dash

常见 Shell 对比:

Shell 类型特点
BashLinux 默认 Shell,支持历史命令、自动补全、数组等扩展功能
Zsh强大的交互式 Shell,支持主题和插件(如 Oh My Zsh)
Dash轻量高效,适合系统启动脚本(Ubuntu 的 /bin/sh 默认指向 Dash)
Ksh兼容 POSIX 标准,适合商业环境

1.3 脚本执行方式

方式1:sh执行,指的是用脚本对应的sh或bash来接着脚本执行

bash script.sh

方式2: 工作目录执行,指的是执行脚本时,先进入到脚本所在的目录(此时,称为工作目录),然后使用 ./脚本方式执行

[root@localhost shell]# ./9*9.sh
-bash: ./1.sh: Permission denied
[root@localhost shell]# chmod +x 9*9.sh    //赋予权限  x代表执行权限
[root@localhost shell]# ./9*9.sh        //执行脚本

方式3:shell环境执行,指的是在当前的shell环境中执行,可以使用 . 接脚本 或 source 接脚本

source script.sh

方式4:绝对路径执行,指的是直接从根目录/到脚本目录的绝对路径

/root/script.sh

二、shell基础命令

2.1 基础命令

(1)查看脚本执行过程

[root@localhost shell]# bash -x 9*9.sh
++ seq 9
+ for i in '`seq 9`'
++ seq 1
+ for j in '`seq $i`'
+ printf '1*1=%2d ' 1
1*1= 1 + echo ''

(2)查看脚本是否有语法错误

[root@localhost shell]# bash -n 9*9.sh

2.2 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)显示星期

[root@shell ~]# date +%w
5
[root@shell ~]# date +%W
41

(4)时间戳

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

[root@shell ~]# date +%s
1728608466

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

[root@shell ~]# date -d@1728608466
20241011日 星期五 09:01:06 CST

(5)显示一个小时之前、后

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

(6)显示一天之前、之后

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

2.3 重定向及管道

前言:标准流

文件描述符名称默认目标
0标准输入键盘
1标准输出屏幕
2标准错误屏幕

1.输出重定向(>和>>)

1.1标准输出重定向(>)

作用:将命令的标准输出重定向到文件。如果文件不存在,则创建文件;如果文件存在,则覆盖原有内容。

示例1:ls -l > file_list.txt,此命令会将ls -l(列出文件详细信息)的输出结果保存到file_list.txt文件中。如果file_list.txt之前有内容,会被覆盖。

实例2:在script.sh脚本中,将echo命令的输出重定向到一个文件。
在这里插入图片描述

1.2标准输出追加重定向(>>)

作用:将命令的标准输出追加到文件末尾。如果文件不存在,则创建文件。

示例:echo “New line” >> log.txt,会将字符串 “New line” 添加到log.txt文件的末尾。

1.3标准错误重定向(2>)

作用:将命令执行过程中产生的标准错误输出重定向到文件。

示例:grep non_existent_pattern file.txt 2> error.log,当grep命令在file.txt中找不到指定模式时,产生的错误信息会被保存到error.log文件中,而不是显示在终端。

1.4标准错误追加重定向(2>>)

作用:将标准错误输出追加到文件末尾。

示例:在一个循环执行可能出错的命令脚本中,for i in $(seq 1 5); do command_that_might_fail 2>> error_accumulate.log; done,每次循环中命令产生的错误信息都会被追加到error_accumulate.log文件中。

1.5合并标准输出和标准错误重定向(&> 或 >&)

作用:将命令的标准输出和标准错误输出同时重定向到一个文件。

示例:find. -name “*.bak” &> output_and_error.log,find命令的所有输出(包括正常输出和可能出现的错误输出)都会被保存到output_and_error.log文件中。

2.输入重定向(<)

用法:将文件的内容作为命令的输入。

示例 1:
假设有一个input.txt文件,内容为一些数字 “1 2 3 4 5”,使用sort命令对这些数字进行排序,通过输入重定向来读取文件内容作为输入。
在这里插入图片描述
运行脚本后,会输出排序后的数字 “1 2 3 4 5”。如果没有输入重定向,sort命令会等待用户从键盘输入内容进行排序。

示例 2:使用wc -l命令(用于统计行数)来统计text_file.txt文件的行数,通过输入重定向。
在这里插入图片描述

3. 管道和重定向结合(|和>或>>)

用法:管道(|)用于将一个命令的输出作为另一个命令的输入,再结合重定向可以进一步处理输出结果。

1.保存管道中间结果并继续处理:
示例:cat data.txt | grep “important” > intermediate_result.txt,这个命令先通过cat和grep组合从data.txt中筛选出包含 “important” 的行,然后将这些筛选后的结果保存到intermediate_result.txt文件中。之后可以对这个文件进行其他操作,如sort intermediate_result.txt。

2.实时处理并记录结果:
示例:tail -f access.log | grep “404” > error_404.log,tail -f access.log会实时跟踪access.log文件的新增内容,通过管道将这些内容传递给grep命令来查找包含 “404” 的行,然后将这些行保存到error_404.log文件中,用于实时监控网站的 404 错误。

3.复杂数据处理流程:
示例:find. -type f -name “*.txt” -exec cat {} ; | awk ‘{print $1}’ | sort | uniq -c > result.txt,这个命令首先使用find命令查找当前目录下所有的.txt文件,并将这些文件的内容通过cat命令输出,然后通过管道将这些内容传递给awk命令提取每行的第一个字段,接着进行排序和去重统计,最后将结果重定向到result.txt文件中,用于分析.txt文件内容的第一个字段的统计信息。

示例 1:
先使用cat命令读取file.txt文件内容,然后通过管道将输出传递给grep命令来查找包含特定单词(如 “error”)的行,最后将结果覆盖写入到error_lines.txt文件。
在这里插入图片描述

示例 2:
先使用ps -ef命令获取所有进程信息,然后通过管道将输出传递给grep命令查找包含特定进程名(如 “httpd”)的行,最后将结果追加到process_log.txt文件。
在这里插入图片描述

三、变量与数据类型

3.1 变量操作

(1) 定义与赋值

name="John"         # 字符串(等号两侧不可有空格)
count=42            # 整型
files=$(ls)         # 命令替换赋值
readonly PI=3.14    # 只读变量

(2) 变量引用与删除

echo $name # 输出变量值
echo ${name} # 推荐写法(明确变量边界)
unset name # 删除变量

(3)与用户交互

这里相当于把用户交互时写的值赋予给变量n

[root@shell ~]# read -p "请输入一个数字:" n
请输入一个数字:20
[root@shell ~]# echo $n
20

由于没有创造一个变量接收值,系统默认变量REPLY

[root@shell ~]# read -p "请输入一个数字:"
请输入一个数字:30
[root@shell ~]# echo $REPLY
30

3.2 变量作用域

类型定义方式作用范围生命周期
局部变量var=value当前 Shell 进程进程结束销毁
环境变量export var=value当前进程及其子进程进程结束销毁
永久变量写入配置文件所有新启动的 Shell系统重启有效

环境变量配置文件:
(1)用户级:~/.bashrc, ~/.bash_profile
(2)系统级:/etc/profile, /etc/environment
(3)以上配置文件定义变量不是实时生效,需要resource刷新一下

3.3 特殊变量

变量描述
$0当前脚本名称
$1-$9脚本参数(第1到第9个)
${10}位置参数10
$#参数个数
$*所有参数(合并为一个字符串),整体作为单个字符串
$@所有参数(保留原始分隔符),每个作为单独字符串
${#*}传递到脚本中的命令行参数的个数
$?返回值,用于判断前一命令是否执行成功,0为成功,1则失败
$$当前进程 PID
$-传递到脚本中的标识
$_之前命令的最后一个参数
$!运行在后台的最后一个作业的进程ID(PID)

示例:

[root@localhost ~]# vi cbd.sh
#!/bin/bash
echo "$1"
echo "第二个参数是$2"
echo "第三个参数是$3"
echo "本脚本一共有$#个参数"
echo "所有位置参数(作为单个字符串)为:"$*""
echo "所有位置参数每个作为单独字符串)为:"$@""
echo "$0"
echo "脚本中的命令行参数的个数为:${#*}"
echo "脚本中的标识为:$-"
echo "命令的最后一个参数为:$_"

在这里插入图片描述
判断上一命令是否执行成功

[root@shell ~]# echo $?
0

3.4 系统变量

变量描述示例值使用场景
$PATH可执行文件搜索路径。命令所示路径,以冒号为分割;/usr/bin:/usr/local/bin添加自定义命令路径:export PATH=$PATH:/myapp
$HOME当前用户主目录/home/user快速访问家目录:cd $HOME
$USER当前用户名john日志记录:echo “User: $USER”
$PWD当前工作目录/var/www获取脚本所在目录:cd $(dirname $0)
$SHELL当前使用的 Shell 路径/bin/bash检查 Shell 类型:echo $SHELL
$LANG系统语言设置en_US.UTF-8设置脚本输出语言:export LANG=C
$RANDOM生成随机数(0-32767)15872创建临时密码:passwd=$(echo $RANDOM
$SECONDS脚本已运行时间(秒)30计算执行耗时:echo “耗时: $SECONDS 秒”
$BASH_VERSIONBash 版本信息5.1.16(1)-release检查 Bash 特性兼容性
[root@shell ~]# echo $SHELL                #显示当前Shell类型;
/bin/bash
[root@shell ~]# echo $PATH                  #命令所示路径,以冒号为分割;
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@shell ~]# echo $PWD                   #显示当前所在路径;
/root
[root@shell ~]# echo $RANDOM          #随机生成一个 0 至 32767 的整数;
7532

四、运算符与运算

4.1 算术运算

a=10 b=3
# 方式1:$(( ))
echo $((a + b))      # 13
# 方式2:expr(需空格)+ , - , \*,  /,  %    加,减,乘,除,取余
expr $a + $b        # 13
# 方式3:let
let "c = a * b"
echo $c             # 30
# 方式4:bc(浮点运算)
echo "scale=2; 10/3" | bc  # 3.33
# 方式5:[]
echo $[a+b]

4.2 比较运算符

(1) 数值比较

运算符描述示例
-eq等于[ $a -eq 10 ]
-ne不等于[[ $a -ne 5 ]]
-gt大于[ $b -gt 2 ]
-lt小于[ $b -lt 2 ]
-ge大于等于[ $b -ge 2 ]
-le小于等于[ $b -le2 ]

(2) 字符串比较

str1="hello"
str2="world"
[ "$str1" = "hello" ]   # 等于
[[ "$str1" != "$str2" ]] # 不等于
[ -z "$str" ]           # 判断空字符串

(3) 文件测试

[ -f "file.txt" ]    # 是普通文件
[ -d "/tmp" ]        # 是目录
[ -x "/usr/bin/git" ] # 可执行

4.3 逻辑运算符

# 逻辑与(&&)
[ $a -gt 5 ] && [ $b -lt 10 ]
# 逻辑或(||)
[[ -f "file" ]] || echo "文件不存在"
# 逻辑非(!)
if ! [ -d "/tmp" ]; thenmkdir /tmp
fi

五、字符串和数组

5.1 Shell字符串

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

三种形式的区别:

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

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

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

a. 获取字符串长度:

${#字符串名}

[root@shell ~]# rzc1="123456"
[root@shell ~]# echo ${#rzc1}
6

b.字符串拼接

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

[root@localhost ~]# rzc2="8910jqk"
[root@localhost ~]# rzc3=$rzc1$rzc2
[root@localhost ~]# echo $rzc3
12345678910jqk

c. 字符串截取

shell截取字符串通常有两种方式:从指定位置开始截取和从指定字符(子字符串)开始截取。
(1)从左边开始计数时,起始数字是0(这符合程序员思维);从右边开始计数时,起始数字是1(这符合常人思维)。计数方向不同,起始数字也不同。

(2)不管从哪边开始计数,截取方向都是从左到右。且截取的原则为[ ),即左闭右开

使用指定位置从左边开始截取:

[root@shell ~]# echo ${rzc1:2:2}       #2代表从左往右数第二个数   2代表输出两个数
34
[root@shell ~]# echo ${rzc1:1:2}      #1 从左往右数第一个数   2 输出两个数字
23
[root@shell ~]# echo ${rzc1:1:4}
2345

使用指定位置从右边开始截取:

[root@shell ~]# echo ${rzc1:0-3:2}
45
[root@shell ~]# echo ${rzc1:0-4:2}
34

使用字符指定从左边开始截取:

使用#号可以截取指定字符(或者子字符串)右边的所有字符。

*是通配符的一种,表示任意长度的字符串。*字符3连起来使用的意思是:忽略左边的所有字符,直到遇见字符3(3字符不会被截取)。

[root@shell ~]# echo ${rzc1#*3}
456

使用字符指定从右边开始截取:
使用%号可以截取指定字符(或者子字符串)左边的所有字符。
注意的位置,因为要截取字符3左边的字符,而忽略3右边的字符,所以应该位于3的右侧。

[root@shell ~]# echo ${rzc1%3*}
12

5.2 字符串替换

格式:${字符串/要替换的字符/替换的字符}

[root@shell ~]# rzc4="welcome my word"
[root@shell ~]# echo $rzc4
welcome my word
[root@shell ~]# echo ${rzc4/my/you}
welcome you word
str="Hello World"
# 截取子串
echo ${str:0:5}      # Hello
# 替换操作
echo ${str/World/Shell}  # Hello Shell
# 分割字符串
IFS=' ' read -ra parts <<< "$str"
echo ${parts[1]}     # World

5.3 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 ~]#
# 定义数组
colors=("red" "green" "blue")
# 访问元素
echo ${colors[1]}    # green
# 遍历数组
for color in "${colors[@]}"; doecho $color
done
# 关联数组(Bash 4+)
declare -A user=(["name"]="Alice" ["age"]=30)
echo ${user["name"]}  # Alice

2. 获取数组长度

利用@或*,可以将数组扩展成列表,然后使用#来获取数组元素的个数。

[root@localhost ~]# echo ${#array1[@]}
4
[root@localhost ~]# echo ${#array1[*]}
4

3. 数据拼接、合并

Shell数组拼接(数组合并),将两个数组连接成一个数组。拼接数组的思路是:先利用@或*,将数组扩展成列表,然后再合并到一起。

[root@shell ~]# array1=(aa bb cc dd)
[root@shell ~]# echo ${array1[@]}
aa bb cc dd
[root@shell ~]# array2=(ee ff gg hh)
[root@shell ~]# echo ${array2[@]}
ee ff gg hh
[root@shell ~]# array3=(${array2[@]} ${array1[@]})
[root@shell ~]# 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@shell ~]# echo ${array3[@]}
ee ff gg hh aa bb cc dd
[root@shell ~]# echo ${array3[@]:1:4}
ff gg hh aa

六、流程控制

6.1 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  判断语句; thencommand
fi
[root@shell ~]# vi if1.sh
[root@shell ~]# cat if1.sh
#!/bin/bash
a=10
if [ $a -gt 4 ] #这里的gt为英文单词greater than(大于)
then
echo ok
fi
[root@shell ~]# sh if1.sh
ok

在这里插入图片描述

2. 带有else(否则的意思)

基础结构:

if  判断语句  ; thencommand
elsecommand
fi
[root@shell ~]# vi if2.sh
[root@shell ~]# cat if2.sh
#!/bin/bash
a=10
if [ $a -gt 4 ]
thenecho ok
else echo "not ok"
fi
[root@shell ~]# sh if2.sh
ok

在这里插入图片描述

3. 带有elif(相当于再则的意思)

[root@shell ~]# vi if3.sh
[root@shell ~]# cat if3.sh
#!/bin/bash
a=3
if [ $a -gt 4 ]
thenecho ok
elif [ $a -gt 8 ]
thenecho "very ok"
elseecho "not ok"
fi
[root@shell ~]# sh if3.sh
not ok

在这里插入图片描述

4. 嵌套(if句里在添加if语句)

[root@localhost ~]# vi if4.sh
#!/bin/bash
a=15if [ $a -gt 4 ]
thenif [ $a -lt 20 ]
thenecho "ok"
elseecho "very ok"
fielseecho "not ok"
fi

在这里插入图片描述

5. 多个条件

[root@shell ~]# cat if5.sh
#!/bin/bashread -p "请输入任志财的一百米跑步成绩:" a
read -p "请输入王帅的一百米跑步成绩:" bif [ $a -gt 9 ] && [ $a -lt 11 ]
then
echo "任志财对王帅说老弟你还得练”
if [ $b -gt 12 ]
then
echo "王帅对任志财说财哥我错了我再也不敢和你比赛了”
fi[root@shell ~]# sh if5.sh
请输入任志财的一百米跑步成绩:10
请输入王帅的一百米跑步成绩:15
任志财对王帅说老弟你还得练”if [ 15 -gt 12 ]
then
echo 王帅对任志财说财哥我错了我再也不敢和你比赛了”

在这里插入图片描述
在这里插入图片描述

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 ]; thenif [ -f if1.sh ]; thenif [ -r if1.sh ]; thenif [ ! -w if1.sh ]; then  # !-W 表示数学中的非,即本为ture,非本则为falseecho "文件不具有写权限"elseecho "文件具有写权限"fiecho "文件具有读权限"elseecho "文件不具有读权限"fiecho "文件存在"elseecho "文件不存在"fi
echo "目录存在"elseecho "目录不存在"fi

在这里插入图片描述

6.2 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:" nif [ -z "$n" ]thenecho "Please input a number."exit 1fiif [ $n -lt 60 ] && [ $n -ge 1 ]thentag=1
elif [ $n -ge 60 ] && [ $n -lt 80 ]
thentag=2
elif [ $n -ge 80 ] && [ $n -lt 90 ]
thentag=3
thentag=4elsetag=0fi
case $tag in                          #$tag匹配为1,输出not ok1)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

七、循环控制

7.1. for循环

基础结构如下

for 变量名 in 循环条件;
do
command
done

案例:
基础案例

[root@localhost shell]# vi for1.sh
#!/bin/bash
sum=0
for i in `seq 1 10`
dosum=$[$sum+$i]echo $i
done
echo $sum

执行结果:
在这里插入图片描述
进阶案例(9*9乘法表)

[root@shell ~]# vi for2.sh
[root@shell ~]# cat for2.sh
#!/bin/bash
for((i=1;i<10;i++))    #定义i的初始值为1,且这个值不大于9,每次循环加1
dofor((j=1;j<=i;j++))doecho -en "$i*$j=$[i*j]\t" #-n 表示不换行打印,\t表示制表符,属于转义字符,-e的作用就是使转义字符能够被解释        doneechodone

在这里插入图片描述

7.2 while循环

基础结构

while 条件; do
command
done

用while循环制作99乘法表

[root@shell ~]# vi while.sh
[root@shell ~]# cat while.sh
#!/bin/bashi=1while (( $i<=9 ))doj=1while (( $j<=$i ))doecho -ne "$i*$j=$((i * j))\t"let j++    # let为赋值表达式,即j++ 《=》j=j+1donelet i++echo ""    # 这步操作在于换行done

在这里插入图片描述

7.3 跳出循环

break在脚本中表示跳出该层循环,示例如下:

[root@shell ~]# vi break1.sh
[root@shell ~]# cat break1.sh
#!/bin/bash
for i in `seq 1 5` 
doecho $iif [ $i -eq 3 ] thenbreak fiecho $i 
done
echo aaaaa

在这里插入图片描述

7.4 结束本次循环

当在shell脚本中使用continue时,结束的不是整个循环,而是本次循环。忽略continue之下的代码,直接进行下一次循环。示例如下:

[root@shell ~]# vi continue1.sh
[root@shell ~]# cat continue1.sh
#!/bin/bash
for i in `seq 1 5 `
doecho $iif [ $i == 3 ] thencontinue          #此处continue表示若 $i == 3 则结束本次循环fiecho $i 
done 
echo $i

在这里插入图片描述

7.5 退出整个脚本

当我们在shell脚本中遇到exit时,其表示直接退出整个shell脚本。示例如下:

[root@shell ~]#  vi exit1.sh
[root@shell ~]# cat exit1.sh
#!/bin/bash
for i in `seq 1 5`
doecho $iif [ $i == 3 ] thenexit fiecho $i 
done
echo aaaa

在这里插入图片描述
在这里插入图片描述

八、函数

shell脚本中的函数就是先把一段代码整理到了一个小单元中,并给这个小单元命名,当我们用到这段代码时直接调用这个小单元的名字就可以了,这样很方便,省时省力。但我们需要注意,在shell脚本中,函数一定要写在前面,因为函数要被调用的,如果还未出现就被调用就会出错。

基础格式:

function f_name()                  # function 函数名() 
{                                                     #{
Command                                  #  函数体(即命令序列)
}                                                       #}

8.1 打印出第一个、第二个参数、参数的个数及脚本名

示例如下:

[root@shell ~]# vi fun1.sh
[root@shell ~]# cat fun1.sh
#/bin/bash
input()
{
echo $1 $2 $# $0         # 函数的参数:$1 $2 $# ;$0则是脚本的名字
}
input 1 a b[root@shell ~]# sh fun1.sh
1 a 3 fun1.sh

在这里插入图片描述

8.2 加法的函数

[root@shell ~]# vi fun2.sh
[root@shell ~]# cat fun2.sh
#!/bin/bash
sum()
{
s=$[$1+$2]
echo $s
}
sum 1 2

在这里插入图片描述

8.3 获得一个网卡的ip地址

[root@shell ~]# vi fun3.sh
[root@shell ~]# cat fun3.sh
#!/bin/bash
ip()
{
ifconfig |grep -A1 "$1: " |tail -1 |awk '{print $2}'
}
read -p "Please input the eth name: " e
myip=`ip $e`
echo "$e address is $myip"

在这里插入图片描述

8.4 返回值与传参

add() {echo $(($1 + $2))
}
result=$(add 3 5)  # 通过 $? 或命令替换获取结果
echo "3+5=$result"

8.5 函数库封装

math_lib.sh:

#!/bin/bash
square() {echo $(($1 * $1))
}
1
2
3
4

主脚本:

source math_lib.sh
echo "5的平方: $(square 5)"

九、正则表达式

概述

正则表达式是你所定义的模式模板, 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. 常用命令

(1)Sort排序:
以行对文件进行排序
可以通过linux自带的man手册去查看更多的命令
在这里插入图片描述
在这里插入图片描述

(2)查看一些常用命令可用 命令 –help
在这里插入图片描述

tac:倒序打印文件
rev:反向打印每一行
cut:字符切割,常用选项-d 分割,-f输出第几段
tr:替换或删除字符
seq:打印序列化数字
uniq:去重 -c 打印出现次数、-u :打印不重复的行

3. 三剑客(核心)

3.1 grep

1. 功能
筛选过滤出包含<匹配字符串>的<整行>
例如:筛选出以#开头的打印出来
在这里插入图片描述
2.语法

grep [选项]   PATTERN  [FILE....]
PATTERN:就是正则表达式,默认情况下,grep命令使用基本正则

3.选项

-i   表示忽略大小写
[root@shell ~]# grep -i "rzc" grep.sh     # “”里面表示要找的内容  后面加上文件的路径

在这里插入图片描述

-E 表示启用<扩展正则>
,将模式 PATTERN 作为一个扩展的正则表达式来解释
[root@shell ~]# grep -E "^#|^$" grep.sh

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

-o只显示匹配的行中与 PATTERN 相匹配的部分。
默认情况下,是输出包含<匹配内容><一行数据>

在这里插入图片描述

-v表示仅输出<不匹配的数据行> 注意是<不匹配的行>,也就是取反
^和$代表空行

在这里插入图片描述

-B 打印出匹配的行之前的上文 NUM 行。
在相邻的匹配组之间将会打印内容是 -- 的一行。

在这里插入图片描述

-A打印出紧随匹配的行之后的下文NUM行。
在相邻的匹配组之间将会打印内容是 -- 的一行。

在这里插入图片描述

-C显示匹配的<数据行><行总数>

在这里插入图片描述

3.2 sed

1. 基本语法和功能

语法格式:sed [选项] ‘脚本命令’ 输入文件。例如,sed’s/old/new/g’ file.txt,其中s表示替换操作,old是要被替换的字符串,new是替换后的字符串,g表示全局替换(即文件中所有匹配的字符串都被替换),file.txt是操作的目标文件。

功能概述:sed是一个流编辑器,主要用于对文本文件进行编辑操作。它可以在不打开文件的情况下,对文件内容进行查找、替换、删除、插入等操作。sed的操作是基于行的,它逐行读取文件内容,按照指定的脚本命令进行处理,然后输出结果。

2. 替换操作 (s命令)

简单替换:
示例:sed’s/hello/hi/’ file.txt,此命令会将file.txt文件中每行第一次出现的 “hello” 替换为 “hi”。如果要进行全局替换,需要在替换命令最后添加g选项,如sed’s/hello/hi/g’ file.txt。

使用正则表达式进行替换:
sed支持使用正则表达式来匹配要替换的内容。例如,sed’s/[0 - 9]+/number/’ file.txt,会将file.txt文件中每行出现的数字(一个或多个数字)替换为 “number”。

替换部分匹配的字符串:
可以通过在替换命令中使用&符号来引用匹配的字符串部分。例如,sed’s/(\w+), (\w+)/\2, \1/’ file.txt(在支持扩展正则表达式的情况下),假设文件中有 “John, Doe” 这样的内容,此命令会将其转换为 “Doe, John”,其中\1和\2分别代表第一个和第二个括号内匹配的内容。

3. 删除操作 (d命令)

删除匹配行:
示例:sed ‘/^#/d’ file.txt,此命令会删除file.txt文件中所有以 “#” 开头的行。符号表示行的开头,所以#匹配以 “#” 开头的行。

根据条件删除行:
可以结合多个条件来删除行。例如,sed -n ‘/pattern1/ { /pattern2/!d }’ file.txt(-n选项用于抑制默认输出,只输出经过脚本命令处理后的行),这个命令会删除file.txt中包含 “pattern1” 但不包含 “pattern2” 的行。

4.插入和追加操作(i和a命令)

插入操作(i):
示例:sed ‘1i This is a new line’ file.txt,会在file.txt文件的第一行之前插入 “This is a new line”。

追加操作(a):
示例:sed ‘$a This is an appended line’ file.txt,会在file.txt文件的最后一行之后追加 “This is an appended line”。

5.读取和写入文件(r和w命令)

读取文件(r):
示例:sed ‘3r other_file.txt’ file.txt,会在file.txt文件的第三行之后读取并插入other_file.txt的内容。

写入文件(w):
示例:sed -n ‘/pattern/w output_file.txt’ file.txt,会将file.txt中包含 “pattern” 的行写入到output_file.txt文件中。

6.在shell脚本中的应用场景

配置文件修改:
在脚本中,可以使用sed修改配置文件。例如,修改nginx.conf文件中服务器监听端口,sed -i’s/listen 80/listen 8080/g’ nginx.conf,-i选项表示直接在原文件上进行修改。

日志文件处理:
对于日志文件,可以使用sed提取或清理特定的日志行。如sed -n ‘/ERROR/p’ log_file.txt会只打印log_file.txt中包含 “ERROR” 的行,用于快速定位错误日志。

3.3 awk

1.打印操作

打印整行:
命令格式:awk ‘{print $0}’ 文件名。例如:awk ‘{print $0}’ log.txt会将log.txt文件中的每一行内容都打印出来。这在查看文件的原始内容时非常有用,比如查看配置文件或者简单的文本记录文件。

打印指定列:
命令格式:awk ‘{print $列数}’ 文件名。例如:awk ‘{print $1}’ data.csv,假设data.csv是一个以逗号分隔的文件(如包含姓名、年龄、地址等信息),这个命令会打印出每一行的第一列内容,也就是姓名列。如果想打印多列,可以用逗号分隔,如awk ‘{print $1, $3}’ file.txt会打印第一列和第三列的内容。

2.条件判断操作

基于文本内容筛选行:
命令格式:awk ‘/正则表达式/ {动作}’ 文件名。例如:awk ‘/error/ {print $0}’ error.log会将error.log文件中包含 “error” 字样的行全部打印出来。这在日志文件分析中经常使用,用于快速定位包含特定错误信息的行。

基于列内容筛选行:
命令格式:awk ‘$列数 比较运算符 值 {动作}’ 文件名。例如:awk ‘$2 > 10 {print $0}’ numbers.txt,假设numbers.txt是一个包含数字的文件,这个命令会将第二列数字大于 10 的行全部打印出来。比较运算符可以是>(大于)、<(小于)、==(等于)、>=(大于等于)、<=(小于等于)和!=(不等于)。

3.数据统计操作

计算列总和:
命令格式:awk ‘{sum += $列数} END {print sum}’ 文件名。例如:awk ‘{sum += $3} END {print sum}’ sales.csv,假设sales.csv是一个销售数据文件,第三列是销售额,这个命令会计算出所有行销售额的总和并打印出来。

计算列平均值:
命令格式:awk ‘{sum += $列数; count++} END {print sum/count}’ 文件名。例如:awk ‘{sum += $4; count++} END {print sum/count}’ scores.csv,假设scores.csv是一个学生成绩文件,第四列是某一科目成绩,这个命令会计算出该科目成绩的平均值。

4.文本格式化操作

自定义输出格式:
命令格式:awk ‘{printf “格式化字符串”, $列数}’ 文件名。例如:awk ‘{printf “%-10s %-10s\n”, $1, $2}’ contacts.txt,假设contacts.txt是一个包含联系人姓名和电话的文件,这个命令会将姓名和电话以左对齐、宽度为 10 个字符的格式输出,并且每行末尾添加换行符。格式化字符串中常用的格式控制符有%s(字符串)、%d(整数)、%f(浮点数)等,-表示左对齐,数字表示宽度。

字符串拼接与替换:
命令格式:awk ‘{new_column = $列数1 “连接字符” $列数2; print new_column}’ 文件名。例如:awk ‘{new_column = $1 " - " $2; print new_column}’ products.txt,假设products.txt是一个产品信息文件,第一列是产品名称,第二列是产品型号,这个命令会将名称和型号用 “-” 连接起来并打印新的列。也可以使用sub或gsub函数进行字符串替换,如awk ‘{sub(“旧字符串”, “新字符串”, $列数); print $列数}’ 文件名。

十、错误处理与调试

10.1 错误捕获

# 立即退出遇到错误
set -e
# 捕获错误并处理
trap "echo '发生错误!退出状态: $?'" ERR
# 忽略错误
command || true

10.2 调试技巧

# 启用调试模式
set -x
echo "调试信息可见"
set +x
# 输出行号
echo "当前行号: $LINENO"

10.3 日志记录

exec > >(tee -a script.log) 2>&1
echo "日志将同时输出到屏幕和文件"

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94296.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94296.shtml
英文地址,请注明出处:http://en.pswp.cn/web/94296.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

k8s部署,pod管理,控制器,微服务,集群储存,集群网络及调度,集群认证

k8s部署 k8s中容器的管理方式 ​ Kubernetes集群创建方式 centainerd 默认情况下&#xff0c;K8S在创建集群时使用的方式 docker docker使用的普记录最高&#xff0c;虽然K8S在1.24版本后已经费力了kubelet对docker的支持&#xff0c;但时可以借助cri-docker方式来实现集…

JAVA限流方法

在 Java 项目中限制短时间内的频繁访问&#xff08;即接口限流&#xff09;&#xff0c;是保护系统资源、防止恶意攻击或高频请求导致过载的重要手段。常见实现方案可分为单机限流和分布式限流&#xff0c;以下是具体实现方式&#xff1a;一、核心限流算法无论哪种方案&#xf…

性能比拼: .NET (C#) vs. Fiber (Go)

本内容是对知名性能评测博主 Anton Putra .NET (C#) vs. Fiber (Go): Performance (Latency - Throughput - Saturation - Availability) 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准 在本视频中&#xff0c;我们将对比 C# 与 .NET 框架和 Golang 的表现。在第一个…

信誉代币的发行和管理机制是怎样的?

信誉代币的发行与管理机制是区块链技术与经济模型深度融合的产物&#xff0c;其核心在于通过代码和社区共识构建可量化、可验证的信任体系。以下从技术架构、经济模型、治理机制三个维度展开分析&#xff0c;并结合具体案例说明&#xff1a;一、发行机制&#xff1a;行为即价值…

神经网络|(十二)概率论基础知识-先验/后验/似然概率基本概念

【1】引言 前序学习进程中&#xff0c;对贝叶斯公式曾经有相当粗糙的回归&#xff0c;实际上如果我们看教科书或者网页&#xff0c;在讲贝叶斯公式的时候&#xff0c;会有几个名词反复轰炸&#xff1a;先验概率、后验概率、似然概率。 今天就来把它们解读一下&#xff0c;为以…

使用UE5开发《红色警戒3》类战略养成游戏的硬件配置指南

从零开始&#xff0c;学习 虚幻引擎5&#xff08;UE5&#xff09;&#xff0c;开始游戏开发之旅&#xff01;本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01;开发类似《红色警戒3》级别的战略养成游戏&#xff0c;其硬件需求远超普通2D或小型3D项目——这类游戏…

Vue2+Vue3前端开发_Day12-Day14_大事件管理系统

参考课程: 【黑马程序员 Vue2Vue3基础入门到实战项目】 [https://www.bilibili.com/video/BV1HV4y1a7n4] ZZHow(ZZHow1024) 项目收获 Vue3 composition APIPinia / Pinia 持久化处理Element Plus&#xff08;表单校验&#xff0c;表格处理&#xff0c;组件封装&#xff09…

[ACTF新生赛2020]明文攻击

BUUCTF在线评测BUUCTF 是一个 CTF 竞赛和训练平台&#xff0c;为各位 CTF 选手提供真实赛题在线复现等服务。https://buuoj.cn/challenges#[ACTF%E6%96%B0%E7%94%9F%E8%B5%9B2020]%E6%98%8E%E6%96%87%E6%94%BB%E5%87%BB下载查看&#xff0c;一个压缩包和一张图片。压缩包需要密…

关于日本服务器的三种线路讲解

租用日本服务器时&#xff0c;哪种线路选择更适合?当初次接触跨境业务的站长们着手租用日本服务器时&#xff0c;会发现不同服务商提供的网络线路五花八门&#xff0c;从陌生的运营商名称到复杂的技术参数&#xff0c;常常使其感到眼花缭乱。为了帮助大家理清思路&#xff0c;…

【大白话解析】 OpenZeppelin 的 MerkleProof 库:Solidity 默克尔证明验证工具全指南​​(附源代码)

🧩 一、Merkle Tree 是什么?为什么要验证它? 想象你有一个名单,比如: ["Alice", "Bob", "Charlie", "Dave"] 你想让别人验证:“我(比如 Alice)是不是在这个名单里?”,但不想把整个名单都放在区块链上(太贵!)。 于是你…

机械学习综合练习项目

数据集合完整项目文件已经上传一、项目介绍案例介绍 案例是针对“红酒.csv”数据集&#xff0c;在红葡萄酒质量分析的场景 中&#xff0c;利用多元线性回归来探索红葡萄酒的不同化学成分如何共同 影响其质量评分。在建立线性回归模型之后&#xff0c;当给出了红葡萄酒 的新的一…

第3篇:配置管理的艺术 - 让框架更灵活

前言 在前一章中&#xff0c;我们设计了强大的注解API。本章将深入探讨配置管理系统的设计&#xff0c;学习如何将注解中的声明式配置转换为运行时可用的配置对象。 配置管理的核心挑战 在我们的框架中&#xff0c;配置来源有三个层级&#xff1a;主要挑战&#xff1a; &#x…

发版混乱怎么规范

你是否经历过这种场景&#xff1a;临到发版&#xff0c;一堆功能代码挤在一起&#xff0c;测试分不清范围&#xff0c;修复一个Bug可能引发三个新Bug&#xff1f;发布过程像一场豪赌&#xff1f;问题的核心往往在于分支策略和流程的混乱。今天&#xff0c;我们就来建立一套在绝…

【golang长途旅行第30站】channel管道------解决线程竞争的好手

channel 为什么需要channel 使用全局变量加锁同步来解决goroutine的竞争&#xff0c;可以但不完美难以精确控制等待时间​&#xff08;主线程无法准确知道所有 goroutine 何时完成&#xff09;。全局变量容易引发竞态条件​&#xff08;即使加锁&#xff0c;代码复杂度也会增加…

苹果XR芯片介绍

苹果的 XR 芯片技术主要体现在 A 系列、M 系列处理器以及专为空间计算设计的 R1 协处理器中。以下从技术架构、产品迭代和综合对比三个维度展开分析&#xff1a;一、技术架构解析1. A 系列芯片&#xff08;以 A12 Bionic 为例&#xff09;制程工艺&#xff1a;7nm&#xff08;台…

达梦数据库巡检常用SQL(三)

达梦数据库巡检常用SQL(三) 数据库SQL运行检查 数据库SQL运行检查 死锁的事务情况: SELECT TO_CHAR(HAPPEN_TIME,YYYY-MM-DD HH24:MI:SS) HAPPEN_TIME,SQL_TEXT FROM V$DEADLOCK_HISTORY WHERE HAPPEN_TIME >DATEADD(DAY,-30,

基于SpringBoot的校园周边美食探索及分享平台

1. 项目简介 项目名称&#xff1a;校园周边美食探索及分享平台 项目背景&#xff1a;针对校园师生对周边美食信息的需求&#xff0c;构建一个集美食推荐、鉴赏、评论互动及社交功能于一体的平台&#xff0c;帮助用户发现优质美食资源并进行分享交流。 主要目标&#xff1a; 提供…

Go数据结构与算法-常见的排序算法

虽然看过别人写了很多遍&#xff0c;而且自己也写过很多遍&#xff08;指的是笔记&#xff09;&#xff0c;但是还是要写的就是排序算法。毕竟是初学Go语言&#xff0c;虽然之前写过&#xff0c;但是还是打算再写一遍。主要包括插入排序、选择排序、冒泡排序、快速排序、堆排序…

第 6 篇:目标规则与负载均衡 - `DestinationRule` 详解

系列文章:《Istio 服务网格详解》 第 6 篇:目标规则与负载均衡 - DestinationRule 详解 本篇焦点: 深入理解 DestinationRule 的核心作用:定义流量在到达目的地之后的行为。 详细剖析其三大核心功能:服务子集 (Subsets), 流量策略 (Traffic Policy), TLS 设置。 动手实战…

一个简洁的 C++ 日志模块实现

一个简洁的 C 日志模块实现 1. 引言 日志功能在软件开发中扮演着至关重要的角色&#xff0c;它帮助开发者追踪程序执行过程、诊断问题以及监控系统运行状态。本文介绍一个使用 C 实现的轻量级日志模块&#xff0c;该模块支持多日志级别、线程安全&#xff0c;并提供了简洁易用…