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

Shell 脚本基础完全指南:语法、调试、运行与实战详解

Shell 脚本基础完全指南:语法、调试、运行与实战详解

一、脚本基础

1、Shell编程介绍与特性

Shell是命令解释程序,也是命令语言解释器。用户输入的命令行需符合Shell语法语义规范,才能被Shell理解执行;其使用的命令语言称为Shell语言
Shell语言兼具交互式可编程性:将多个Shell命令写入文件即构成Shell程序(脚本),可通过变量、参数、控制结构组织命令流程,实现复杂工作的自动化。

在Linux系统中,Shell程序广泛用于系统初启、配置、管理与维护,熟练掌握Shell能深入理解系统运行机制,提升系统管理效率。

Shell语言的核心特点
  1. 解释性语言:无需编译,由Shell进程直接解释执行,即编即用,便捷性高,但运行速度低于编译型语言。

  2. 基于字符串的语言:仅处理字符串,不支持复杂数据结构与运算,输出均为字符方式。

  3. 命令级语言:程序由命令(非语句)构成,几乎所有Shell命令与可执行程序均可用于编写脚本;命令丰富且组合能力强,脚本简洁高效。

    注意:不同版本的Shell程序(如Bash、Sh)不完全兼容,差异可能细微或显著。

定义补充

Shell程序也称Shell脚本,是由Shell命令构成的文本文件:

  • 简单脚本:仅命令序列;
  • 高级脚本:包含复杂命令组合、变量、参数、条件命令、控制结构等。

2、变量

(1)什么是变量?

变量是程序中保存用户数据的一块内存空间,变量名是该内存空间的地址。程序执行时,内存空间的内容(变量值)可变化,但变量名固定。
变量是几乎所有编程语言的基础,Shell中变量的核心作用是存储临时数据,供脚本后续调用。

(2)变量的命名规则
  • 组成:仅允许字母、数字、下划线(_);
  • 开头:必须以字母或下划线开头(不能以数字开头);
  • 长度:Shell无明确限制,但为提高可读性,建议使用短字符串;
  • 规范:优先选择有明确意义的英文单词(如age表示年龄、salary表示薪资),避免拼音或无意义字符(如a1abc)。
(3)变量的类型

Shell中变量类型无需显式声明,根据赋值内容自动识别,主要包括以下4类:

