Linux中的Shell脚本基础

一、什么是Shell脚本

Shell 脚本 是一种用 Shell 命令 编写的脚本程序,用于在 Unix/Linux 系统的命令行环境中自动化执行任务

它由一系列命令、逻辑控制语句(如条件判断、循环)和函数组成,保存为文本文件(通常以 .sh 为扩展名),由 Shell 解释器(如 Bash、Zsh)逐行解析执行。

Shell 脚本的核心特点

  1. 基于命令行 :直接调用系统命令(如 lsgrepawk),无需编译。

  2. 轻量级:适合快速开发小型自动化任务。

  3. 跨平台性:在支持相同 Shell 的系统(如 Linux、macOS)中通用。

示例

复制代码
#!/bin/bash
# 这是一个简单的 Shell 脚本
echo "Hello World!"  # 输出文本
mkdir backup         # 创建目录
cp *.txt backup/     # 复制所有 txt 文件到 backup 目录

二、Shell脚本存在的意义

Shell 脚本的主要意义是提升效率实现自动化,尤其在系统管理、运维、数据处理等领域中不可或缺。

核心价值

  1. 自动化重复操作

    • 例:批量重命名文件、定期清理日志、自动备份数据。

    • 替代手动逐条输入命令,减少人为错误。

  2. 简化复杂任务

    • 例:一键部署服务、集成多步骤流程(如下载数据 → 处理 → 上传结果)。

    • 通过逻辑控制(如 iffor)组合多个命令。

  3. 系统管理与监控

    • 例:检查磁盘空间、监控进程状态、发送报警邮件。

    • 直接调用系统工具(如 dfpscron)。

  4. 快速原型开发

    • 例:临时测试某个功能或流程。

    • 无需编译,修改后立即运行。

Shell脚本与其他编程语言的对比

场景 Shell 脚本 Python/Perl
文件操作 直接调用 grepsedawk,语法简洁 需要导入库,代码量稍多
系统命令交互 无缝执行命令,无需额外封装 需通过 subprocess 等模块调用
复杂逻辑/数据处理 适合简单逻辑,复杂场景代码可读性差 支持面向对象、数据结构,更易维护
性能要求 适合轻量级任务,频繁启动子进程效率较低 适合计算密集型任务

Shell 脚本的典型应用场景:

  1. 日常运维:自动化日志切割、清理过期文件、服务状态监控。

  2. 部署与发布:一键编译代码、打包应用、更新服务器。

  3. 数据处理:批量转换文件格式、提取文本内容、生成统计报表。

  4. 开发辅助:运行测试用例、生成文档、环境配置。

三、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)时,操作系统按以下步骤处理:

  1. 读取文件首行 :检查是否包含 #!

  2. 解析解释器路径 :提取 #! 后的路径(如 /bin/bash)。

  3. 启动解释器 :将脚本路径作为参数传递给该解释器,由解释器逐行执行脚本内容

    • 关键点 :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" ]; then
    echo "备份目录存在"
else
    mkdir -p "$BACKUP_DIR"
fi

for file in $LOG_DIR/*.log; do
    gzip "$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. 书写规范注意事项

规范项 关键要点
文件名 脚本文件名应见名知意,明确体现功能,如 backup_mysql.sh --> 就是备份数据库的脚本。
Shebang声明 (脚本幻数) 首行必须指定脚本解释器,例如 #!/bin/bash#!/usr/bin/env bash。
注释 使用英文注释,尽量不要用中文注释,防止本机或切换系统环境后中文乱码的困扰,文件开头加创建日期、作者、版本、用途等信息。
内部命令 优先使用 echoeval 等内置命令,减少外部命令调用(避免频繁创建子进程)。
代码简化 组合命令,减少冗余操作。 组合命令:通过管道、逻辑符 && 或 || 减少代码行数。
缩进与结构 统一缩进,体现代码结构,增强可读性。
错误处理 启用 set -euo pipefail 严格模式(错误退出、未定义变量报错、管道错误检测)。 -eerrexit):遇到错误立即退出 -unounset):检查到未定义变量时报错并终止 -o pipefail:管道命令的严格错误处理

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、关键原理解析

  1. source. 命令

    • 直接在当前Shell进程内执行脚本

    • 脚本中的 cat 成为当前Shell的子进程(无中间进程)

    • 无需执行权限(文件只需读权限)

  2. sh script.sh

    • 启动新 /bin/sh 进程解释脚本

    • sh 进程作为当前Shell的子进程,cat 成为 sh 的子进程

    • 无需执行权限(sh 作为解释器读取文件)

  3. 路径执行 (/path/to/script)

    • 依赖 Shebang 行 (#!/bin/bash) 选择解释器

    • 需要执行权限 (chmod +x)

    • 进程树:当前Shell → /bin/bashcat

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的情况:

相关推荐
拍客圈3 小时前
单服务器部署多个Discuz! X3.5站点并独立Redis配置方案
运维·服务器·redis
aigoushan4 小时前
零基础开始的网工之路第二十一天------性能优化
运维·服务器·网络
小声读源码4 小时前
【技巧】使用frpc安全地内网穿透ssh访问内网机器
运维·安全·ssh·内网穿透·frpc
guygg884 小时前
Linux中的阻塞信号与信号原理
linux·mysql·apache
mxpan5 小时前
Alpine Docker 容器中安装包缓存与 C/C++ 运行问题
运维·docker·容器
眠りたいです5 小时前
MySQL基础与常用数据类型浅析
linux·数据库·mysql
芊言芊语5 小时前
CAN2.0、DoIP、CAN-FD汽车协议详解与应用
运维·服务器·网络
听风lighting6 小时前
1. C++ WebServer项目分享
linux·c语言·c++·设计模式·嵌入式·webserver
chengf2236 小时前
WSL 安装使用和常用命令
linux
Lz__Heng6 小时前
记一次使用HPE SSMC管理停用HPE 3par存储报连接出错
运维·存储