当前位置: 首页 > news >正文

3 shell脚本编程

Shell脚本简介

shell脚本是什么?

shell脚本是由shell命令组成的文本文件。利用shell命令加shell语法,配合正则表达式、管道命令、数据流从定向等写成的纯文本脚本文件。以.sh为后缀


为什么要写它?


1、自动话重复任务:可以将重复性或复杂的任务自动化处理

如:批量重命名文件、定时备份数据、自动清理日志
2、简化管理操作:简化管理操作,如定时执行、系统配置、监测等
3、提高效率:节省手动执行命令的时间,特别是多步操作的时候
4、可重用性:可以多个项目重用,只需简单修改
5、跨平台兼容:在Linux/Unix/macOS系统中通用(但需注意语法差异)


典型应用场景

1、日常运维

  • 定时备份数据库或文件(结合cron使用)。
  • 监控磁盘空间,自动清理旧文件。
  • 检查服务状态,异常时发送告警邮件。

2、开发辅助

  • 自动编译代码、运行测试用例。
  • 批量处理数据(如日志分析、格式转换)。

3、部署与配置

  • 一键安装软件(如Docker、Nginx)。
  • 初始化服务器环境(配置用户、防火墙等)。

4、数据处理

  • 结合grepawksed处理文本文件。
  • 提取日志中的错误信息并生成报告。

shell编写

编写步骤:需求分析、命令测试、脚本编写、测试调优

1 #!/bin/bash #指定解释器。标明使用的shell版本,跟自己用的版本一致, 路径等不能错,否者解释器错误 2 3 echo "hello world!" #打印

执行方式:解释性语言,不需要编译