类型定义与说明示例代码
整形(int)存储整数,直接赋值,无需特殊符号age=10
浮点型(float)存储小数,直接赋值salary=3.1
字符型存储字符串,可加单引号、双引号或不加引号;字符串含空格时必须加引号- 无空格:msg=cymsg="cy"msg='cy'
- 有空格:msg="hello cy"(必须加引号)
布尔型仅两个值:True(真)或 False(假),用于条件判断is_ok=Truehas_error=False
关键:单引号与双引号的区别
  • 双引号(" "):弱引用:引号内的特殊字符(如$\)仍保留原有意义;
  • 单引号(’ '):强引用:引号内所有特殊字符均取消意义,按原始字符串解析。

示例(实际执行效果):

[root@server ~]# name="cy"  # 定义变量name
[root@server ~]# echo "${name} is good"  # 双引号保留$的变量引用意义
cy is good
[root@server ~]# echo '${name} is good'  # 单引号取消$的意义
${name} is good

3、脚本执行方式

Shell脚本执行有5种方式,核心差异在于是否需要脚本文件具备执行权限

执行方式语法格式核心说明
绝对路径执行/path/to/脚本名(如/root/a.sh需脚本具备执行权限(chmod +x 脚本名),通过完整路径调用。
相对路径执行./脚本名(如./a.sh需脚本具备执行权限,仅在脚本所在目录下使用(.表示当前目录)。
sh/bash命令执行sh 脚本名 或 bash 脚本名(如sh a.sh无需执行权限,通过Sh/Bash解释器直接解析脚本。
.(空格)执行. 脚本名(如. a.sh无需执行权限,注意“.”后必须加空格;本质是在当前Shell环境执行脚本。
source命令执行source 脚本名(如source a.sh无需执行权限,核心用途是“生效配置文件”(如source /etc/profile),与“.”执行效果一致。

4、Shebang机制

#!(称为Shebang)用于告诉系统脚本使用的解释器,必须写在脚本文件的第一行。常见解析器路径如下:

  • #!/bin/bash:指定Bash解释器(最常用);
  • #!/usr/bin/python:指定Python解释器;
  • #!/usr/bin/perl:指定Perl解释器。

二、脚本的组成结构

1、脚本的组成

Shell脚本由“开头声明、注释、命令行”三部分构成,具体规则如下:

组成部分说明
开头必须通过Shebang指定解释器(如#!/bin/bash),告知系统解析方式。
注释#开头的行(#!除外),用于说明脚本功能、逻辑,不参与执行;建议多写注释提升可读性。
命令行规则1. 一行为一条命令;
2. 一行多条命令需用;分隔;
3. 长命令可通过\换行(续行符)。
示例:最简单的Shell脚本(Hello World)
#!/bin/bash
# 功能:输出Hello World(这是注释)
echo "Hello World!"  # 单行命令,输出字符串

2、程序返回值

Shell程序执行后,会产生两类返回值,用于判断执行结果:

  1. 程序执行的结果:即脚本输出的内容(如echo打印的字符串、命令执行的输出);
  2. 程序状态返回代码:范围0-255,用于标识执行成功/失败:
    • 0:脚本/命令正确执行
    • 1-255:脚本/命令错误执行(不同错误码对应不同错误类型,如权限不足、文件不存在等)。
关键:获取状态返回代码

通过特殊变量$?可获取“上一行命令/脚本的状态返回代码”,示例:

# 执行成功的命令
echo "test"
echo $?  # 输出0(表示上一条echo命令执行成功)# 执行失败的命令(访问不存在的文件)
cat /tmp/nonexistent.txt
echo $?  # 输出1(表示上一条cat命令执行失败)

三、Shell脚本调试

1、脚本执行的过程解析

当Shell脚本运行时,执行流程如下:

  1. 查找系统环境变量ENV,该变量指定了需加载的环境文件,加载顺序通常为:
    /etc/profile → 当前用户家目录.bash_profile → 当前用户家目录.bashrc/etc/bashrc

    注意:如果环境中有变量名相同起冲突时,优先级低的值会覆盖优先级高的值

  2. 加载完环境变量后,Shell开始执行脚本内容:

    • 从上至下、从左至右依次执行每一行命令/语句;
    • 若遇到子脚本(脚本嵌套),先执行子脚本,完成后返回父脚本,继续执行后续内容。

2、脚本执行的原理

Shell本身不直接执行命令,而是通过派生子进程让子进程执行命令,核心原因是“降低风险”:

  • 子进程执行命令时,即使出现错误(如崩溃),也不会影响父Shell进程;
  • 若Shell直接执行命令,一旦命令出错导致Shell崩溃,将无法再解释其他命令(Shell是用户与系统交互的核心)。
  • 本质:Shell仅负责“发起命令请求”,子进程负责“执行命令并返回结果”,Shell等待子进程完成后继续后续逻辑。

3、写脚本注意事项

为提升脚本稳定性、可读性、可维护性,需遵循以下8条规则:

  1. 开头必须加Shebang(如#!/bin/bash),指定解释器;

  2. 语法缩进使用4个空格(避免用Tab),逻辑块(如条件、循环)需缩进;多写注释说明功能、参数、逻辑;

  3. 命名规范:

    • 变量名:全局变量大写(如AGE),局部变量小写(如local age);
    • 函数名:小写(如calculate_sum);
    • 所有名称需体现实际作用(如salary表示薪资,避免a1b2等无意义名称);
  4. 变量作用域:默认变量为全局变量(整个脚本可访问);在函数中需用local关键字声明局部变量,避免污染全局作用域;

  5. 调试辅助命令:

    • set -e:脚本中遇到“返回码非0的命令”时,立即退出脚本(避免错误扩散);
    • set -x:执行脚本时,打印每一条命令的执行过程(便于定位错误);
  6. 脚本上线前必须先测试:在测试环境验证功能、兼容性、错误处理,确认无误后再部署到生产环境;

  7. 脚本中的命令必须使用绝对路径(如/bin/echo而非echo/usr/bin/cat而非cat),避免因环境变量PATH配置问题导致命令无法找到;

  8. 引用命令执行结果时,需用反引号`命令`)或$(命令)(推荐,兼容性更好),示例:

    current_date=`date +%Y%m%d` 
    #或 
    current_date=$(date +%Y%m%d)
    #两种方式均获取当前日期
    

    ·current_date=date +%Y%m%d`` 或 current_date=$(date +%Y%m%d)`(两种方式均获取当前日期)。

4、脚本调试方法

Shell提供专门的调试命令,用于检查脚本语法错误、跟踪执行过程:

调试命令功能说明
bash -n 脚本名检查脚本是否存在语法错误(如括号不匹配、命令拼写错误),不执行脚本;若无输出,说明语法无错。
bash -x 脚本名执行脚本并打印每一步的执行过程(包括变量展开、命令执行细节),用于定位逻辑错误(如变量赋值错误、条件判断错误)。
示例:调试脚本
# 假设有脚本test.sh,先检查语法
bash -n test.sh  # 无输出,说明语法正确# 跟踪执行过程
bash -x test.sh  # 输出每一步命令及变量值,如+ echo "Hello"、+ age=10等

5、调试案例(实战练习)

需求:完成以下操作,熟悉脚本编写与调试:

  1. 创建目录/tmp/hrz
  2. 切换到/tmp/hrz目录;
  3. 在该目录下创建目录a1bb2c6cy
  4. 在该目录下创建空文件xyx123y123
  5. 列出当前目录下“以a6开头”的文件/目录,将结果导入/tmp/file1
  6. 列出当前目录下“以字母开头、后接1个任意数字、再后接任意长度字符”的文件/目录,将结果导入/tmp/file2
实现脚本(含调试辅助)
#!/bin/bash
set -x  # 打印执行过程(调试用)
set -e  # 出错立即退出(避免错误扩散)# 步骤1-2:创建目录并切换
mkdir -p /tmp/hrz  # -p:确保目录存在,不存在则创建
cd /tmp/hrz# 步骤3:创建3个目录
mkdir -p a1b b2c 6cy# 步骤4:创建3个空文件(touch用于创建空文件)
touch xy x123y 123# 步骤5:筛选a/6开头的文件/目录,导入file1
# ls:列出内容;grep ^[a6]:匹配以a或6开头的行
ls | grep ^[a6] > /tmp/file1# 步骤6:筛选“字母+数字+任意字符”的文件/目录,导入file2
# ^[[:alpha:]]:以任意字母开头;[[:digit:]]:1个任意数字;.*:任意长度字符
ls | grep ^[[:alpha:]][[:digit:]].* > /tmp/file2echo "操作完成,结果已保存到/tmp/file1和/tmp/file2"
关键正则说明
  • [[:alpha:]]:匹配任意大小写字母(等价于[a-zA-Z]);
  • [[:digit:]]:匹配任意整数(等价于[0-9]);
  • ^:行首匹配;.*:匹配任意长度的任意字符(包括空字符)。

四、运算符

原生Bash不支持简单的数学运算,需通过exprlet$[]$(( ))等工具/语法实现。

1、算术运算符

用于整数运算(Bash原生不支持浮点运算,需借助bc等工具),假设ab为变量,常见运算符及语法如下:

运算类型语法格式说明
加法expr $a + $b注意:+前后必须加空格;expr是外部命令,需用反引号或$()获取结果。
减法expr $a - $b同理,-前后必须加空格。
乘法expr $a \* $b需用\转义*(否则*会被解析为通配符)。
除法expr $b / $a仅支持整数除法(舍去小数部分,如expr 5 / 2结果为2)。
取余expr $b % $a求余数(如expr 5 % 2结果为1)。
赋值a=$bb的值赋给a(无需空格)。
相等[ $a == $b ]判断ab是否相等(==前后需加空格,[ ]是条件判断符号)。
不相等[ $a != $b ]判断ab是否不相等(同理,!=前后需加空格)。
算术运算的4种实现方式

以“计算A=3B=6的和”为例,4种常用方式:

A=3
B=6# 方式1:let(内置命令,无需空格,直接运算)
let C=$A+$B
echo "let方式:$C"  # 输出9# 方式2:$[](内置语法,直接运算,无需空格)
C=$[ $A+$B ]
echo "$[]方式:$C"  # 输出9# 方式3:$(( ))(推荐,兼容性好,直接运算)
C=$(( $A+$B ))
echo "$(( ))方式:$C"  # 输出9# 方式4:expr(外部命令,需空格和反引号)
C=`expr $A + $B`  # 或 C=$(expr $A + $B)
echo "expr方式:$C"  # 输出9
例题:计算两个整数的四则运算与取余

脚本功能:定义两个整数,计算并显示其和、差、积、商、余:

#!/bin/bash
# 功能:计算两个整数的四则运算与取余
a=40
b=20# 计算各结果
let jia=$a+$b    # 和
let jian=$a-$b   # 差
let cheng=$a*$b  # 积
let chu=$a/$b    # 商(整数)
let yu=$a%$b     # 余# 输出结果
echo "a=$a"
echo "b=$b"
echo "a+b=$jia"
echo "a-b=$jian"
echo "a*b=$cheng"
echo "a/b=$chu"
echo "a%b=$yu"
执行结果
[root@hrz2 tmp]# . ./bbb.sh 
a=40
b=20
a+b=60
a-b=20
a*b=800
a/b=2
a%b=0

2、逻辑运算

用于判断多个条件的“与/或”关系,核心运算符为&&(逻辑与)和||(逻辑或),基于“上一条命令的状态返回码”判断是否执行下一条命令。

(1)逻辑与(&&):AND关系
  • 规则:前一条命令执行成功(返回码0)时,才执行后一条命令;若前一条失败(返回码非0),则后一条不执行。
  • 场景:用于“依赖前序操作成功的后续操作”(如“安装成功后,才启动服务”)。
(2)逻辑或(||):OR关系
  • 规则:前一条命令执行失败(返回码非0)时,才执行后一条命令;若前一条成功(返回码0),则后一条不执行。
  • 场景:用于“前序操作失败后的兜底处理”(如“安装失败时,输出错误信息”)。
示例:安装HTTP服务并部署简单网页

脚本功能:通过yum安装httpd服务,部署首页,启动服务并测试访问:

#!/bin/bash
set -e
# 功能:安装HTTP服务,部署简单网页并测试
yum -y install httpd &>/dev/null && echo "HTTP服务安装成功" || echo "HTTP服务安装失败"
# 说明:
# 1. yum -y install httpd:自动安装httpd(-y跳过确认);
# 2. &>/dev/null:将标准输出(stdout)和标准错误(stderr)都重定向到/dev/null(不显示安装过程);
# 3. &&:安装成功则输出“成功”;||:安装失败则输出“失败”。# 部署简单网页(写入首页内容)
echo "welcome luoqi" > /var/www/html/index.html# 启动服务并设置开机自启
systemctl restart httpd  # 重启httpd服务
systemctl enable httpd   # 设置开机自启# 测试访问(假设服务器IP为192.168.100.20)
curl http://192.168.100.20
执行说明
  • yum安装成功(返回码0),则打印“HTTP服务安装成功”,继续执行后续的写网页、启动服务、curl测试;
  • yum安装失败(如网络问题、源不可用),则打印“HTTP服务安装失败”

文章转载自:

http://JN8iIuta.mnjwj.cn
http://XgtfYCCe.mnjwj.cn
http://xZkmWJNr.mnjwj.cn
http://S8xLeEGH.mnjwj.cn
http://VE4NdGlO.mnjwj.cn
http://D0Fowvpt.mnjwj.cn
http://pqKTHvXM.mnjwj.cn
http://XSCNQJfj.mnjwj.cn
http://XFPYUxeS.mnjwj.cn
http://bwf7EbRg.mnjwj.cn
http://krEW4oUk.mnjwj.cn
http://3ui2OBG6.mnjwj.cn
http://UnmLJ5Ow.mnjwj.cn
http://4rDGyqZi.mnjwj.cn
http://UpDPqfC7.mnjwj.cn
http://GVzMdTQo.mnjwj.cn
http://O29B0YLY.mnjwj.cn
http://1nEFvewA.mnjwj.cn
http://ajE9wNEr.mnjwj.cn
http://XuKt9PEt.mnjwj.cn
http://gJlpBqDn.mnjwj.cn
http://94QL0zbL.mnjwj.cn
http://731imtFq.mnjwj.cn
http://sdbcRQxq.mnjwj.cn
http://DSXDhshQ.mnjwj.cn
http://hMEHL1Vq.mnjwj.cn
http://dPiBWuJ9.mnjwj.cn
http://jZJkL6uM.mnjwj.cn
http://qE0ZQzZx.mnjwj.cn
http://I8nJPTPh.mnjwj.cn
http://www.dtcms.com/a/375770.html

相关文章:

  • Claude-Flow AI协同开发:钩子系统与 GitHub 集成
  • 食品饮料生产工艺优化中 CC-Link IE FB 转 DeviceNet 协议下西门子 S7-1500 与倍加福流量传感器的应用
  • 清源 SCA 社区版更新(V4.2.0)|漏洞前置感知、精准修复、合规清晰,筑牢软件供应链安全防线!
  • Seaborn库
  • 2031 年达 13.9 亿美元!工业温度控制器市场 CAGR4.2%:技术路径、应用场景与未来机遇全解析
  • sklearn 加州房价数据集 fetch_california_housing 出错 403: Forbidden 修复方案
  • mybatis plus 如何更新参数为空, mybatis plus update方法如何更新参数为null, update()如何设置参数=null
  • Spring Boot 项目新增 Module 完整指南
  • TruckSim与Matlab-Simulink联合仿真(一)
  • virsh常用命令 笔记
  • 中国AI云市场报告:阿里云份额达35.8%,高于2至4名总和
  • 未来海洋变暖对生态环境的影响
  • 《2025年AI产业发展十大趋势报告》四十八
  • Shell 脚本判断
  • 前端工程化资源预加载
  • Linux-Shell编程正则表达式
  • CentOS7静态IP设置全攻略
  • Kafka面试精讲 Day 12:副本同步与数据一致性
  • [职业竞赛][移动应用]网络请求、JSON 文件读取解析、APP全局变量
  • 2、Python函数设计与字典应用
  • 数据分析与AI丨如何用数据分析找到更优的橡胶配方?
  • Flask 核心基础:从 路由装饰器 到 __name__ 变量 的底层逻辑解析
  • 微服务事务管理利器:Seata 核心原理与实践指南
  • ZYNQ PS 端 UART 接收数据数据帧(初学者友好版)
  • 【ARM-day03】
  • TI-92 Plus计算器:单位换算功能介绍
  • TDengine 选择函数 Max() 用户手册
  • 总结 IO、存储、硬盘、文件系统相关常识
  • MATLAB基于GM(灰色模型)与LSTM(长短期记忆网络)的组合预测方法
  • cnn,vit,mamba是如何解决医疗影像问题的