news 2026/9/1 20:06:37

Shell脚本入门指南:从零开始掌握自动化运维核心技能

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Shell脚本入门指南:从零开始掌握自动化运维核心技能

1. 为什么必须学 Shell:一个运维工程师每天都在用的技能

很多刚开始接触 Linux 的同学都会有这样的困惑:Linux 命令我会敲不少,cd、ls、cp、rm 都挺熟练,为什么还要专门学 Shell 脚本?

这个问题的答案,在真实的生产环境中非常清晰。

假设你管理着 50 台 Linux 服务器,每天要做的事情包括:检查磁盘空间、清理过期日志、备份数据库文件、定时同步配置。如果你一台一台登录,逐条命令去敲,每天光重复操作可能就要耗费两三个小时。而如果你把这些操作写成 Shell 脚本,配合 crontab 定时任务,所有工作会在每天凌晨自动完成,早上打开电脑只需要看一份运行日志即可。

Shell 脚本就是这样一个“把命令变成程序”的工具。它不是一门新的编程语言,而是把 Linux 命令按逻辑组织起来,配合变量、循环、判断、函数等编程能力,让服务器自动完成重复性工作。

除了提高效率,Shell 脚本还是自动化运维的基石。现在企业招聘运维工程师和 DevOps 工程师,Shell 几乎是必考技能。不管是写自动化部署脚本、监控脚本、日志采集脚本,还是编写容器启动入口脚本,都离不开 Shell。即便是开发岗位,掌握 Shell 也能让你在处理构建、发布、排查线上问题时更从容。

从 CSDN 后台和招聘平台的热搜数据也能看出,shell脚本入门linux常用命令教程自动化运维 shell这类关键词常年处于高位。这说明 Shell 不是过时的技术,而是 Linux 生态中最基础、最持久的能力之一。

本文将会从零开始,不假设你有任何编程基础,逐步讲清楚 Shell 脚本的核心语法、常用命令组合、完整实战案例和常见坑点。读完并动手练习后,你就能独立编写自己的第一个自动化运维脚本。

2. 环境准备:开始前的几个必要检查

Shell 脚本的学习和运行,必须有一个 Linux 环境。这里不要求你一定购买云服务器,本地虚拟机、Windows 下的 WSL(Windows Subsystem for Linux)都可以。

2.1 选择操作系统与 Shell 版本

目前市面上主流的 Linux 发行版有两大家族:

家族代表系统常用软件包管理常见环境
Debian 系Ubuntu、Debian、Deepinapt开发测试、个人学习
RedHat 系CentOS、Rocky Linux、Alibaba Cloud Linuxyum / dnf企业服务器、生产环境

不同发行版之间,命令的基本语法一致,区别主要在软件包管理器和默认目录结构上。本文中的 Shell 语法和大部分命令在各发行版上是通用、可以直接运行的。

Shell 本身也有多种实现,常见的有:

  • bash(Bourne Again Shell):Linux 默认 Shell,功能最全面,也是本文主讲的版本。
  • sh(Bourne Shell):早期的 Shell,在一些脚本中会看到#!/bin/sh
  • zsh:macOS 默认 Shell,兼容 bash,交互体验更好。
  • dash:Debian 系系统中/bin/sh的实际指向,体积小、执行快,但缺少一些 bash 特性。

版本需要根据你的项目实际情况调整。如果你用的是 CentOS 7 或 Ubuntu 18.04 以上的系统,默认 bash 版本基本都在 4.x 以上,学习本文内容没有任何障碍。

2.2 检查当前环境

打开终端,执行以下命令查看当前 Shell 和版本:

echo $SHELL bash --version

输出示意:

/bin/bash GNU bash, 版本 4.2.46(2)-release (x86_64-redhat-linux-gnu)

如果你的系统没有 bash,可以使用系统的软件包管理器安装:

# Debian/Ubuntu sudo apt update && sudo apt install -y bash # CentOS/RHEL sudo yum install -y bash

2.3 创建实验目录与第一个脚本

为了接下来的学习,建议单独建立一个目录,避免测试文件散落各处:

mkdir -p ~/shell-lab && cd ~/shell-lab

然后创建一个最简单的脚本文件:

vim hello.sh

输入以下内容:

#!/bin/bash echo "Hello, Shell!"

保存退出后,有两种执行方式:

