目录
[1.1 你每天都在用Shell,只是没意识到](#1.1 你每天都在用Shell,只是没意识到)
[1.2 Shell在系统中的位置](#1.2 Shell在系统中的位置)
[1.3 Shell的多样性](#1.3 Shell的多样性)
[1.4 什么是Shell脚本?](#1.4 什么是Shell脚本?)
[二、第一个脚本:Hello World](#二、第一个脚本:Hello World)
[2.1 创建并编写脚本](#2.1 创建并编写脚本)
[2.2 赋予执行权限](#2.2 赋予执行权限)
[2.3 执行脚本](#2.3 执行脚本)
[4.1 定义变量:一条严格的语法](#4.1 定义变量:一条严格的语法)
[4.2 引用变量的多种写法](#4.2 引用变量的多种写法)
[4.3 环境变量 vs 局部变量](#4.3 环境变量 vs 局部变量)
[4.4 只读变量与删除变量](#4.4 只读变量与删除变量)
[4.5 命令替换:把命令结果存进变量](#4.5 命令替换:把命令结果存进变量)
一、引言:Shell是什么?
1.1 你每天都在用Shell,只是没意识到
每当你通过SSH登录Linux,看到这个提示符:
bash
root@server:~$ _
你就在Shell 里面了。你输入ls、cd、top,回车后看到结果------这个"接收你输入的命令、传给系统执行、把结果展示给你"的程序,就是Shell。
1.2 Shell在系统中的位置
如果把Linux想象成一家公司:
| 角色 | 对应组件 | 职责 |
|---|---|---|
| 董事长 | 内核(Kernel) | 掌控所有硬件资源,但不直接和基层员工说话 |
| 总经理秘书 | Shell | 把员工的诉求翻译成董事长听得懂的语言,把董事长的批复传达给员工 |
| 员工 | 你 | 想做事,但无法直接指挥硬件,必须通过秘书 |
从技术架构看:
text
用户 → 终端模拟器 → Shell → 系统调用 → 内核 → 硬件
-
终端(Terminal):你看到那个黑框框窗口(如GNOME Terminal、iTerm2)
-
Shell:在终端里运行的程序(如Bash、Zsh、Fish),负责解释你输入的命令
-
内核:真正干活的人
1.3 Shell的多样性
Linux上有多种Shell可供选择:
bash
cat /etc/shells # 查看系统支持哪些Shell
echo $SHELL # 查看当前使用的Shell
常见的Shell:
| Shell | 全称 | 特点 |
|---|---|---|
sh |
Bourne Shell | Unix原始Shell,功能最简 |
bash |
Bourne Again Shell | Linux默认Shell,功能强大 |
zsh |
Z Shell | 兼容bash,更强的交互体验 |
dash |
Debian Almquist Shell | 极简,启动快,Ubuntu的/bin/sh指向它 |
本文及整个专栏的脚本均使用bash------它是Linux发行版的事实标准,语法兼容性最广。
1.4 什么是Shell脚本?
当你把多条命令按顺序写进一个文件,加上一些逻辑控制(如果...就...),这个文件就是Shell脚本。
bash
#!/bin/bash
# 这是我写的第一个Shell脚本
echo "Hello, Shell!"
date
whoami
这三行命令如果每次都要手动逐一输入,很烦。写成脚本后,一句./hello.sh全搞定。这就是Shell脚本的第一层意义:把重复操作变成一键执行。
二、第一个脚本:Hello World
2.1 创建并编写脚本
bash
# 创建脚本文件
vim hello.sh
写入以下内容:
bash
#!/bin/bash
# 我的第一个Shell脚本
echo "Hello World!"
echo "今天是:$(date)"
echo "当前用户:$(whoami)"
逐行解释:
-
#!/bin/bash:Shebang(也叫Hashbang),告诉系统"用/bin/bash这个解释器来执行本文件" -
# 我的第一个...:注释(以#开头的行不执行) -
echo:输出文本到屏幕 -
$(date):命令替换------先执行date命令,把输出结果嵌入到这里
2.2 赋予执行权限
bash
ls -l hello.sh # 默认没有执行权限(-rw-r--r--)
chmod +x hello.sh
ls -l hello.sh # 多了一个x(-rwxr-xr-x)
2.3 执行脚本
bash
./hello.sh
输出:
text
Hello World!
今天是:Sun Apr 26 15:30:00 CST 2026
当前用户:zhangsan
为什么是./hello.sh而不是直接hello.sh?
Linux只在PATH环境变量指定的目录中查找可执行文件(如/usr/bin、/usr/local/bin)。当前目录一般不在PATH中(出于安全考虑),所以需要加上./明确告诉系统:"就在当前目录找"。
三、三种执行方式的本质区别
执行Shell脚本有三种方式,它们看似一样,实则不同:
bash
# 方式一:直接执行(需要x权限)
./hello.sh
# 方式二:用bash命令执行(不需要x权限)
bash hello.sh
# 方式三:source执行(在当前Shell中执行)
source hello.sh
. hello.sh # . 是 source 的简写
| 对比维度 | ./hello.sh |
bash hello.sh |
source hello.sh |
|---|---|---|---|
| 需要x权限 | 是 | 否 | 否 |
| 启动方式 | 启动子Shell | 启动子Shell | 当前Shell中执行 |
| 对当前环境的影响 | 不改变当前Shell | 不改变当前Shell | 会改变当前Shell |
| Shebang生效 | 是 | 忽略(用bash) | 是 |
什么时候必须用source?
当你修改了~/.bashrc配置后,希望立即生效:
bash
source ~/.bashrc # 在当前Shell中加载配置,立即生效
如果写成bash ~/.bashrc,会在子Shell中执行,子Shell退出后一切环境变量都丢了,等于白干。
四、变量:脚本的"记忆细胞"
脚本不只是顺序执行命令,还需要记住数据 、传递信息。这靠的就是变量。
4.1 定义变量:一条严格的语法
bash
#!/bin/bash
# 定义变量(注意:= 两边不能有空格!)
name="zhangsan"
age=25
pi=3.14
current_time=$(date)
# 引用变量(用$符号)
echo "姓名:$name"
echo "年龄:$age"
echo "Pi的值:$pi"
echo "当前时间:$current_time"
最容易犯的错误:
bash
name = "zhangsan" # 错误!Shell会把name当成命令执行
name ="zhangsan" # 错误!
name= "zhangsan" # 错误!
name="zhangsan" # 正确
为什么=两边不能有空格?
Shell把空格视为命令和参数的分隔符。name = "zhangsan"被解析为"执行name命令,参数是=和zhangsan"------而系统里根本没有name这个命令。
4.2 引用变量的多种写法
bash
name="world"
echo $name # world
echo ${name} # world(花括号明确变量边界)
echo "${name}" # world(双引号内解析变量)
echo '${name}' # ${name}(单引号原样输出,不解析)
花括号{}的必要场景:
bash
prefix="super"
echo "$prefixman" # 空值(Shell找的是prefixman变量)
echo "${prefix}man" # superman(明确边界)
推荐习惯 :始终用${变量名}的写法,避免边界不明确导致的bug。
4.3 环境变量 vs 局部变量
bash
# 局部变量:只在当前脚本中有效
my_var="hello"
# 环境变量:当前Shell及所有子进程都能访问
export MY_GLOBAL="visible everywhere"
典型的环境变量:
-
$HOME:当前用户家目录 -
$PATH:命令搜索路径 -
$USER:当前用户名 -
$PWD:当前工作目录 -
$RANDOM:生成一个随机数 -
$?:上一条命令的退出状态码
bash
echo "我的家目录:$HOME"
echo "命令搜索路径:$PATH"
echo "当前用户:$USER"
echo "随机数:$RANDOM"
4.4 只读变量与删除变量
bash
#!/bin/bash
readonly author="zhangsan"
author="lisi" # 报错!author是只读变量
temp="delete me"
unset temp # 删除变量
echo $temp # 空值
4.5 命令替换:把命令结果存进变量
两种等价写法:
bash
# 语法一:$(命令) —— 推荐
current_dir=$(pwd)
files_count=$(ls | wc -l)
# 语法二:`命令` —— 老式写法,不推荐(嵌套时易读性差)
current_dir=`pwd`
推荐使用$(),因为嵌套时更清晰:
bash
# 统计某个目录下的文件数量
count=$(ls $(pwd) | wc -l)
# 如果换成反引号:count=`ls \`pwd\` | wc -l` —— 可读性差
五、本篇小结
Shell的本质:介于用户和内核之间的命令解释器,bash是Linux的事实标准。
Shebang :#!/bin/bash告诉系统用哪个解释器执行脚本。写脚本第一行带上它是好习惯。
三种执行方式:
-
./script:标准执行,需要x权限,启动子Shell -
bash script:不需要x权限,启动子Shell,忽略Shebang -
source script:在当前Shell执行,会改变当前环境
变量三要点:
-
定义:
变量名=值,等号两边绝不能有空格 -
引用:
$变量名或${变量名} -
命令替换:
$(命令)获取命令输出
动手练习
bash
#!/bin/bash
# 练习脚本:创建一个系统信息报告
# 1. 定义变量
report_time=$(date "+%Y-%m-%d %H:%M:%S")
host_name=$(hostname)
current_user=$(whoami)
kernel_ver=$(uname -r)
cpu_count=$(nproc)
# 2. 输出报告
echo "========== 系统信息报告 =========="
echo "报告时间:${report_time}"
echo "主机名:${host_name}"
echo "当前用户:${current_user}"
echo "内核版本:${kernel_ver}"
echo "CPU核心数:${cpu_count}"
echo "=================================="
将上述内容保存为system_info.sh,赋予执行权限,运行查看结果。
六、下篇预告
掌握了变量的基本使用,下一篇我们将深入学习Shell变量与数据类型,包括:
-
如何获取字符串长度、截取子串
-
环境变量的配置文件(
~/.bashrc、~/.bash_profile) -
位置参数变量(把命令行参数传给脚本)
这些是构建复杂脚本逻辑的基础素材。
延伸思考 :执行echo $SHELL看你的当前Shell,再执行cat /etc/shells看系统装了哪些Shell。你有没有想过,脚本第一行的#!/bin/bash如果改成#!/usr/bin/python3会怎样?试试看------这正体现了Shebang的通用性:任何解释型语言都可以用这种方式写"可执行脚本"。