bash **.sh source **.sh ./**.sh //要先赋权

Shell脚本变量

变量介绍

变量来源于数学,是计算机语言中能储存计算结果能表示值的抽象概念。 变量可以通过变量名访问。在指令式语言中,变量通常是可变的。

在一个脚本周期内,其值可以发生改变的量


变量的作用

存放特定参数:用来存放系统和用户需要使用的特定参数(值)

变量名:使用固定的名称,由系统预设或用户定义

变量值:能够根据用户设置、系统环境的变化而变化


命名要求

分类

变量操作

定义变量

通常使用全大写变量,方便识别

等号左右两侧不能有空格

1 #!/bin/bash 2 3 COUNT=3 #变量创建 4 echo $COUNT 5 6 unset COUNT #变量取消 7 echo $COUNT

set //变量查看
shell中,变量本身只存储字符串,小数,整数都按字符串形式存储,所以对于小数运算需要借助外部工具(如bc、awk)

取值

变量的值如果有空格,需要使用单引号双引号包括。如:test=“hello world!”

双引号:允许通过$符号引用其他变量值。实现转义,其中的变量引用会被替换为变量值

单引号:单引号括起来的内容都是普通字符。不能转义,$被视为普通字符,其中的变量引用不会被替换为变量值,而保持源字符串

反撇号: 命令替换,提取命令执行后的输出结果(不是运算表达式的结果),` `和$(…)作用相同

1 #!/bin/bash 2 3 COUNT=3 4 echo $COUNT 5 6 echo "$COUNT" #显示“ ”里运算的结果 7 echo '$COUNT' #原样显示‘ ’里的内容 8 9 #A=echo $COUNT #错误写法 10 A=`echo $COUNT` #将命令执行的结果赋值给变量,这个命令要有确定值 11 B=$(echo $COUNT) 12 echo $A 13 echo $B
[root@localhost ~]$ name=sc #定义变量name 的值是sc [root@localhost ~]$ echo '$name' $name #如果输出时使用单引号,则$name原封不动的输出 [root@localhost ~]$ echo "$name" sc #如果输出时使用双引号,则会输出变量name的值 sc [root@localhost ~]$ echo `date` 2018年10月21日星期一18:16:33 CST #反引号括起来的命令会正常执行 [root@localhost ~]$ echo '`date`' `date` #但是如果反引号命令被单引号括起来,那么这个命令不会执行,―date会被当成普通字符输出 [root@localhost ~]$ echo "`date`" 2018年10月21日星期一18:14:21 CST #如果是双引号括起来,那么这个命令又会正常执行 wlw@wlw-virtual-machine:~/text$ echo '"`date`"' "`date`" wlw@wlw-virtual-machine:~/text$ echo "'`date`'" '2026年 04月 17日 星期五 10:44:10 CST' echo "Value: ${var}" # 用{}来明确变量边界 比如: var="Hello" varify="World" echo "Value: ${var}ify" # 这表示引用 var 的值并加上 "ify" 使用 {} 来明确变量的边界,避免混淆 原文链接:https://blog.csdn.net/w918589859/article/details/108752592

变量值叠加

变量需要用双引号包含"$变量名"或用${变量名}包含变量名。

[root@localhost ~]$ test=123 [root@localhost ~]$ test="$test"456 [root@localhost ~]$ echo $test 123456 #叠加变量test,变量值变成了123456 [root@localhost ~]$ test=${test}789 [root@localhost ~]$ echo $test 123456789 #再叠加变量test,变量值编程了123456789

数组

a=(元素1 元素2 元素3 ...) :创建数组,元素间用空格隔开

echo $a:默认显示数组a的第一个元素

echo ${a[0]} :显示数组中第一个元素,以此类推

echo ${a[-1]}: 显示数组中最后一个元素(a[-2]:倒数第二个)

echo ${a[*]} 和echo ${a[@]} :显示数组中所有元素

echo ${#a[@]} :显示数组中元素的个数

echo ${a[@]:起始元素id:元素个数]} :显示数组中以起始元素为首的指定个数的元素(注意:这里起始元素id不能为负值

unset a[n] 删除数组中的第n个元素

unset a 删除a这个数组

1 #!/bin/bash 2 #數組 3 a=(1 2 3 4 5) #创建 4 echo $a #默认取第一个元素 5 echo ${a[*]} #取所有元素 6 echo ${a[@]} 7 echo ${#a[*]} #元素个数 8 echo ${#a[@]} 9 echo ${a[2]} #取指定下标的元素 10 a[2]=8 #给指定下标赋值 11 echo ${a[*]} 12 echo ${a[@]:1:3} #取下标为1开始的三个元素 13 unset a[2] #删指定下标的元素 14 echo ${a[@]} 15 unset a #删数组

环境变量

使用export声明的变量即是环境变量

删除

环境变量查询

env与set

set可以查看所有变量,env只能查看环境变量

常用环境变量:

$USER 表示用户名称

$HOME 表示用户的宿主目录

$LANG 表示语言和字符集

$PWD 表示当前所在工作目录

$PATH 表示可执行用户程序的默认路径

只读变量

变量值不允许修改(重新赋值)的情况 , 无法使用 unset删除, 删除的最快方法是重启终端。

用readonly来定义

1 #!/bin/bach 2 3 readonly COUNT=3 4 COUNT=5 #报错 5 echo $COUNT 6 unset COUNT #报错

位置变量和预定义变量

  • $0 与键入的命令行一样,包含脚本文件名
  • $1,$2,……$9 ${10} 分别包含第一个到第十个命令行参数
  • $# 包含命令行参数的个数
  • $@ 包含所有命令行参数:“$1,$2,……$9”
  • $* 包含所有命令行参数,是一个整体:“$1,$2,……$9”
  • $? 包含前一个命令的退出状态,正常退出,值为0,非正常退出,值为非0(1~255之间)导致退出的因素不同,值不同
  • $$ 包含正在执行进程的ID号
1 #!/bin/bash 2 3 echo $0 4 echo $1 5 echo $2 6 echo $3 7 echo $4 8 echo $5 9 echo $6 10 11 echo $# #统计传入的参数 12 echo $* #显示全部参数 13 echo $@ #显示全部参数,实际上两者有区别 14 echo $? #上一条命令的退出状态,成功是0 15 echo $$ #Pid号

shell语句

Shell 程序由零或多条shell语句(也就是Shell命令)构成。 shell语句包括三类:说明性语句 功能性语句 结构性语句。

说明性语句(注释行)

以#号开始到该行结束,不被解释执行

功能性语句(命令)

标准输入:read

read从标准输入读入一行,阻塞, 并赋值给后面的变量,其语法为:

read var

read var1 var2 var3//把读入行中的第一个单词(word)赋给var1, 第二个单词赋给var2, ……把其余所有的词赋给最后一个变量.。输入的多个数据由空格隔开

1 #!/bin/bash 2 3 read -p "提示语句:"val1 val2 4 echo $val1 $val2

-p “ ” #提示语句

-t 5 #5秒内不输入,自动结束,5内没有输入完(没按回车),也自动结束

-s #输入时不显示输入内容

算术运算命令:expr

主要用于进行简单的整数运算,包括加(+)、减(-)、乘(\*)、整除(/)和求模(%)等操作。

1 #!/bin/bash 2 3 read val1 val2 4 echo $val1 $val2 5 6 ADD=`expr $val1 + $val2` 7 echo $ADD 8 ADD=`expr $val1 - $val2` 9 echo $ADD 10 ADD=`expr $val1 \* $val2` 11 echo $ADD 12 ADD=`expr $val1 / $val2` 13 echo $ADD

等号前后不能有空格,要夹``,运算符号前后要加空格

直接返回计算结果,在命令行中直接打印出来

测试三种对象test

字符串 整数 文件属性 每种测试对象都有若干测试操作符

字符串测试

s1 = s2 测试两个字符串的内容是否完全一样

s1 != s2 测试两个字符串的内容是否有差异

-z s1 测试s1 字符串的长度是否为0

-n s1 测试s1 字符串的长度是否不为0

test命令的退出状态码:

条件成立(正):test返回0

条件不成立(假):test返回非0(通常是1)

1 #!/bin/bash 2 3 val1="hello" 4 val2="hello" 5 val3="world" 6 #成立为0,不成立为1 7 test $val1 = $val2 8 echo $? #0 9 10 test $val1 = $val3 11 echo $? #1 12 13 test $val1 != $val3 14 echo $? #0 15 16 val1= 17 test -z $val1 18 echo $? #0 19 20 val1="haha" 21 test -z $val1 22 echo $? #1 23 24 val1="haha" 25 test -n $val1 26 echo $? #0 27 28 val1= 29 test -n $val1 30 echo $? #0 31 32 val1="haha" 33 test -n "$val1" #-n要加“ ”,所有都最好加 34 echo $? #0 35 36 val1= 37 test -n "$val1" 38 echo $? #1

整数测试

a -eq b 测试a 与b 是否相等

a -ne b 测试a 与b 是否不相等

a -gt b 测试a 是否大于b

a -ge b 测试a 是否大于等于b

a -lt b 测试a 是否小于b

a -le b 测试a 是否小于等于b

文件测试

-e name 测试一个文件是否存在

-d name 测试name 是否为一个目录

-f name 测试name 是否为普通文件

-L name 测试name 是否为符号链接

-r name 测试name 文件是否存在且为可读

-w name 测试name 文件是否存在且为可写

-x name 测试name 文件是否存在且为可执行

-s name 测试name 文件是否存在且其长度不为0

f1 -nt f2 测试文件f1 是否比文件f2 更新

f1 -ot f2 测试文件f1 是否比文件f2 更旧

test命令测试的条件成立时, 命令返回值为(0),否则返回值为(1).

结构性语句

结构性语句主要根据程序的运行状态、输入数据、变量的取值、控制信号以及运行时间等因素来控制程序的运行流程。 主要包括: 条件测试语句(两路分支) 多路分支语句 循环语句 循环控制语句等

分枝语句


if 表达式
then 命令表 //条件成立
fi

if 表达式
then //条件成立
。。。
else //条件不成立
。。。
fi

if 条件语句
then
。。。
elif 条件语句
then
。。。
fi

表达式为真,执行命令表,假执行fi后语句。if-fi成对使用

if语句判断的依据是所跟命令的退出状态码决定分支:

  • 状态码为0→ 条件为“真”,执行then后面的命令表。

  • 状态码为非 0→ 条件为“假”,跳过then部分(或执行else/elif部分)。

  • 注意要和C的0为假,非0为真区别

1 #!/bin/bash 2 3 read -p "input a filename: " file 4 5 #test -e $file 6 #echo $? #之前的判断法 7 8 #if test -e $file #这个形式也可以 9 if [ -e $file ] #[ ]与条件语句要有空格 10 then 11 echo "$file exist" 12 echo "***********" 13 echo "***********" 14 echo "***********" 15 else 16 echo "$file is not exist" 17 echo "***********" 18 echo "***********" 19 echo "***********" 20 fi

一个if对应一个then

1 #!/bin/bash 2 3 read -p "input a filename: " file 4 5 if [ -f $file ] 6 then 7 echo "$file is a file" 8 elif [ -d $file ] 9 then 10 echo "$file is a dir" 11 fi

例:判断用户是否存在

用户信息保存在/etc/passwd下,

grep “用户内容” /etc/passwd //查找命令

grep "wlw" /etc/passwd

头一个是用户名,“^wlw”限定头一个

用户不存在就不会打印

通过判断是否有打印来确定用户是否存在

wc //统计命令

wc -l //统计行数

利用管道:grep “^wlw” /etc/passwd | wc -l //统计查找命令输出结果有几行

为1表示找到这个用户,为0表示没有这个用户

通过shell脚本实现:

1 #!/bin/bash 2 3 read -p "input a ures: " U 4 RET=`grep "$U" /etc/passwd | wc -l` 5 if [ $RET -eq 1 ] 6 then 7 echo "exist" 8 else 9 echo "not exist" 10 fi

多路分枝语句

case....esac

模式匹配着字符串变量的可能取值

1 #!/bin/bash 2 3 read -p "input yes or no: " val 4 case $val in 5 yes | y) #输入yes或y都执行同一个语句块 6 echo "input yes" 7 ;; 8 YES | Y) 9 echo "input YES" 10 ;; 11 no) 12 echo "input no" 13 esac

例:成绩分级

1 #!/bin/bash 2 3 read -p "input score: " val 4 5 #if [ $val -gt 100 ] || [ $val -lt 0 ] #两种方式都可以 6 if [ $val -gt 100 -o $val -lt 0 ] 7 then 8 echo "input error val" 9 exit 10 fi 11 12 val=`expr $val / 10` 13 case $val in 14 8 | 9 | 10) 15 echo "A" 16 ;; 17 6 | 7) 18 echo "B" 19 ;; 20 *) 21 echo "C" 22 esac

-gt //大于 -lt //小于 -a 与 -o //或 !//非

循环语句

for的用法

for 变量 in 表 //变量依次从表里面拿值,拿一次循环一次,拿完为止

do

命令块

done

1 #!/bin/bash 2 3 filename=`ls` 4 for file in $filename #所有文件组成的文件表 5 do 6 if [ -f $file ] 7 then 8 echo "$file is a file" 9 elif [ -d $file ] 10 then 11 echo "$file is a dir" 12 else 13 echo "*****" 14 fi 15 done

$@ $* //命令行传的所有参数表

1 #!/bin/bash 2 3 for n in $@ 4 do 5 echo "$n" 6 done

1 #!/bin/bash 2 3 for n in $* 4 do 5 echo "$n" 6 done

1 #!/bin/bash 2 3 for n in "$@" 4 do 5 echo "$n" 6 done

1 #!/bin/bash 2 3 for n in "$*" 4 do 5 echo "$n" 6 done

$@和$*的区别:

“$@”还是挨个参数表,“$*”是一个整体

C语言形式

1 #!/bin/bash 2 3 for ((i = 0; i < 5; i++)) 4 do 5 echo "$i" 6 done

for里头echo命令会自动换行

while的用法

结构:

while 命令或表达式 //为真便执行命令表

do

命令表

done

1 #!/bin/bash 2 3 i=0 4 while [ $i -lt 5 ] #方式1 5 do 6 echo "$i" 7 i=`expr $i + 1` 8 done 1 #!/bin/bash 2 3 i=0 4 while (( i < 5 )) #方式2 5 do 6 echo "$i" 7 i=`expr $i + 1` 8 done

循环控制语句

break和contine

break //跳出一层循环

break n //跳出n层循环

contine //跳过本次循环的语句去判断下一次循环

contine n //跳过本次以及往后的n-1次循环去判断后面的循环

Shell函数

定义:

function name() //关键字和函数名

{

代码块

[return] //可有可无

}

1 #!/bin/bash 2 3 function fun() 4 { 5 echo "hello woed" 6 return 0 7 } 8 9 fun

函数调用

方式1:value_name=`function_name [arg1 arg2...]`

命令置换是把函数内的标准输出的内容赋给变量

方式2:function_name [arg1 arg2....]

echo $?

$?是获取函数返回值的状态

1 #!/bin/bash 2 3 function fun() 4 { 5 echo "hello woed" 6 grep "wlw" /etc/passwd 7 return 0 8 } 9 fun

1 #!/bin/bash 2 3 function fun() 4 { 5 echo "hello woed" 6 grep "wlw" /etc/passwd 7 return 0 8 } 9 rea=`fun`

1 #!/bin/bash 2 3 function fun() 4 { 5 echo "hello woed" 6 grep "wlw" /etc/passwd 7 return 0 8 } 9 ret=`fun` 10 echo $ret

1 #!/bin/bash 2 3 function fun() 4 { 5 echo "hello woed" 6 grep "wlw" /etc/passwd 7 return 0 8 } 9 fun 10 echo $?

1 #!/bin/bash 2 3 function fun() 4 { 5 echo "hello woed" 6 grep "wlw" /etc/passwd 7 return 2 8 } 9 fun 10 echo $?

函数传参

1 #!/bin/bash 2 3 function fun() 4 { 5 echo "hello woed" 6 grep "$1" /etc/passwd 7 echo $2 8 echo $3 9 return 2 10 } 11 fun wlw 5 9 12 echo $?

$1 $2 $3 就是参数替换的位置,函数调用后直接跟参数值就行

函数内变量的作用域

1 #!/bin/bash 2 3 function fun() 4 { 5 val=10 6 echo $val 7 return 2 8 } 9 fun 10 echo "**$val**"

含数内的变量是全局变量,要想变局部变量加local修饰或采用命令替换调用

采用命令替换调用,那么val就不是全局变量了

1 #!/bin/bash 2 3 function fun() 4 { 5 val=10 6 echo $val 7 return 2 8 } 9 ret=`fun` #采用命令替换调用,那么val就不是全局变量了 10 echo $ret 11 echo "**$val**"

http://www.jsqmd.com/news/671177/

相关文章:

  • C语言数组实战:避开‘暴力模拟’的坑,用标记法高效统计‘安全区域’
  • 5分钟掌握Inter字体:现代网页排版的终极OpenType特性指南
  • 齿轮箱零部件及其装配质检中的TVA技术突破(9)
  • XXMI Launcher终极指南:一站式游戏模组管理器快速上手
  • 题解:AcWing 6 多重背包问题III
  • 突破Vitest浏览器测试并行执行瓶颈:从阻塞到飞一般的体验
  • ITK-SNAP医学图像分割:3步掌握专业级医学影像分析
  • 3大秘诀解锁Salt Player歌词黑科技:从零基础到车载高手全攻略
  • 终极指南:WarcraftHelper让魔兽争霸3在现代Windows系统焕发新生
  • 深度解析:Elasticsearch 的 REST API 有什么优点?
  • docker containerd 3 - 小镇
  • 题解:洛谷 AT_abc356_a [ABC356A] Subsegment Reverse
  • 别再傻傻分不清:5分钟搞懂通信里的误比特率、误码率、误帧率和误块率(BLER)
  • 从LocalDateTime序列化报错到搞定:一个Jackson配置拯救你的Spring Boot日期接口
  • Cadence原理图设计避坑指南:PinName提取工具安装配置全流程(含报错解决)
  • 用HLS在Zynq上实现图像缩放IP:从720P到1080P,一个工程搞定OV5640摄像头适配
  • 如何用League Akari重构你的英雄联盟游戏体验:一个技术驱动的高效解决方案
  • 掌握ReactPage中的CSS变量:轻松实现主题定制与样式动态调整
  • B站缓存视频转换神器:m4s-converter终极使用指南
  • 南京玄武区空调安装公司权威测评:南京舒特机电设备有限公司深度推荐 - 小艾信息发布
  • 别让Claude Skill变‘话痨’:从官方最佳实践看如何写出‘省token’的高效技能
  • AMD Ryzen 处理器功耗调校实战:RyzenAdj 深度应用指南
  • 用YOLOv4训练自己的数据集?从标注到模型部署,这份Win10实战指南全了(附VOC格式转换脚本)
  • Synopsys AXI VIP实战:用回调函数搞定Outstanding事务统计(附完整代码)
  • 3步搞定PS手柄PC游戏兼容:DS4Windows终极配置指南
  • 题解:洛谷 AT_abc356_c [ABC356C] Keys
  • 从VBA到Python:一个老工程师的HFSS脚本自动化升级之路(踩坑与收获)
  • UDOP-large保姆级教程:Tesseract OCR语言包chi_sim+eng安装与调优
  • 高性能开源PLC编程平台:OpenPLC Editor工业自动化开发完整解决方案
  • 2026年昆山全屋定制公司评价排行榜:全屋定制设计/极简全屋定制/轻奢风全屋定制/全屋定制一站式服务/全屋定制个性化定制 - 品牌策略师