# 方式一:直接指定解释器执行,不要求脚本有执行权限 bash hello.sh # 方式二:给脚本添加执行权限后,直接运行 chmod +x hello.sh ./hello.sh

运行结果:

Hello, Shell!

这里需要注意:脚本第一行的#!/bin/bash称为 shebang,它告诉系统应该用哪个解释器来执行这个脚本。虽然写不写有时候都能运行,但建议每个脚本都写上,这样可以避免很多莫名其妙的兼容性问题。

3. Shell 核心语法拆解:从变量到函数

学 Shell 脚本,不需要死记硬背“知识点大全”,更有效的方式是按“我需要表达什么逻辑”去掌握对应的语法要素。下面我们把 Shell 编程需要的基础语法按功能逐一拆解。

3.1 变量:命名、赋值、引用与特殊变量

Shell 变量和编程语言中的变量类似,用来临时存储数据。定义一个变量的语法非常简单:

name="zhangsan" num=100

使用变量时,在变量名前加$符号即可:

echo $name echo "欢迎 $name 登录系统"

注意一个高频误区:等号两边不能有空格name = "zhangsan"是错误的写法,会被 Shell 解析成执行一个叫作name的命令,然后传入="zhangsan"参数。

变量名的规范是:由字母、数字、下划线组成,不能以数字开头。赋值内容如果包含空格,需要用双引号或单引号包裹:

full_name="Zhang San"

双引号和单引号是有区别的:

  • 双引号内的$变量名会被解析成变量值。
  • 单引号内的内容会原样输出,不解析任何变量。
name="zhangsan" echo "hello, $name" # 输出 hello, zhangsan echo 'hello, $name' # 输出 hello, $name

除了自定义变量,Shell 还内置了一批位置变量和特殊变量,在编写自动化脚本时非常常用:

变量含义
$0当前脚本的文件名
$1$2...脚本的第 1 个、第 2 个参数
$#参数的个数
$@所有参数列表(每个参数独立)
$*所有参数列表(整体作为单个字符串)
$?上一条命令的退出状态码,0 表示成功
$$当前 Shell 进程的 PID

写一个args.sh来验证特殊变量:

#!/bin/bash echo "脚本名称: $0" echo "第一个参数: $1" echo "参数个数: $#" echo "所有参数: $@" echo "上条命令退出码: $?"

运行:

bash args.sh hello world

输出:

脚本名称: args.sh 第一个参数: hello 参数个数: 2 所有参数: hello world 上条命令退出码: 0

另外,Shell 中还有shift这个常用命令,它可以把参数列表左移一位,也就是丢弃掉当前的$1,原来的$2变成$1。这个命令在编写需要循环处理大量参数的脚本时非常实用,后面实战案例中会用到。

3.2 字符串处理:截取、替换、判断长度

在自动化脚本中,字符串处理是最频繁的操作之一,例如处理日志文件路径、解析配置项、拼接日期等。

字符串截取的基本语法:

str="hello-shell-world" echo ${str:0:5} # 从第 0 个字符开始截取 5 个字符:hello echo ${str:6} # 从第 6 个字符截取到末尾:shell-world echo ${#str} # 字符串长度:17

字符串替换:

echo ${str/-/_} # 替换第一个匹配:hello_shell-world echo ${str//-/} # 替换全部匹配:helloshellworld

字符串判断是否为空:

if [ -z "$str" ]; then echo "str 为空" else echo "str 不为空" fi

在真实场景中,判断变量是否为空的场景非常常见,比如检查用户传参是否完整。建议养成习惯:变量在比较时加上双引号,例如[ -z "$var" ]而不是[ -z $var ],这样可以避免变量内容为空或包含空格时产生语法错误。

3.3 条件判断:if、case 与 test

条件判断是让脚本拥有“智能逻辑”的基础。Shell 中最常见的是if语句,配合[ ]test命令进行判断。

基本结构:

#!/bin/bash score=$1 if [ $score -gt 90 ]; then echo "优秀" elif [ $score -gt 60 ]; then echo "及格" else echo "不及格" fi

