Linux中的Shell脚本基础
一、什么是Shell脚本
Shell 脚本是一种用 Shell 命令编写的脚本程序,用于在 Unix/Linux 系统的命令行环境中自动化执行任务。
它由一系列命令、逻辑控制语句(如条件判断、循环)和函数组成,保存为文本文件(通常以 .sh
为扩展名),由 Shell 解释器(如 Bash、Zsh)逐行解析执行。
Shell 脚本的核心特点:
-
基于命令行:直接调用系统命令(如
ls
、grep
、awk
),无需编译。 -
轻量级:适合快速开发小型自动化任务。
-
跨平台性:在支持相同 Shell 的系统(如 Linux、macOS)中通用。
示例:
#!/bin/bash
# 这是一个简单的 Shell 脚本
echo "Hello World!" # 输出文本
mkdir backup # 创建目录
cp *.txt backup/ # 复制所有 txt 文件到 backup 目录
二、Shell脚本存在的意义
Shell 脚本的主要意义是提升效率和实现自动化,尤其在系统管理、运维、数据处理等领域中不可或缺。
核心价值:
-
自动化重复操作
-
例:批量重命名文件、定期清理日志、自动备份数据。
-
替代手动逐条输入命令,减少人为错误。
-
-
简化复杂任务
-
例:一键部署服务、集成多步骤流程(如下载数据 → 处理 → 上传结果)。
-
通过逻辑控制(如
if
、for
)组合多个命令。
-
-
系统管理与监控
-
例:检查磁盘空间、监控进程状态、发送报警邮件。
-
直接调用系统工具(如
df
、ps
、cron
)。
-
-
快速原型开发
-
例:临时测试某个功能或流程。
-
无需编译,修改后立即运行。
-
Shell脚本与其他编程语言的对比:
场景 | Shell 脚本 | Python/Perl |
---|---|---|
文件操作 | 直接调用 grep 、sed 、awk ,语法简洁 | 需要导入库,代码量稍多 |
系统命令交互 | 无缝执行命令,无需额外封装 | 需通过 subprocess 等模块调用 |
复杂逻辑/数据处理 | 适合简单逻辑,复杂场景代码可读性差 | 支持面向对象、数据结构,更易维护 |
性能要求 | 适合轻量级任务,频繁启动子进程效率较低 | 适合计算密集型任务 |
Shell 脚本的典型应用场景:
-
日常运维:自动化日志切割、清理过期文件、服务状态监控。
-
部署与发布:一键编译代码、打包应用、更新服务器。
-
数据处理:批量转换文件格式、提取文本内容、生成统计报表。
-
开发辅助:运行测试用例、生成文档、环境配置。
三、Shell脚本中的基本元素
Shell 脚本的基本元素是构建自动化任务和逻辑流程的核心组成部分。
脚本的基本结构
1. Shebang声明(也可以叫脚本幻数)(必选)
#!/bin/bash
-
作用:指定脚本解释器路径(例如
#!/bin/bash
或#!/usr/bin/bash
) -
必须放在脚本第一行,且Shebang 声明前不能有任何字符(包括空格、空行),否则会被忽略,可能被当作普通文本执行。
-
脚本幻数(Shebang) 是计算机领域中对脚本文件首行
#!
声明的俗称,也被直接称为 “Shebang 声明”(读作 "hash-bang")。它是脚本文件的身份标识与执行指令,核心作用是告诉操作系统:“这个脚本需要用哪个解释器来运行”。
(1) Shebang 的本质
-
不是解释器本身:Shebang(
#!
)本身只是一个指令前缀,用于告诉操作系统使用哪个解释器来执行脚本。 -
举例:
-
#!/bin/bash
:指定用bash
解释器执行脚本。 -
#!/usr/bin/python3
:指定用 Python 3 解释器执行脚本。
-
(2) Shebang 的工作流程
当执行脚本(如 ./script.sh
)时,操作系统按以下步骤处理:
-
读取文件首行:检查是否包含
#!
。 -
解析解释器路径:提取
#!
后的路径(如/bin/bash
)。 -
启动解释器:将脚本路径作为参数传递给该解释器,由解释器逐行执行脚本内容。
-
关键点:Shebang 仅负责触发解释器,而解释命令的实际工作由解释器完成。
-
(3) 常见误区澄清
误区 | 正解 |
---|---|
“Shebang 是解释器” | Shebang 是指向解释器的指令,解释器是 /bin/bash 等具体程序 |
“Shebang 解释脚本命令” | 解释命令的是解释器程序(如 bash ),而非 Shebang 本身 |
“Shebang 是脚本的一部分” | Shebang 是由操作系统内核处理的元指令,不会传递给解释器 |
(4) 类比理解
-
Shebang 类似钥匙:告诉系统“用哪把钥匙(解释器)打开这把锁(脚本)”。
-
解释器 类似锁匠:真正执行解锁(解释命令)操作的是锁匠(如
bash
)。
2. 注释说明(推荐使用)
# 脚本功能:备份日志文件
# 作者:YourName
# 创建时间:2023-10-01
-
单行注释用
#
-
多行注释可通过
<<EOF...EOF
或 : "...
" 实现 -
示例:
-
3. 变量定义(可选但常用)
LOG_DIR="/var/log"
BACKUP_DIR="/backup"
TODAY=$(date +%Y%m%d) # 获取当前日期
4. 主逻辑代码(核心)
(1) 基础命令
echo "开始备份日志..." # 输出信息
cp -v $LOG_DIR/*.log $BACKUP_DIR/${TODAY}_logs/
(2) 流程控制
if [ -d "$BACKUP_DIR" ]; thenecho "备份目录存在"
elsemkdir -p "$BACKUP_DIR"
fifor file in $LOG_DIR/*.log; dogzip "$file"
done
(3) 函数定义(可选)
clean_old_backups() {find $BACKUP_DIR -name "*.log.gz" -mtime +7 -delete
}
clean_old_backups # 调用函数
5. 退出状态码(推荐使用)
exit 0 # 0表示成功,非0表示失败(通常1-255)
四、脚本的书写规范
1. 书写规范注意事项
规范项 | 关键要点 |
---|---|
文件名 | 脚本文件名应见名知意,明确体现功能,如 |
Shebang声明 (脚本幻数) | 首行必须指定脚本解释器,例如 #!/bin/bash 或 #!/usr/bin/env bash。 |
注释 | 使用英文注释,尽量不要用中文注释,防止本机或切换系统环境后中文乱码的困扰,文件开头加创建日期、作者、版本、用途等信息。 |
内部命令 | 优先使用 echo 、eval 等内置命令,减少外部命令调用(避免频繁创建子进程)。 |
代码简化 | 组合命令,减少冗余操作。 组合命令:通过管道、逻辑符 && 或 || 减少代码行数。 |
缩进与结构 | 统一缩进,体现代码结构,增强可读性。 |
错误处理 | 启用
|
2. 使用vim命令书写脚本的设定
Vim 自动编写脚本主属性信息的配置方法
~/.vimrc
是 Vim 编辑器的用户配置文件,用于自定义 Vim 的行为、快捷键、插件、界面样式等。它位于用户的主目录(~
)下,是 Vim 的核心配置文件。
通过 Vim 的 模板自动插入功能,可以在新建脚本时自动生成固定格式的头部信息(如作者、日期、描述等)。以下是详细配置步骤及示例:
(1)理解 ~/.vimrc这个文件的核心作用
.vimrc
的核心作用
功能 | 示例配置 | 说明 |
---|---|---|
基础设置 | set number | 显示行号 |
语法高亮 | syntax on | 启用代码语法高亮 |
缩进控制 | set tabstop=4 | 设置制表符为 4 个空格 |
快捷键映射 | nnoremap <C-s> :w<CR> | 按 Ctrl + S 保存文件 |
插件管理 | call plug#begin('~/.vim/plugged') | 声明插件管理器(如 vim-plug) |
自动命令 | autocmd BufNewFile *.sh 0r ~/.vim/templates/shell_header.tpl | 新建文件时加载模板。 |
较难理解的示例配置解析:
1、nnoremap <C-s> :w<CR>
该命令由三部分组成:
-
nnoremap
:表示在普通模式(Normal Mode) 下创建一个非递归映射(noremap
会禁止映射中调用其他映射,避免递归循环)。 -
<C-s>
:触发映射的快捷键,即Ctrl + s
(<C>
代表 Ctrl 键,<s>
代表 s 键)。 -
:w<CR>
:映射执行的命令,:w
是 Vim 中保存文件的命令,<CR>
表示按下回车键(CR
是 Carriage Return 的缩写)。
2、call plug#begin('~/.vim/plugged')
该命令由三部分组成:
-
call
:Vimscript 中调用函数的关键字。 -
plug#begin(...)
:Vim-Plug 提供的函数,用于初始化插件管理器。 -
'~/.vim/plugged'
:参数,表示插件的安装目录。Vim-Plug 会将所有插件下载到这个目录下。
3、autocmd BufNewFile *.sh 0r ~/.vim/templates/shell_header.tpl
该命令由三部分组成:
-
autocmd
:Vim 的自动命令关键字,用于在特定事件发生时自动执行命令。 -
BufNewFile *.sh
:触发自动命令的事件,表示新建一个以.sh
结尾的文件时执行后续命令。 -
0r ~/.vim/templates/shell_header.tpl
:执行的命令,0r
表示在文件的第 0 行(即文件开头)读取并插入指定文件的内容,这里读取的是~/.vim/templates/shell_header.tpl
文件。
(2)配置 Vim 编辑器的用户配置文件
五、脚本执行方法
测试脚本内容:
[root@sakura1 桌面]# vim lee.sh
#!/bin/bash
cat
1、两种环境下运行脚本
(1)在当前环境下运行

(2)在指定环境中运行
通过路径来执行脚本时需要脚本文件有执行权限。
2、执行方式对比
执行方式 | 命令示例 | 是否需要执行权限 | 进程树表现 | 执行环境 |
---|---|---|---|---|
1. 当前Shell环境 | . lee.sh & | 否 | bash → cat | 当前Shell进程 |
source lee.sh & | 否 | bash → cat | 当前Shell进程 | |
2. 新建子Shell | sh lee.sh & | 否 | bash → sh → cat | 新建子Shell |
3. 路径执行 | /root/lee.sh & | 需要 | bash → /bin/bash → cat | 新建子Shell |
3、关键原理解析
-
source
与.
命令-
直接在当前Shell进程内执行脚本
-
脚本中的
cat
成为当前Shell的子进程(无中间进程) -
无需执行权限(文件只需读权限)
-
-
sh script.sh
-
启动新
/bin/sh
进程解释脚本 -
sh
进程作为当前Shell的子进程,cat
成为sh
的子进程 -
无需执行权限(
sh
作为解释器读取文件)
-
-
路径执行 (
/path/to/script
)-
依赖 Shebang 行 (
#!/bin/bash
) 选择解释器 -
需要执行权限 (
chmod +x
) -
进程树:当前Shell →
/bin/bash
→cat
-
4、后台执行 (&
) 现象
-
阻塞进程的处理
脚本中的cat
会持续等待输入,导致进程进入T
状态(暂停/后台阻塞):PID TTY STAT TIME COMMAND 17890 pts/2 T 0:00 /bin/bash /root/lee.sh # T = Stopped,父进程被阻塞 17891 pts/2 T 0:00 \_ cat # 子进程同样阻塞
-
恢复方法:
用fg
切回前台输入,或发送SIGCONT
信号 (kill -CONT PID
)
六、脚本调试
测试脚本:
[root@timinglee ~]# vim lcf.sh
#!/bin/bash
hostname
echo $USER
date
cat #这行的命令应为cal显示系统日历,这里是故意打错导致脚本错误,用来进行脚本调试展示
pwd
1、直接执行测试脚本的效果
脚本突然就卡住了,不能清晰的看出脚本的错误在哪里。
2、显示测试脚本执行过程的效果
明显可见脚本在执行到cat命令的时候因为cat命令没有写完整而导致了脚本被卡在cat命令这一步。
七、命令退出值
1、什么是退出值(Exit Status)
-
定义:每个命令执行后返回的整数状态码(0-255)
-
含义:
-
0
:成功执行 -
1-255
:执行失败(不同值代表不同错误类型)
-
-
重要性:Shell脚本中常用退出值判断命令执行结果
2、怎么查看和修改退出值
(1)查看退出值
# 查看上一个执行命令的退出值
echo $?
示例:
(2)修改退出值(在脚本中进行操作)
方法一:使用 exit
命令
在脚本中显式设置退出值:
#!/bin/bash
# 脚本内容...
exit 5 # 设置退出值为5
示例:
方法二:通过命令返回值
使用最后执行命令的返回值:
#!/bin/bash
grep "pattern" file.txt # 如果grep失败,自动返回非0值---当 grep 未找到匹配或出错时,
脚本会继承其非 0 退出状态,无需手动处理。
# 无需显式exit,自动继承grep的退出值---脚本的最终退出状态等于最后一条命令(grep)的退出
状态,无需添加exit语句。
grep "pattern" file.txt
- 核心命令:在
file.txt
中搜索包含 "pattern" 的行。- grep 的退出状态:
- 找到匹配行时返回
0
(成功);- 文件存在但无匹配时返回
1
;- 发生错误(如权限问题)或文件不存在时返回
2
。
示例:
下图为file文件内的内容
退出值为0的情况:
退出值为1的情况:
退出值为2的情况: