news 2026/10/16 4:04:35

Shell 脚本编程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Shell 脚本编程

Shell 脚本编程

📖简介:bash shell 编程入门,讲解什么是 shell、怎么写第一个脚本;shell 普通变量、环境变量、特殊位置变量;字符串子串截取;多种整数计算方式;test/[]/[[]]条件测试语法。

一、有关 Shell 编程

1.1 什么是 Shell

Shell 是命令解释器,负责解析执行用户输入的命令。登录 Linux 之后,所有交互操作都交给 shell 处理。

  • Linux 默认 shell:bash(Bourne‑Again Shell)
  • Solaris/FreeBSD 默认:sh
  • AIX 默认:ksh

类比:内核是操作系统核心,Shell 相当于包裹在内核外面的外壳,接收用户输入,转发给内核,再把内核输出展示给用户。

1.2 什么是 Shell 脚本

把多条命令写在文件中,批量执行,这种文件就是 shell 脚本。类似 Windows 的 bat 批处理。

  • 交互模式:键盘敲一条,立刻执行一条
  • 非交互模式:读取脚本文件,一次性批量执行全部语句

1.3 Shell 脚本的用途

Linux 几乎所有配置、日志、服务文件都是纯文本。shell 擅长处理文本,是运维自动化必备工具。

  • 批量检查多台服务器运行状态
  • 自动化部署、升级业务服务
  • 日志分析、定期备份

学好 shell 需要的基础:vim 编辑器、Linux 常用命令、grep/sed/awk 三剑客、了解常见服务。

学习建议:多写多练,从简单脚本入手,多模仿,变量命名见名知意,形成自己编码习惯。

1.4 Shell 两大分支

  1. Bourne 家族:sh、ksh、bash(CentOS 默认)
  2. C‑Shell 家族:csh、tcsh,语法接近 C 语言,BSD/macOS 常见。

二、创建第一个 Shell 脚本

2.1 脚本头部幻数#!

脚本第一行指定解释器,称为幻数。

#!/bin/bash

如果不写,系统会用当前 shell 执行;规范写法必须写第一行。#代表注释,除了第一行#!,其余 #后面内容全部是注释,不会执行。

示例脚本hello.sh

#!/bin/bash # Date:2025‑10‑09 # Author:Created by user # Description:第一个shell测试脚本 # Version:1.0 echo "Hello World !"

/bin/sh实际是 bash 的软链接。

[user@shell ~]$ ls -l /bin/sh lrwxrwxrwx. 1 root root 4 11月 2 17:33 /bin/sh -> bash

2.2 Shell 脚本 5 种执行方式

方式 1:bash/sh 直接执行,不需要 x 执行权限
[user@shell ~]$ bash hello.sh Hello World !
方式 2:给脚本增加执行权限,相对 / 绝对路径运行
[user@shell ~]$ chmod +x hello.sh # 相对路径 [user@shell ~]$ ./hello.sh # 绝对路径 [user@shell ~]$ /home/user/hello.sh
方式 3:source /.点号执行(在当前 shell 进程执行,不新建子 shell)

重点:source 执行脚本,脚本里面定义的变量会保留在当前 shell 环境。

[user@shell ~]$ source hello.sh # 等价写法 [user@shell ~]$ . hello.sh
方式 4:管道、输入重定向执行
[user@shell ~]$ bash < hello.sh [user@shell ~]$ cat hello.sh | bash
方式 5:放到 PATH 环境变量目录,直接脚本名运行
[user@shell ~]$ echo $PATH [user@shell ~]$ cp hello.sh ~/bin [user@shell ~]$ hello.sh

2.3 Shell 脚本编写良好习惯

  1. 第一行写#!/bin/bash指定解释器。
  2. 脚本开头增加版本、作者、描述注释,尽量使用英文注释,避免中文乱码。
  3. 成对符号{} [] '' "" ``一次性写全,再填入内容,防止漏写。
  4. 中括号[ ]内部两端必须保留空格[ 条件 ]。
  5. if、for、while、case 先把完整框架写出来,再填充业务代码。
  6. 使用缩进,提升可读性。
  7. 字符串赋值:简单字符串不加引号;带空格、变量解析用双引号;原样输出用单引号。
  8. 全部符号使用英文半角。

三、Shell 变量基础

变量:内存中临时存储数据,变量名由字母数字下划线组成,不能以数字开头。 bash 默认弱类型,不区分整数、字符串,全部当做字符串处理。

3.1 普通变量定义

三种赋值方式:

  1. 变量名=值:简单连续字符串
  2. 变量名='值':单引号,所见即所得,不解析变量
  3. 变量名="值":双引号,解析里面的变量、特殊符号

⚠️赋值等号左右绝对不能加空格。

[user@shell ~]$ a=192.168.1.2 [user@shell ~]$ b='192.168.1.2' [user@shell ~]$ c="192.168.1.2" [user@shell ~]$ echo "a=$a" a=192.168.1.2 # 单引号原样输出$符号,双引号解析变量 [user@shell ~]$ a=testval [user@shell ~]$ b='value is $a' [user@shell ~]$ c="value is $a" [user@shell ~]$ echo $b value is $a [user@shell ~]$ echo $c value is testval

3.2 把命令输出赋值给变量

两种写法,推荐$(),反引号```容易和单引号混淆。

[user@shell ~]$ CMD1=$(pwd) [user@shell ~]$ echo $CMD1 /home/user [user@shell ~]$ CMD2=`date +%A` [user@shell ~]$ echo $CMD2 Thursday

3.3 环境变量

环境变量可以传递给子 shell 进程;普通变量只在当前 shell 有效。 使用export导出为环境变量。

# 三种等价写法 export NAME=user NAME=user ; export NAME declare -x NAME=user

查看变量命令:

  • set:输出所有变量,普通变量 + 环境变量
  • env:只输出环境变量
  • declare:输出变量、函数、整型

常用内置环境变量

表格

变量说明
PATH命令搜索路径
HOME当前用户家目录
USER当前用户名
PWD当前工作目录
PS1终端提示符
LANG系统字符集
HISTSIZEhistory 历史命令条数
环境变量持久化配置文件
  • 用户生效:~/.bashrc(推荐)、~/.bash_profile
  • 全局所有用户:/etc/bashrc、/etc/profile、/etc/profile.d/*.sh

登录 shell 和非登录 shell 加载顺序: 登录 shell:/etc/profile→/etc/profile.d/*→~/.bash_profile→~/.bashrc→/etc/bashrc非登录 shell(ssh 非登录、执行脚本)只会加载~/.bashrc、/etc/bashrc。

unset 取消变量定义

[user@shell ~]$ unset NAME

四、Shell 进阶变量

4.1 位置参数特殊变量

执行脚本时从命令行传入参数。

表格

变量含义
$0脚本本身文件名(带路径则显示路径)
$1 $2 ... ${10}第 1、第 2… 第 10 个参数,大于 9 必须大括号${10}
$#传入参数总个数
$*全部参数,不加引号和$@行为一致;"$*"把所有参数合并成一个字符串
$@全部参数;"$@"保留每个参数独立,带空格参数也可以正确传递(推荐)

示例脚本 showargs.sh

#!/bin/bash echo "\$0 = $0" echo "\$1 = $1" echo "\$2 = $2" echo "\${10}= ${10}" echo "\$# = $#" echo "\$* = $*" echo "\$@ = $@" [user@shell ~]$ bash showargs.sh a b c d e f g h i j k

简单小脚本 ssh_ctl.sh

#!/bin/bash systemctl $1 sshd [user@shell ~]$ sudo bash ssh_ctl.sh stop [user@shell ~]$ sudo bash ssh_ctl.sh start [user@shell ~]$ sudo bash ssh_ctl.sh status

4.2 状态特殊变量

表格

变量说明
$?上一条命令退出返回值,0 成功,非 0 失败,最常用
$$当前 shell 脚本 PID 进程号
$!上一个后台运行进程 PID
$_上一条命令最后一个参数

示例:

[user@shell ~]$ ls /etc/hosts [user@shell ~]$ echo $? 0 [user@shell ~]$ ls /root ls: 无法打开目录/root: 权限不够 [user@shell ~]$ echo $? 2

4.3 内置命令 read、shift、echo

echo 输出
  • -n:不换行输出
  • -e:开启转义字符解析\n换行、\t制表符
[user@shell ~]$ echo -n "hello ";echo "world" hello world [user@shell ~]$ echo -e "hello\nworld" hello world
read 读取用户输入
# -p 提示文字,-s 不回显输入(密码) [user@shell ~]$ read -p "请输入内容:" str [user@shell ~]$ echo $str [user@shell ~]$ read -s -p "请输入密码:" pass [user@shell ~]$ echo $pass
shift 位置参数左移

每执行一次 shift,$2→$1、$3→$2,参数总数$#减一。 shift.sh

#!/bin/bash echo "第一个参数:$1" shift echo "shift之后第一个参数:$1" [user@shell ~]$ bash shift.sh apple banana orange 第一个参数:apple shift之后第一个参数:banana

4.4 变量子串截取与替换

假设变量str="abc123abc123"

表格

语法作用
${str}获取变量完整内容
${#str}获取字符串字符长度
${str:offset}从 offset 下标开始截取到末尾,下标从 0 开始
${str:offset:length}截取 offset 开始,length 个字符
${str#word}从开头删除最短匹配 word
${str##word}从开头删除最长匹配 word
${str%word}从结尾删除最短匹配 word
${str%%word}从结尾删除最长匹配 word
${str/pattern/rep}替换第一个匹配内容
${str//pattern/rep}全部全局替换

实操示例

[user@shell ~]$ str="abc123abc123" [user@shell ~]$ echo ${#str} 12 [user@shell ~]$ echo ${str:3} 123abc123 [user@shell ~]$ echo ${str:3:4} 123a # 替换示例 [user@shell ~]$ echo ${str/abc/DEF} DEF123abc123 [user@shell ~]$ echo ${str//abc/DEF} DEF123DEF123

4.5 变量默认值扩展

表格

语法行为
${var:-word}变量为空 / 未定义,返回 word;不修改原变量
${var:=word}变量为空 / 未定义,赋值 var=word 并返回
${var:?word}变量未定义,把 word 输出 stderr 报错退出
${var:+word}变量有值,返回 word;变量空则返回空

示例

[user@shell ~]$ unset test [user@shell ~]$ echo ${test:-"默认内容"} 默认内容 [user@shell ~]$ echo $test [user@shell ~]$ echo ${test:="hello"} hello [user@shell ~]$ echo $test hello

生产小技巧,防止变量为空导致危险操作

find ${path:-/tmp} -name "*.tar.gz" -type f -mtime +7 | xargs rm -f

五、Shell 数值计算

bash 原生只支持整数运算,不支持小数;小数使用bc / awk。

5.1 双小括号(( ))

支持+ - * / % ** ++ --运算、比较判断。

[user@shell ~]$ echo $((1+1)) 2 [user@shell ~]$ a=5 [user@shell ~]$ ((a=a*2)) [user@shell ~]$ echo $a 10 # 自增 [user@shell ~]$ a=10 [user@shell ~]$ echo $((a++)) 10 [user@shell ~]$ echo $a 11

5.2 let 命令

等价(( )),用于变量运算赋值,等号两边不能空格

[user@shell ~]$ i=2 [user@shell ~]$ let i=i+8 [user@shell ~]$ echo $i 10

5.3 expr 命令

注意:运算符前后必须有空格,乘号*需要反斜杠转义\*

[user@shell ~]$ expr 2 + 3 5 [user@shell ~]$ expr 3 \* 4 12

5.4 bc 计算器,支持小数运算

[user@shell ~]$ echo "scale=4; 1/3" | bc .3333

5.5 awk 做小数计算

[user@shell ~]$ echo "7.7 3.8" | awk '{print $1-$2}' 3.9

六、条件测试判断(test / [] / [[]] / (( )))

shell 判断命令执行返回值:0 = true 真,非 0 = false 假。

四种语法格式

  1. test 表达式
  2. [ 表达式 ]👉最常用,注意中括号内部必须空格
  3. [[ 表达式 ]]👉 bash 扩展,支持&& || =~正则匹配
  4. (( ))👉 专门做数字比较,不需要空格

6.1 文件测试

表格

参数含义
-d是否目录
-f是否普通文件
-e文件 / 目录是否存在
-r是否可读
-w是否可写
-x是否可执行
-L是否软链接
-s文件存在且大小不为 0
file1 -nt file2file1 修改时间比 file2 新
file1 -ot file2file1 修改时间比 file2 旧

示例:

[user@shell ~]$ [ -d /tmp ] && echo "目录存在" 目录存在 [user@shell ~]$ [ -f /etc/passwd ] && echo "普通文件" 普通文件

6.2 字符串测试

表格

参数含义
-z "$var"字符串长度为 0(空)返回真
-n "$var"字符串不为空返回真
"a" = "b"字符串相等
"a" != "b"字符串不相等

⚠️变量建议双引号包裹,防止变量为空出现语法报错。

[user@shell ~]$ name="" [user@shell ~]$ [ -z "$name" ] && echo "字符串为空" 字符串为空 [user@shell ~]$ str="hello" [user@shell ~]$ [ "$str" != "world" ] && echo "不相等" 不相等

[[ ]]支持正则匹配=~,正则不要加引号

[user@shell ~]$ num="12345" [user@shell ~]$ [[ "$num" =~ ^[0-9]+$ ]] && echo "全数字" 全数字

6.3 整数比较

[]`使用 `-eq -ne -gt -ge -lt -le` `(( ))`、`[[]]`可以直接用 `> < >= <= == !=

表格

符号 [] 中含义
-eq等于 equal
-ne不等于 not equal
-gt大于 greater than
-ge大于等于 greater equal
-lt小于 less than
-le小于等于 less equal

示例

[user@shell ~]$ [ 10 -gt 5 ] && echo "10大于5" 10大于5 [user@shell ~]$ (( 10 > 5 )) && echo "10大于5" 10大于5

6.4 逻辑运算符

  1. 在[ ] / test内部:-a逻辑与;-o逻辑或;!逻辑非
  2. 在[[ ]] / (( ))内部:&&与;||或;!非
  3. 表达式之间:&&前面成功才执行后面;||前面失败才执行后面
# [] 内部逻辑与 [user@shell ~]$ num=12 [user@shell ~]$ [ $num -gt 10 -a $num -lt 20 ] && echo "10<num<20" 10<num<20 # [[]] && [user@shell ~]$ [[ $num -gt 10 && $num -lt 20 ]] && echo "10<num<20" 10<num<20

多命令块,条件成立执行多条语句,使用{ 命令1;命令2; },注意大括号内侧前后空格、分号结尾。

[user@shell ~]$ [ -d /tmp/test ] || { mkdir -p /tmp/test echo "创建目录完成" }

📝小结

  1. shell 脚本第一行写#!/bin/bash幻数;执行脚本区分新建子 shell(bash ./xxx.sh)与 source(当前 shell 执行,保留变量)。
  2. 变量:双引号解析变量;单引号原样输出;$()捕获命令输出。环境变量用 export 导出,区分登录 shell / 非登录 shell 配置文件。
  3. 特殊变量:$0 $1 $# $* $@ $? $$ $!,"$@"是传递多参数最佳实践。
  4. 字符串子串${#var}取长度,${var:offset:length}截取,${var/pat/rep}替换;还有变量默认值扩展${var:-}。
  5. 整数运算优先(( ));小数使用 bc/awk;expr 注意运算符空格与转义。
  6. 条件测试:
    • [ ]通用,内部必须空格,整数用‑eq‑gt‑lt;
    • [[ ]]支持&& || =~正则;
    • (( ))专门数字比较,直接> < ==。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 4:38:14

基于DLBP+PCA+SVM的人脸识别复现:从原理到调参避坑指南

简介&#xff1a;这份PDF文献聚焦人脸识别中的特征提取与分类难题&#xff0c;面向计算机视觉、模式识别方向的学习者与研究人员&#xff0c;尤其适合正在研读经典算法、准备课程设计或论文写作的读者参考。资源包共1个PDF文件&#xff0c;大小约793KB&#xff0c;内容为期刊论…

作者头像 李华
网站建设 2026/10/15 9:41:41

J2ME贪吃蛇毕业设计源码解析:游戏循环与MVC架构

简介&#xff1a;一份面向Java初学者的完整毕业设计项目&#xff0c;内容为经典贪吃蛇游戏从零到一的完整设计与实现&#xff0c;完整展示从需求分析、界面绘制、键盘控制到碰撞检测、得分计数的开发流程&#xff0c;非常适合正在准备Java课程设计或毕业设计的在校学生。压缩包…

作者头像 李华
网站建设 2026/10/16 21:50:30

用Qt与C++实现迷宫游戏:DFS生成算法与QGraphicsView渲染实战

简介&#xff1a;一份基于Qt C框架的迷宫游戏完整项目&#xff0c;面向具备一定C基础、希望学习Qt图形界面与游戏逻辑开发的读者。项目实现了迷宫随机生成、玩家操控、通关路径自动计算等功能&#xff0c;覆盖DFS或Prim生成算法、QGraphicsView场景搭建、键盘事件响应等关键知识…

作者头像 李华
网站建设 2026/10/14 23:03:05

生鲜配送供应链管理系统:POS收银、门店WMS与离线同步一体化设计

1. 背景与整体设计思路做生鲜配送这块&#xff0c;真正把人逼疯的从来不是货源&#xff0c;也不是找不到客户&#xff0c;而是订单、库存、收银、会员这些环节各用各的系统&#xff0c;数据对不上&#xff0c;月底一算账全是窟窿。我见过太多生鲜配送商&#xff0c;白天忙得脚不…

作者头像 李华
网站建设 2026/10/16 16:56:33

开源音乐模型之后,MiniMax股价先起飞:纳入港股通单日大涨17%

开源音乐模型之后&#xff0c;MiniMax股价先起飞&#xff1a;纳入港股通单日大涨17% 【免费下载链接】MiniMax-Music3 项目地址: https://ai.gitcode.com/MiniMax-AI/MiniMax-Music3 一边是模型开源页面上"最长5分钟完整歌曲"的技术参数被工程圈反复咀嚼&…

作者头像 李华