注意[ ]的左右括号和里面的表达式之间必须有空格,否则会报语法错误。为了方便记忆,可以把[看作test命令的别名。

文件相关的判断是脚本中最高频的操作:

[ -f "file.txt" ] # 判断是否为普通文件 [ -d "dir" ] # 判断是否为目录 [ -e "path" ] # 判断路径是否存在 [ -r "file.txt" ] # 判断是否可读 [ -w "file.txt" ] # 判断是否可写 [ -x "file.sh" ] # 判断是否可执行

数值判断和字符串判断用的运算符也容易混淆:

判断类型运算符示例
数值相等-eq[ $a -eq $b ]
数值不等-ne[ $a -ne $b ]
数值大于-gt[ $a -gt $b ]
数值小于-lt[ $a -lt $b ]
字符串相等===[ "$s1" = "$s2" ]
字符串不等!=[ "$s1" != "$s2" ]
字符串为空-z[ -z "$s1" ]
字符串非空-n[ -n "$s1" ]

&&表示“并且”,||表示“或者”。下面这个写法在脚本中很常见:

if [ -z "$1" ] || [ -z "$2" ]; then echo "请传入两个参数" exit 1 fi

当分支情况比较多时,case语句可读性比一连串的if-elif更好:

#!/bin/bash case $1 in start) echo "启动服务" ;; stop) echo "停止服务" ;; restart|reload) echo "重启服务" ;; *) echo "用法: $0 {start|stop|restart}" exit 1 ;; esac

*)是默认分支,对应其他所有未匹配的情况。每个分支结束时用两个分号;;收尾,最后用esac(case 反写)结束整个语句。

3.4 for 循环、while 循环与实战场景

循环是脚本最提效的语法之一。比如批量处理日志文件、批量创建用户、批量重命名文件,靠的是循环。

for循环最常见的有三种写法。

写法一:遍历列表

for ip in 192.168.1.1 192.168.1.2 192.168.1.3; do echo "Ping $ip" ping -c 1 $ip > /dev/null 2>&1 && echo "$ip 可达" || echo "$ip 不可达" done

写法二:使用seq生成数字序列

for i in $(seq 1 5); do echo "第 $i 次执行" done

写法三:C 语言风格

for ((i=1; i<=5; i++)); do echo "number: $i" done

while循环同样常用,重点是“当满足条件时持续执行”。例如持续检查某个进程是否存在:

#!/bin/bash counter=0 while [ $counter -lt 5 ]; do echo "counter=$counter" counter=$((counter + 1)) done

这里$((...))是 Shell 的算术运算语法,也可以简写为((counter++))

处理参数列表时,for配合$@是一种标准模式:

#!/bin/bash for arg in "$@"; do echo "处理参数: $arg" done

再结合前面说的shift命令,可以在while循环中逐步消费参数:

#!/bin/bash while [ $# -gt 0 ]; do echo "当前参数: $1" shift done

3.5 函数:封装复用逻辑

当一个脚本开始变得复杂,就应该把重复的逻辑封装成函数。Shell 函数定义很灵活,但有几个规范建议务必遵守。

函数定义的推荐写法是写清函数名和空括号,函数体用花括号包住:

#!/bin/bash # 定义一个日志函数 log_info() { echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" } log_error() { echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" } # 业务函数 check_disk() { local max=80 local usage=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%') if [ "$usage" -gt "$max" ]; then log_error "根分区使用率已达 $usage%" return 1 else log_info "根分区使用率正常:$usage%" return 0 fi } log_info "开始检查磁盘空间" check_disk if [ $? -eq 0 ]; then echo "磁盘状态正常" else echo "需要处理磁盘空间" fi

关于函数的几个关键点:

  • local关键字用于声明局部变量。如果不加local,函数里定义的变量都是全局的,外部也可能被误改。
  • 函数通过return返回状态码,范围是 0-255,0 表示成功,非 0 表示失败。如果要返回字符串结果,可以用echo输出,然后用$(函数名)捕获。
  • 函数可以先定义再调用,但一定要确保调用时函数已经被定义,不能像 C 语言那样声明前置。

3.6 常用符号与命令组合的坑

Shell 中有几个容易混淆的低频符号,在阅读他人脚本时经常遇到:

符号含义示例
;分号,命令分隔符,不关心前面命令是否成功cd /tmp; ls
&&只有前一条命令成功才执行后一条mkdir test && cd test
``
&后台执行命令./start.sh &
>重定向输出到文件,覆盖echo 123 > a.log
>>重定向输出到文件,追加echo 123 >> a.log
2>&1将标准错误重定向到标准输出command > a.log 2>&1
:Shell 内置的空操作命令,永远返回 0while :; do echo ok; done

特别提一下:这个命令,它不显眼但很实用。前面热词中也出现了: 这是一个 shell 内置的空操作命令。它常用于:

  • 充当死循环的条件:while :
  • 占位,避免脚本结构不完整:if [ -z "$1" ]; then :; else echo "有参数"; fi
  • 调试时临时注释掉某些逻辑,又不想破坏结构。

4. 自动化运维实战:三个可直接使用的脚本案例

本章我们进入实战环节。下面三个脚本是我认为 Shell 入门阶段最值得写一遍的案例,分别覆盖系统信息采集、批量文件处理和日志清理。案例难度从简单到中等,代码可以直接复制到自己的环境中运行。

4.1 系统信息采集脚本

运维工作第一步往往是了解机器状态:磁盘用了多少、内存还够不够、当前负载如何、系统已经运行多久。写一个脚本把这些信息一次性采集出来,是很好的练手项目。

创建sys_info.sh

#!/bin/bash # 描述: 采集 Linux 系统关键信息 # 用法: bash sys_info.sh echo "======== 系统基本信息 ========" echo "主机名: $(hostname)" echo "操作系统: $(cat /etc/os-release | grep PRETTY_NAME | cut -d '=' -f2 | tr -d '"')" echo "内核版本: $(uname -r)" echo "运行时间: $(uptime -p)" echo "" echo "======== 硬件资源使用情况 ========" echo "CPU 核心数: $(nproc)" echo "内存使用情况:" free -h | awk 'NR==1 || NR==2' echo "" echo "根分区磁盘使用情况:" df -h / | awk 'NR==1 || NR==2' echo "" echo "======== 网络信息 ========" # 获取本机主要 IP(排除回环地址) ip -o -4 addr show | awk '{print $2, $4}' | grep -v '^lo ' echo "" echo "======== 关键进程检查 ========" for pkg in sshd crond; do if pgrep -x "$pkg" > /dev/null 2>&1; then echo "$pkg 运行中" else echo "$pkg 未运行" fi done

运行方式:

bash sys_info.sh

运行结果类似:

======== 系统基本信息 ======== 主机名: vm-master-01 操作系统: "CentOS Linux 7 (Core)" 内核版本: 3.10.0-1160.el7.x86_64 运行时间: up 25 days, 3 hours ======== 硬件资源使用情况 ======== CPU 核心数: 2 内存使用情况: total used free shared buff/cache available Mem: 1.8G 1.2G 104M 8.5M 535M 459M ... ======== 网络信息 ======== eth0 192.168.1.10/24 ======== 关键进程检查 ======== sshd 运行中 crond 未运行

这个脚本用到了两个非常重要的小工具:awkgrepawk 'NR==1 || NR==2'表示只输出第 1 行和第 2 行,awk '{print $2, $4}'表示取每行的第 2 和第 4 列。grep -v表示排除匹配行。这些文本处理命令在 Shell 脚本中与循环、管道搭配使用,能解决绝大多数日志与输出解析问题。

4.2 批量重命名文件脚本

批量重命名文件是高频需求。比如批量把*.txt改为带日期前缀,把.log改成.bak,或者把文件名中的空格替换成下划线。用 Shell 写一个通用一点的批量重命名脚本,是一个很不错的实战练习。

创建rename_files.sh

#!/bin/bash # 描述: 批量重命名当前目录下的文件 # 用法: bash rename_files.sh 旧关键字 新关键字 if [ $# -ne 2 ]; then echo "用法: $0 旧关键字 新关键字" echo "示例: $0 .log .bak" exit 1 fi old_word="$1" new_word="$2" count=0 for file in *"$old_word"*; do # 防止目录下没有匹配文件时,* 被原样输出 if [ -e "$file" ]; then new_name="${file//$old_word/$new_word}" mv "$file" "$new_name" echo "已重命名: $file -> $new_name" count=$((count + 1)) fi done echo "共重命名 $count 个文件"

测试一下:

touch a.log b.log c.txt bash rename_files.sh .log .bak

输出:

已重命名: a.log -> a.bak 已重命名: b.log -> b.bak 共重命名 2 个文件

这个脚本有两个细节值得注意:

第一,for file in *"$old_word"*中的星号是通配符,Shell 会把它展开成匹配的文件列表。如果目录下没有匹配文件,循环变量会直接拿到一个不存在的路径*.log。因此循环体内先做[ -e "$file" ]判断,是健壮性的关键。

第二,${file//$old_word/$new_word}是前面语法部分讲过的“全局替换”,注意替换内容中如果包含/或特殊字符,写法需要调整。这个脚本适用于关键字中不包含斜杠的简单场景。

4.3 日志清理与磁盘告警脚本

日志清理是最典型的自动化运维场景。应用日志会不断增长,如果不清理,最终会耗尽磁盘空间。下面这个脚本完成两件事:

  1. 找出指定目录下 N 天前的日志文件并删除。
  2. 检查磁盘使用率,超过阈值则输出告警。

创建clean_logs.sh

#!/bin/bash # 描述: 清理指定目录下 N 天前的日志文件,同时检查磁盘空间 # 用法: bash clean_logs.sh /var/log/myapp 7 log_dir="$1" days="$2" threshold=85 # 参数检查 if [ -z "$log_dir" ] || [ -z "$days" ]; then echo "用法: $0 日志目录 保留天数" exit 1 fi if [ ! -d "$log_dir" ]; then echo "错误: $log_dir 目录不存在" exit 1 fi echo "开始清理 $log_dir 下 $days 天前的日志文件..." # 使用 find 命令找到并删除旧日志 deleted=$(find "$log_dir" -name "*.log" -type f -mtime +$days | wc -l) find "$log_dir" -name "*.log" -type f -mtime +$days -delete echo "已删除 $deleted 个日志文件" # 检查磁盘使用率 disk_usage=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%') echo "当前根分区使用率: $disk_usage%" if [ "$disk_usage" -ge "$threshold" ]; then echo "警告: 磁盘使用率已超过阈值 $threshold%,请及时处理!" else echo "磁盘使用率正常。" fi

运行示例:

bash clean_logs.sh /tmp/logs 7

预期输出:

开始清理 /tmp/logs 下 7 天前的日志文件... 已删除 5 个日志文件 当前根分区使用率: 68% 磁盘使用率正常。

这里find命令是核心:

  • -name "*.log"指定文件名模式。
  • -type f限定为普通文件,避免误删目录。
  • -mtime +$days表示文件修改时间在 N 天前。
  • -delete直接删除匹配文件。

在生产环境中,建议先去掉-delete,只打印出匹配的文件列表,人工确认后再真正执行删除。这也是所有删除类脚本的通用安全经验:先验证,再删除;先备份,再变更

将这个脚本加入 crontab,就可以实现每天自动清理:

crontab -e

添加一行:

0 3 * * * /bin/bash /root/scripts/clean_logs.sh /var/log/myapp 7 >> /var/log/clean_logs.log 2>&1

这行配置表示每天凌晨 3 点执行一次清理,脚本输出追加到日志文件中,方便观察执行情况。

5. 常见问题与排查思路

Shell 脚本在运行时报错,新手最容易无从下手。下面把最常见的几类问题汇总成表,并给出排查思路。

问题现象常见原因解决思路
./test.sh: 权限不够脚本文件没有可执行权限执行chmod +x test.sh,或用bash test.sh运行
bad interpreter: /bin/bash^M在 Windows 上编辑脚本,文件包含回车符使用dos2unix test.sh转换,或换用 Linux 编辑器
[: missing]'`if 判断里[ ]两侧没有加空格确保写成[ "$var" = "value" ]
command not found可能拼写错误,或环境变量 PATH 未包含命令路径检查命令名是=还是空格赋值,检查是否用了中文标点
变量赋值写成了name = "xx"等号两边不能有空格改成name="xx"
脚本没有输出任何内容可能脚本没有执行权限,或 shebang 写错bash -x script.sh调试运行查看执行过程
循环时*被当成普通字符目录下没有匹配的文件循环体内先加[ -e "$file" ]判断
$?获取不到正确退出码中间执行了 echo 等命令,覆盖了退出码把退出码先存到变量:ret=$?
日期或变量在单引号内不解析用了单引号包裹改成双引号"$var"
syntax error near unexpected token脚本语法错误,或者 if / for 结构不完整使用bash -n script.sh检查语法

除了上面的问题,这里额外推荐两个调试技巧。

第一个是bash -x,逐行跟踪脚本的执行过程,常被称为 Shell 脚本调试的“金钥匙”:

bash -x test.sh

它会打印出每条命令及其展开后的真实内容。比如echo $name实际展开为echo zhangsan,一眼就能看出变量值是否符合预期。

第二个是bash -n,只做语法检查,不实际执行,适合在执行前快速排查:

bash -n test.sh

如果没有语法错误,命令不会有任何输出。如果有错误,会直接指出出错行号。

新手遇到脚本行为不符预期时,不要猜,先运行bash -x看执行过程,再按上面表格对照排查,绝大多数问题都能定位。

6. Shell 编程最佳实践与工程建议

Shell 脚本入门容易,但写出“可维护、可排错、可上线”的脚本并不简单。以下经验是在实际运维和开发过程中逐渐总结出来的,希望你能从最初就养成这些习惯。

6.1 每个脚本都写注释和使用说明

脚本是给别人看的,也是给三个月后的自己看的。建议开头固定写清:脚本功能、使用方式、作者或维护日期。例如:

#!/bin/bash ########################################################### # 脚本名称: backup_data.sh # 功能: 备份 MySQL 指定数据库到 /data/backup 并压缩 # 用法: bash backup_data.sh <数据库名> # 作者: your_name # 更新: 2025-06-01 ###########################################################

写注释的成本很低,但在半年后排查问题时价值巨大。

6.2 脚本开头设置严谨选项

在脚本开头加入下面几个选项,可以显著增强脚本健壮性:

set -e # 遇到任何命令返回非 0 状态时立即退出脚本 set -u # 使用未定义变量时直接报错,避免变量名拼写错误 set -o pipefail # 管道命令中,只要有一个命令失败,整个管道返回失败

但这三个选项不一定是所有脚本的黄金标准。set -e在部分循环和判断场景下会“误伤”脚本,比如你本来希望某个命令失败后继续执行后续逻辑。建议在编写脚本时理解每个选项的意义,按需组合。更稳妥的做法是,在确实需要忽略某条命令失败时,显式追加|| true

command_that_may_fail || true

6.3 使用变量而不是重复硬编码

硬编码路径和参数会大大降低脚本的可移植性。例如,不要直接在脚本里写:

rm -rf /var/log/myapp/*.log

而是定义成变量:

LOG_DIR=/var/log/myapp find "$LOG_DIR" -name "*.log" -type f -delete

这样后续只需要维护变量即可,也能防止误操作写错目录。

6.4 删除和变更类命令要加保护

涉及rmmv、覆盖写入、数据库变更等危险操作时,遵循以下原则:

  • 先在测试环境执行,确认效果。
  • 删除前先打印将删除的文件列表,人工确认后再加-deleterm
  • 重要数据先备份或移动到一个回收目录。
  • 生产环境脚本不要裸写rm -rf,至少用变量、路径判断和日志记录保护。

比如可以在清理脚本里加上一行“防呆”判断:

if [ "$log_dir" = "/" ] || [ "$log_dir" = "/data" ]; then echo "危险路径,拒绝执行" exit 1 fi

6.5 日志记录比 echo 更重要

脚本在 crontab 中自动化运行后,没有人盯着屏幕看输出。所以关键操作必须写日志。统一的日志格式建议:

log() { echo "$(date '+%Y-%m-%d %H:%M:%S') $*" >> /var/log/my_script.log }

调用时:

log "开始执行备份任务" log "备份完成,文件大小: $(du -sh backup.tar.gz | awk '{print $1}')"

6.6 注意跨平台差异

  • 不要在脚本中用\r或 Windows 记事本编辑脚本。
  • /bin/bash/bin/sh的差异要清楚,如果脚本用到 bash 特性,shebang 写#!/bin/bash
  • 调用命令时尽量用绝对路径或确保 PATH 中包含相应目录,尤其是在 crontab 环境中,PATH 可能与登录 Shell 不一样。可以在脚本开头显式设置:
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

6.7 合理使用退出码

脚本的不同失败场景,建议返回不同的退出码。运维监控脚本可以通过$?判断失败类别:

exit 0 # 成功 exit 1 # 一般性错误 exit 2 # 参数错误

这在后续接入监控平台、自动化调度平台时非常有用。

7. 总结与进阶路线

走到这里,你已经掌握了 Shell 脚本从零到实战的核心知识。现在回顾一下,你应该已经具备以下能力:

  • 理解 Shell 脚本的作用和适用场景,能区分不同 Shell 的差异。
  • 熟练写出变量、字符串处理、条件判断、循环、函数等脚本基本结构。
  • 掌握$?$#$@shift等特殊变量,能处理脚本参数。
  • 能综合使用findawkgrepcrontab等命令完成自动化运维任务。
  • 对常见脚本报错有清晰的排查思路,知道用bash -xbash -n调试脚本。
  • 具备编写安全、可维护脚本的工程意识。

接下来的进阶方向,可以根据你的实际需求选择:

  • 学习文本处理三剑客的深入用法:grepsedawk。它们能让你的 Shell 脚本处理复杂文本时效率翻倍。
  • 学习如何用 Shell 封装复杂的部署流程,配合expect处理交互式输入,配合rsync做增量同步。
  • 学习 Shell 与其他工具结合,例如调用 Python 脚本处理复杂数据、调用 Docker 命令管理容器生命周期。
  • 如果从事云原生或平台研发,还要了解容器镜像的入口脚本通常也是 Shell 写的,Shell 是打通“系统命令”和“上层应用”的桥梁。

最终想说的是:Shell 脚本这门技术,入门门槛不高,但上限很高。判断你是否真正掌握它的标准,不是背了多少语法,而是遇到重复性工作时,你是否能下意识地想到“这个能用脚本自动跑掉”。带着这个思路去写脚本,你的进步会非常快。建议现在就打开终端,从第一个Hello, Shell!开始,把一个实际工作中的重复操作写成脚本,跑通它。脚本跑通的那一刻,你对 Shell 的理解就真正扎实了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 19:59:12

科研代码能跑,不等于结论正确:Codex适合科研人员吗?

先给结论 如果你的日常研究包含 Python、R、MATLAB 脚本、实验数据、软件依赖或论文代码仓库&#xff0c;Codex 值得纳入工具箱。它的优势不是“替你判断科研结论”&#xff0c;而是围绕真实项目文件工作&#xff1a;阅读代码、修改脚本、查看终端输出并继续排错。 如果你主要…

作者头像 李华
网站建设 2026/9/1 19:58:18

C语言字符串数组详解:内存模型与两种主流写法对比

C语言字符串数组&#xff0c;这一篇把内存模型和常见写法讲透字符串数组是 C 语言里绕不开的一个知识点。很多初学者卡在“字符数组”和“字符串数组”的区别上&#xff0c;又分不清char a[10][20]和char *a[10]到底谁适合哪种场景。这次就把字符串数组拆开讲清楚&#xff1a;怎…

作者头像 李华
网站建设 2026/9/1 19:58:02

灾害事件可视化仪表盘:用 Python 提取公开事件 API,并导出给 Tableau / Power BI

㊗️本期内容已收录至专栏《Python爬虫实战》,持续完善知识体系与项目实战,建议先订阅收藏,后续查阅更方便~ ㊙️本期爬虫难度指数:⭐⭐⭐⭐☆(高级) 🉐福利: 一次订阅后,专栏内的所有文章可永久免费看,持续更新中,保底1000+(篇)硬核实战内容。 全文目录: 🌟 开…

作者头像 李华
网站建设 2026/9/1 19:57:48

跑团Replay制作实战:从OBS多音轨录制到ffmpeg后期全流程

看跑团 Replay 已经成了不少人的固定娱乐方式&#xff0c;尤其是《寄生者之间》这类 PVP 秘密团&#xff0c;每一集都充满了互相试探、身份反转和“节目效果拉满”的名场面。很多观众看的时候会好奇&#xff1a;这种一群人挂在语音频道里聊天、GM 私下传信息、最后还要剪成完整…

作者头像 李华
网站建设 2026/9/1 19:57:14

JavaEE多线程(2)

1.死锁1.1产生死锁四个必要条件只要破坏其中一条就能打破死锁1&#xff09;互斥条件&#xff1a;锁是互斥的&#xff0c;同一时间只能一个线程拿到锁。2&#xff09;请求与保持&#xff1a;线程拿到一把锁&#xff0c;又申请另一把锁&#xff0c;并且不释放锁。3&#xff09;不…

作者头像 李华
网站建设 2026/9/1 19:49:29

DeepSeek Harness 上手实操:从装好到跑起来,再到插件管理,一篇全给你

如果你是个 AI Agent / 模型开发的人&#xff0c;最近应该没少听说 DeepSeek Harness。简单说&#xff0c;它是一个围绕 DeepSeek 模型打造的、可以自托管、能插件的智能体运行框架——所有能力都是插件&#xff0c;你想让它干什么&#xff0c;装个插件就行。 但网上的资料大多…

作者头像 李华