Shell 命令与基础完全指南
本文系统归纳 Shell 环境下的命令类型、查找机制、变量系统、I/O 重定向与管道、通配符与引号、流程控制、函数与数组、历史命令与别名等,每节均配有表格与 Mermaid 图 ,与《Linux命令完全指南》中「十五、Shell 基础与命令格式」互补,只增不减。
目录
- [一、Shell 概述与架构](#一、Shell 概述与架构)
- 二、工作目录与导航
- 三、命令类型与查找机制
- 四、变量系统
- 五、引号、转义与通配符
- [六、I/O 重定向与管道](#六、I/O 重定向与管道)
- [七、date 与 clock/hwclock](#七、date 与 clock/hwclock)
- [八、获取帮助(man / whatis / help)](#八、获取帮助(man / whatis / help))
- [九、echo 与 printf](#九、echo 与 printf)
- [十、file 与文件命名规则](#十、file 与文件命名规则)
- 十一、路径与命令展开
- [十二、Shell 脚本流程控制](#十二、Shell 脚本流程控制)
- 十三、函数
- 十四、数组与字符串操作
- 十五、历史命令、别名与快捷键
- [十六、作业控制(Job Control)](#十六、作业控制(Job Control))
- [十七、文本查看与 less/more 操作](#十七、文本查看与 less/more 操作)
- 十八、练习与速查
一、Shell 概述与架构
1.1 Shell 在系统中的位置

1.2 常见 Shell 类型
| Shell | 说明 | 路径 | 特点 |
|---|---|---|---|
| bash | Bourne Again Shell | /bin/bash |
Linux 默认,功能最全,推荐 |
| sh | Bourne Shell | /bin/sh |
最早的 Shell,POSIX 标准 |
| zsh | Z Shell | /bin/zsh |
macOS 默认,强大补全 |
| csh | C Shell | /bin/csh |
语法类似 C 语言 |
| ksh | Korn Shell | /bin/ksh |
兼容 sh,加入编程增强 |
| tcsh | TENEX C Shell | /bin/tcsh |
csh 增强版 |
| dash | Debian Ash | /bin/dash |
轻量,脚本执行快 |
bash
cat /etc/shells # 查看系统支持的 Shell
echo $SHELL # 查看当前使用的 Shell
chsh -s /bin/zsh # 切换默认 Shell
1.3 Shell 的两种工作模式
🐚 Shell
💬 交互模式
用户逐条输入
📜 脚本模式
批量执行命令
$ 等待输入
#!/bin/bash
| 模式 | 说明 | 典型场景 |
|---|---|---|
| 交互模式 | 终端逐条输入,Shell 逐条解释执行 | 日常操作、调试 |
| 脚本模式 | 将多条命令写入文件,一次批量执行 | 自动化、定时任务 |
1.4 Shell 脚本基本结构
bash
#!/bin/bash
# 第一行 shebang 指定解释器
# 这是注释
echo "Hello, Shell!" # 命令
exit 0 # 退出码(0=成功)
| 元素 | 说明 |
|---|---|
#!/bin/bash |
Shebang,指定脚本解释器 |
# |
注释(从 # 到行末被忽略) |
exit N |
脚本退出码,0 成功,非 0 失败 |
chmod +x script.sh |
给脚本加执行权限 |
./script.sh |
执行脚本 |
bash script.sh |
不需要执行权限也可运行 |
二、工作目录与导航
2.1 pwd:当前工作目录
- 全称:Printing Working Directory
- 含义:working directory = current directory(当前目录)
| 选项 | 说明 |
|---|---|
-P |
显示物理路径(解析符号链接) |
-L |
显示逻辑路径(默认) |
bash
pwd # 显示当前工作目录的绝对路径
/bin/pwd -P # 物理路径,如 /etc/rc.d/init.d
/bin/pwd -L # 逻辑路径,如 /etc/init.d
2.2 cd:切换目录
- 全称:change directory
- 家目录 :home directory,可用
~表示。
| 用法 | 说明 |
|---|---|
cd ~ 或 cd |
进入当前用户家目录 |
cd ~USERNAME |
进入指定用户的家目录 |
cd - |
在当前目录与上一次所在目录之间来回切换 |
cd .. |
返回父目录 |
cd ../.. |
返回上两级 |
cd /path |
进入绝对路径 |
三、命令类型与查找机制
3.1 命令的两种类型
| 类型 | 英文 | 说明 | 示例 |
|---|---|---|---|
| 内置命令 | built-in | Shell 内置,不产生子进程 | cd, echo, export, alias |
| 外部命令 | external | 文件系统中的可执行文件 | ls, grep, find, awk |
3.2 命令查找与执行流程
是
否
是
否
是
否
是
否
是
否
用户输入命令
是绝对/相对路径?
直接执行该文件
是别名 alias?
展开别名后执行
是内置命令?
Shell 直接执行
hash 缓存有记录?
从缓存路径执行
按 PATH 顺序查找
找到?
执行并记入缓存
command not found
命令执行优先级(从高到低):
| 优先级 | 类型 | 说明 |
|---|---|---|
| 1 | 绝对/相对路径 | 如 /bin/ls 或 ./script.sh |
| 2 | 别名(alias) | 如 alias ll='ls -l' |
| 3 | 内置命令 | 如 cd, echo, export |
| 4 | hash 缓存 | 已缓存的外部命令路径 |
| 5 | $PATH 查找 | 按 PATH 从左到右逐目录查找 |
3.3 type:查看命令类型
| 用法 | 说明 |
|---|---|
type COMMAND |
显示命令类型(内置/外部/别名) |
type -a COMMAND |
列出所有同名类型(内置 + 外部路径) |
type -t COMMAND |
仅输出类型关键字:alias / builtin / file / function / keyword |
bash
type echo # echo is a shell builtin
type ls # ls is aliased to 'ls --color=auto'(若有 alias)
type -a echo # 列出内置 + /usr/bin/echo
type -t cd # builtin
3.4 hash:命令路径缓存
- Shell 将解析过的外部命令路径缓存到 hash 表,再次执行直接查缓存,O(1)。
- 原则:缓存为王(Cache is King)。
| 用法 | 说明 |
|---|---|
hash |
查看已缓存的命令及命中次数 |
hash -r |
清空所有缓存 |
hash -d COMMAND |
删除指定命令的缓存 |
hash -p /path COMMAND |
手动添加缓存条目 |
四、变量系统
4.1 变量体系概览
Bash 变量
环境变量
export 全局
普通变量
当前 Shell
特殊变量
Shell 自动设置
位置参数
HOME PATH
USER SHELL LANG
name=value
退出码 进程ID
参数个数等
第1到第N个参数
4.2 变量定义与引用规则
| 规则 | 说明 | 示例 |
|---|---|---|
| 赋值 | 等号两侧不能有空格 | NAME=Jerry |
| 引用 | $ 或 ${} |
echo $NAME 或 echo ${NAME} |
| 双引号 | 变量会展开 | echo "Hello $NAME" |
| 单引号 | 变量不展开(原样输出) | echo 'Hello $NAME' |
反引号 / $() |
命令替换(嵌入命令结果) | ``TODAY=date +%F``` 或 TODAY=$(date +%F)` |
| 删除变量 | unset |
unset NAME |
| 只读变量 | readonly |
readonly PI=3.14 |
4.3 环境变量(全局变量)
| 变量 | 说明 |
|---|---|
$HOME |
当前用户家目录 |
$USER |
当前用户名 |
$UID |
当前用户 ID(0 = root) |
$SHELL |
当前 Shell 路径 |
$PATH |
命令搜索路径列表(冒号分隔) |
$PWD |
当前工作目录 |
$OLDPWD |
上一次工作目录(cd - 用到) |
$LANG |
系统语言与字符集 |
$HOSTNAME |
主机名 |
$RANDOM |
随机数(0~32767) |
$HISTSIZE |
历史命令内存缓冲区大小 |
$HISTFILESIZE |
历史命令文件保存条数 |
$PS1 |
主提示符(如 [\u@\h \W]\$) |
$PS2 |
续行提示符(默认 >) |
bash
echo $PATH # 查看 PATH
export MYVAR="hello" # 定义并导出为环境变量
env # 显示所有环境变量
printenv HOME # 查看指定环境变量
set # 显示所有变量(含本地+环境)
4.4 特殊变量
| 变量 | 说明 |
|---|---|
$0 |
当前脚本文件名(或 Shell 名称) |
$1 ~ $9 |
第 1~9 个位置参数 |
${10} |
第 10 个及以后需用大括号 |
$# |
位置参数总个数 |
$* |
所有参数(作为一个字符串) |
$@ |
所有参数(每个独立引用,推荐) |
$? |
上一条命令的退出码(0=成功) |
$$ |
当前 Shell 的 PID |
$! |
最后一个后台进程的 PID |
$_ |
上一条命令的最后一个参数 |
$- |
当前 Shell 的选项标志 |
$* vs $@ 区别(加双引号时):
| 写法 | 效果 |
|---|---|
"$*" |
所有参数合成一个字符串:"$1 $2 $3" |
"$@" |
每个参数独立引用:"$1" "$2" "$3" |
4.5 变量运算
| 方式 | 示例 | 说明 |
|---|---|---|
$(( )) |
echo $((3+5)) |
算术运算(推荐) |
$[ ] |
echo $[3+5] |
同上(旧写法) |
let |
let "a=3+5" |
整数运算 |
expr |
expr 3 + 5 |
外部命令,运算符两侧须有空格 |
bc |
`echo "scale=2;10/3" | bc` |
4.6 字符串变量操作
| 操作 | 语法 | 说明 |
|---|---|---|
| 获取长度 | ${#str} |
字符串长度 |
| 截取子串 | ${str:start:length} |
从 start 截取 length 个字符 |
| 删除前缀 | ${str#pattern} |
最短匹配删除(从前) |
| 删除前缀 | ${str##pattern} |
最长匹配删除(从前) |
| 删除后缀 | ${str%pattern} |
最短匹配删除(从后) |
| 删除后缀 | ${str%%pattern} |
最长匹配删除(从后) |
| 替换 | ${str/old/new} |
替换第一个匹配 |
| 全部替换 | ${str//old/new} |
替换所有匹配 |
| 默认值 | ${str:-default} |
若 str 未设置或为空,返回 default |
| 赋默认值 | ${str:=default} |
同上,且将 default 赋给 str |
bash
path="/usr/local/bin/script.sh"
echo ${#path} # 27
echo ${path:5:5} # local
echo ${path##*/} # script.sh(取文件名)
echo ${path%/*} # /usr/local/bin(取目录)
五、引号、转义与通配符
5.1 三种引号机制
全部原样
部分保留
执行
单引号
硬引用
所有字符失去特殊含义
双引号
软引用
变量和命令替换仍有效
反引号
命令替换
执行命令并嵌入结果
| 引号 | 名称 | 变量展开 | 命令替换 | 通配符展开 | 适用场景 |
|---|---|---|---|---|---|
'...' |
单引号(硬引用) | 否 | 否 | 否 | 原样输出字符串 |
"..." |
双引号(软引用) | 是 | 是 | 否 | 保护空格、保留变量 |
... |
反引号 | 是 | 是 | 是 | 命令替换(建议用 $() 替代) |
| 无引号 | - | 是 | 是 | 是 | 默认,有分词和通配符展开 |
bash
name="World"
echo 'Hello $name' # Hello $name(原样)
echo "Hello $name" # Hello World(展开)
echo "Today is $(date +%F)" # Today is 2026-02-12(命令替换)
5.2 转义字符
| 转义序列 | 含义 |
|---|---|
\\ |
反斜杠本身 |
\n |
换行(echo -e 中使用) |
\t |
制表符 Tab |
\r |
回车 |
\a |
响铃 |
\$ |
美元符号(不做变量替换) |
\" |
双引号 |
\' |
单引号(在双引号内使用) |
5.3 通配符(Globbing)
Shell Globbing
文件名模式匹配
星号 *
匹配任意个字符
问号 ?
匹配 1 个字符
方括号
匹配其中一个
范围匹配
如 a-z 0-9
取反匹配
排除指定字符
大括号展开
枚举多个值
| 通配符 | 功能 | 示例 | 匹配 |
|---|---|---|---|
* |
任意个字符(含 0 个) | *.txt |
a.txt, log.txt |
? |
恰好 1 个字符 | file?.log |
file1.log, fileA.log |
[abc] |
括号内任一字符 | [abc].txt |
a.txt, b.txt, c.txt |
[a-z] |
范围内任一字符 | file[0-9] |
file0 ~ file9 |
[!abc] / [^abc] |
不在括号内的字符 | [!0-9]* |
不以数字开头的文件 |
{a,b,c} |
大括号展开 | file{1,2,3}.txt |
file1.txt, file2.txt, file3.txt |
** |
递归匹配子目录(需 shopt -s globstar) |
**/*.log |
所有子目录中的 .log |
重要区别 :通配符(Globbing)用于文件名匹配,在命令执行前 由 Shell 展开;正则表达式用于文本内容匹配(grep、sed、awk 等),两者语法含义不同。
六、I/O 重定向与管道
6.1 文件描述符
0 stdin
标准输入 键盘
1 stdout
标准输出 屏幕
2 stderr
标准错误 屏幕
键盘
屏幕
屏幕
| 文件描述符 | 名称 | 默认设备 | 说明 |
|---|---|---|---|
| 0 | stdin(标准输入) | 键盘 | 程序读取数据的来源 |
| 1 | stdout(标准输出) | 屏幕 | 程序正常输出 |
| 2 | stderr(标准错误) | 屏幕 | 程序错误信息 |
6.2 输出重定向
| 语法 | 说明 |
|---|---|
cmd > file |
stdout 覆盖写入文件 |
cmd >> file |
stdout 追加写入文件 |
cmd 2> file |
stderr 覆盖写入文件 |
cmd 2>> file |
stderr 追加写入文件 |
cmd > file 2>&1 |
stdout 和 stderr 都写入文件(推荐) |
cmd &> file |
同上(Bash 简写) |
cmd &>> file |
stdout + stderr 追加 |
cmd > /dev/null 2>&1 |
丢弃所有输出 |
cmd 2>/dev/null |
仅丢弃 stderr |
6.3 输入重定向
| 语法 | 说明 |
|---|---|
cmd < file |
从文件读取 stdin |
cmd << EOF |
Here Document:将 EOF 之间内容作为 stdin |
cmd <<< "string" |
Here String:将字符串作为 stdin |
bash
# Here Document 示例
cat << EOF
Hello, $USER!
Today is $(date +%F)
EOF
# Here String 示例
grep "hello" <<< "hello world"
6.4 管道(Pipe)
管道
管道
命令1 stdout
命令2 stdin/stdout
命令3 stdin
| 语法 | 说明 |
|---|---|
| `cmd1 | cmd2` |
| `cmd1 | cmd2 |
| `cmd1 | & cmd2` |
bash
ls -l | grep ".txt" | sort -k5 -n # 列出→筛选→按大小排序
ps aux | grep nginx | grep -v grep # 查进程并去掉 grep 自身
cat /var/log/syslog | head -50 # 看日志前 50 行
dmesg | tail -20 # 看内核日志最后 20 行
6.5 tee 命令:同时输出到屏幕和文件
bash
ls -l | tee output.txt # 屏幕显示 + 写入文件(覆盖)
ls -l | tee -a output.txt # 追加模式
6.6 重定向顺序要点
bash
# 正确:stdout 和 stderr 都进 file
cmd > file 2>&1
# 错误理解:stderr 指向 stdout 旧位置(屏幕),然后 stdout 才指向 file
cmd 2>&1 > file # stderr 仍输出到屏幕!
口诀 :重定向从左到右 依次生效,
2>&1表示"让 fd2 指向 fd1 此刻所指向的地方"。
七、date 与 clock/hwclock
7.1 date:系统时钟
开机读取
hwclock -w
hwclock -s
ntpdate
🔋 硬件时钟 RTC
BIOS/CMOS 中
💻 系统时钟
内核维护
🌐 NTP 服务器
date 格式化输出:
| 格式 | 说明 | 输出示例 |
|---|---|---|
%Y |
四位年份 | 2026 |
%m |
月份(01-12) | 02 |
%d |
日(01-31) | 12 |
%H |
时(00-23) | 14 |
%M |
分(00-59) | 30 |
%S |
秒(00-59) | 00 |
%F |
完整日期(%Y-%m-%d) | 2026-02-12 |
%T |
完整时间(%H:%M:%S) | 14:30:00 |
%s |
Unix 时间戳 | 1739327400 |
%D |
短日期(%m/%d/%y) | 02/12/26 |
%A |
星期名 | Thursday |
%u |
星期几(1=周一) | 4 |
%n |
换行符 | - |
bash
date +%F # 2026-02-12
date +"%Y-%m-%d %H:%M:%S" # 2026-02-12 14:30:00
date -s "2026-04-12 17:00:00" # 设置系统时间
date +%s # 时间戳
7.2 clock / hwclock:硬件时钟
| 选项 | 说明 |
|---|---|
-r / --show |
显示硬件时钟 |
-w / --systohc |
系统时钟 → 硬件时钟 |
-s / --hctosys |
硬件时钟 → 系统时钟 |
--set --date="..." |
直接设置硬件时钟 |
bash
hwclock -r # 显示硬件时钟
hwclock -w # 系统 → 硬件
hwclock --hctosys # 硬件 → 系统
hwclock --set --date="09/17/2003 13:26:00" # 设置硬件时钟
ntpdate 0.rhel.pool.ntp.org && hwclock -w # 网络对时后写回硬件
八、获取帮助(man / whatis / help)
8.1 帮助方式总览
❓ 获取帮助
🔴 help cmd
内置命令
🟡 cmd --help
快速选项
🟢 man cmd
完整手册
🔵 info cmd
详细文档
🟣 /usr/share/doc
软件文档
⚪ whatis cmd
手册章节
| 方式 | 适用 | 详细度 | 用法 |
|---|---|---|---|
help COMMAND |
内置命令 | 简要 | help cd |
COMMAND --help |
外部命令 | 简要 | ls --help |
man COMMAND |
通用 | 完整 | man ls |
man N COMMAND |
指定章节 | 完整 | man 5 passwd |
info COMMAND |
GNU 软件 | 最详细 | info ls |
whatis COMMAND |
查章节 | 一行 | whatis passwd |
apropos KEYWORD |
模糊搜索 | 一行 | apropos network |
8.2 man 手册章节
| 章节 | 内容 | 路径示例 |
|---|---|---|
| 1 | 用户命令 | /bin, /usr/bin |
| 2 | 系统调用 | open(), read() |
| 3 | 库函数 | printf(), malloc() |
| 4 | 设备/特殊文件 | /dev/* |
| 5 | 文件格式 | /etc/passwd |
| 6 | 游戏 | - |
| 7 | 杂项 | 协议、信号 |
| 8 | 管理命令 | /sbin, /usr/sbin |
8.3 man 翻页与搜索
| 操作 | 说明 |
|---|---|
f / Space |
向后翻一屏 |
b |
向前翻一屏 |
j / Enter |
向后翻一行 |
k |
向前翻一行 |
d |
向后翻半屏 |
u |
向前翻半屏 |
/KEYWORD |
向后搜索 |
?KEYWORD |
向前搜索 |
n |
下一个匹配 |
N |
上一个匹配 |
g |
跳到首行 |
G |
跳到末行 |
q |
退出 |
8.4 SYNOPSIS 符号含义
| 符号 | 含义 | 示例 |
|---|---|---|
<> |
必选参数 | <filename> |
[] |
可选参数 | [-v] |
... |
可重复 | file ... |
| ` | ` | 多选一 |
{} |
分组 | `{start |
九、echo 与 printf
9.1 echo
| 选项 | 说明 |
|---|---|
-n |
不输出末尾换行 |
-e |
启用转义序列(\n \t \a 等) |
-E |
禁用转义(默认) |
echo -e 转义序列:
| 序列 | 含义 |
|---|---|
\n |
换行 |
\t |
Tab |
\a |
响铃 |
\b |
退格 |
\\ |
反斜杠 |
\0nnn |
八进制 ASCII |
\xHH |
十六进制 ASCII |
bash
echo "Hello World"
echo -e "Line1\nLine2\tTabbed"
echo -n "no newline: "; echo "continue"
echo -e "\033[31mRed Text\033[0m" # ANSI 颜色:红色
echo -e "\033[32mGreen\033[0m" # 绿色
9.2 printf
类似 C 语言,默认不换行,需显式 \n。
| 格式 | 说明 |
|---|---|
%s |
字符串 |
%d |
十进制整数 |
%f |
浮点数 |
%x |
十六进制 |
%o |
八进制 |
%c |
单个字符 |
%-10s |
左对齐,宽度 10 |
%10s |
右对齐,宽度 10 |
bash
printf "Name: %-10s Age: %d\n" "Alice" 25
printf "PI = %.4f\n" 3.14159
printf "The year is %d.\nToday is %d.\n" $(date +%Y) $(date +%d)
十、file 与文件命名规则
10.1 file:判断文件类型
| 文件格式 | 系统 | 说明 |
|---|---|---|
| ELF | Linux | Executable and Linkable Format |
| PE | Windows | Portable Executable |
| Mach-O | macOS | 苹果可执行格式 |
bash
file /bin/ls # ELF 64-bit LSB executable
file README.md # ASCII text
file image.png # PNG image data
file /dev/null # character special
10.2 文件命名规则
| 规则 | 说明 |
|---|---|
| 最大长度 | 单文件名 255 字符,完整路径 4096 |
| 禁用字符 | 仅 / 不能用作文件名 |
| 大小写 | 严格区分大小写 |
以 . 开头 |
隐藏文件(ls -a 可见) |
| 避免字符 | `* ? > < ; & ! [ ] |
| 避免开头 | 不建议用 - 或 + 开头 |
十一、路径与命令展开
11.1 Shell 展开执行顺序
- 大括号展开
{a,b,c} 2. 波浪号展开
~ → /home/user 3. 变量展开
VAR → value 4. 命令替换 (cmd) 5. 算术展开
$((1+2)) 6. 分词
按 IFS 分割 7. 通配符展开
*.txt 8. 执行命令
11.2 大括号展开
bash
echo {a,b,c} # a b c
echo {1..10} # 1 2 3 ... 10
echo {a..z} # a b c ... z
echo {01..12} # 01 02 03 ... 12(补零)
echo {1..10..2} # 1 3 5 7 9(步长)
mkdir -p project/{src,bin,doc,test}
touch file{1..5}.txt # file1.txt ~ file5.txt
cp config.conf{,.bak} # 等同于 cp config.conf config.conf.bak
11.3 路径特殊符号
| 符号 | 含义 |
|---|---|
. |
当前目录 |
.. |
上一级目录 |
~ |
当前用户家目录 |
~USER |
指定用户家目录 |
- |
上一个工作目录(仅 cd -) |
十二、Shell 脚本流程控制
12.1 条件测试(test / [ ] / [[ ]])
🧪 条件测试
📄 文件测试
-f -d -e -r -w -x
🔢 数值比较
-eq -ne -lt -gt
🔤 字符串比较
= != -z -n
🔗 逻辑组合
-a -o ! && ||
文件测试:
| 操作符 | 说明 |
|---|---|
-e file |
文件存在 |
-f file |
是普通文件 |
-d file |
是目录 |
-L file |
是符号链接 |
-r file |
可读 |
-w file |
可写 |
-x file |
可执行 |
-s file |
文件非空(大小 > 0) |
f1 -nt f2 |
f1 比 f2 新(newer than) |
f1 -ot f2 |
f1 比 f2 旧(older than) |
数值比较:
| 操作符 | 含义 | 等价 |
|---|---|---|
-eq |
等于 | == |
-ne |
不等于 | != |
-lt |
小于 | < |
-le |
小于等于 | <= |
-gt |
大于 | > |
-ge |
大于等于 | >= |
字符串比较:
| 操作符 | 说明 |
|---|---|
str1 = str2 |
字符串相等 |
str1 != str2 |
字符串不等 |
-z str |
字符串长度为 0(空) |
-n str |
字符串长度非 0(非空) |
12.2 if 语句
bash
# 基本 if
if [ 条件 ]; then
命令
fi
# if-else
if [ 条件 ]; then
命令1
else
命令2
fi
# if-elif-else
if [ 条件1 ]; then
命令1
elif [ 条件2 ]; then
命令2
else
命令3
fi
bash
# 示例:判断文件是否存在
if [ -f /etc/passwd ]; then
echo "passwd exists"
else
echo "passwd not found"
fi
# 使用 [[ ]] 支持正则和更多运算符
if [[ "$name" == J* ]]; then
echo "Name starts with J"
fi
12.3 case 语句
bash
case $变量 in
模式1)
命令1
;;
模式2|模式3)
命令2
;;
*)
默认命令
;;
esac
bash
case $1 in
start) echo "Starting..." ;;
stop) echo "Stopping..." ;;
restart) echo "Restarting..." ;;
*) echo "Usage: $0 {start|stop|restart}" ;;
esac
12.4 for 循环
bash
# 列表 for
for var in item1 item2 item3; do
echo $var
done
# 范围 for
for i in {1..10}; do
echo $i
done
# C 风格 for
for ((i=0; i<10; i++)); do
echo $i
done
# 遍历文件
for file in /etc/*.conf; do
echo "Config: $file"
done
12.5 while / until 循环
bash
# while(条件为真时循环)
count=1
while [ $count -le 5 ]; do
echo "Count: $count"
((count++))
done
# until(条件为假时循环,即直到条件为真停止)
count=1
until [ $count -gt 5 ]; do
echo "Count: $count"
((count++))
done
# 逐行读取文件
while read line; do
echo "$line"
done < /etc/passwd
12.6 循环控制
| 关键字 | 说明 |
|---|---|
break |
退出当前循环 |
break N |
退出 N 层嵌套循环 |
continue |
跳过本次迭代,继续下一次 |
continue N |
跳到外 N 层循环的下一次 |
十三、函数
13.1 函数定义与调用
定义函数
function name 或 name方式
调用
直接写函数名
返回值
return 0到255
bash
# 方式一(推荐)
greet() {
echo "Hello, $1!"
return 0
}
# 方式二
function greet {
echo "Hello, $1!"
}
# 调用
greet "Alice" # Hello, Alice!
echo "Exit code: $?" # 0
13.2 函数参数
| 变量 | 说明 |
|---|---|
$1 ~ $9 |
函数的第 1~9 个参数 |
${10} |
第 10 个及以后 |
$# |
参数个数 |
$@ |
所有参数(独立引用) |
$* |
所有参数(单字符串) |
13.3 变量作用域
| 关键字 | 作用域 | 说明 |
|---|---|---|
| 默认 | 全局 | 函数内外都可见 |
local |
函数内部 | 仅函数内部可见,推荐使用 |
export |
子 Shell | 导出为环境变量,子进程可见 |
export -f |
子 Shell | 导出函数,子进程可用 |
bash
myfunc() {
local name="inside" # 仅函数内可见
echo $name
}
myfunc # inside
echo $name # (空,因为 local)
十四、数组与字符串操作
14.1 数组定义
bash
# 方式一:整体赋值
arr=(apple banana cherry)
# 方式二:逐个赋值
arr[0]="apple"
arr[1]="banana"
# 方式三:指定下标
arr=([0]="apple" [3]="date")
14.2 数组操作
| 操作 | 语法 | 说明 |
|---|---|---|
| 取全部元素 | ${arr[@]} 或 ${arr[*]} |
所有元素 |
| 取某个元素 | ${arr[N]} |
第 N 个(从 0 开始) |
| 数组长度 | ${#arr[@]} |
元素个数 |
| 元素长度 | ${#arr[N]} |
第 N 个元素的字符串长度 |
| 切片 | ${arr[@]:start:length} |
从 start 取 length 个 |
| 替换 | ${arr[@]/old/new} |
替换每个元素的首个匹配 |
| 删除元素 | unset arr[N] |
删除第 N 个元素 |
| 追加 | arr+=(new_item) |
末尾追加 |
bash
fruits=(apple banana cherry)
echo ${fruits[1]} # banana
echo ${#fruits[@]} # 3
echo ${fruits[@]:1:2} # banana cherry
fruits+=(date) # 追加
for f in "${fruits[@]}"; do echo $f; done
14.3 字符串操作速查
| 操作 | 语法 | 示例 |
|---|---|---|
| 长度 | ${#str} |
${#"hello"} → 5 |
| 截取 | ${str:start:len} |
${str:0:5} |
| 删除最短前缀 | ${str#pattern} |
${path#*/} |
| 删除最长前缀 | ${str##pattern} |
${path##*/} → 文件名 |
| 删除最短后缀 | ${str%pattern} |
${path%/*} → 目录 |
| 删除最长后缀 | ${str%%pattern} |
${path%%/*} |
| 首次替换 | ${str/old/new} |
|
| 全部替换 | ${str//old/new} |
|
| 大写 | ${str^^} |
Bash 4+ |
| 小写 | ${str,,} |
Bash 4+ |
十五、历史命令、别名与快捷键
15.1 历史命令(history)
退出/history -w
登录/history -r
⌨️ 输入命令
💾 内存缓冲区
HISTSIZE 条
📄 ~/.bash_history
HISTFILESIZE 条
| 命令 | 说明 |
|---|---|
history |
显示全部历史命令 |
history N |
显示最近 N 条 |
history -c |
清空当前会话历史 |
history -w |
写入 ~/.bash_history |
history -r |
读取 ~/.bash_history |
history -d N |
删除第 N 条记录 |
历史命令调用:
| 快捷方式 | 说明 |
|---|---|
!! |
执行上一条命令 |
!N |
执行第 N 条历史命令 |
!-N |
执行倒数第 N 条 |
!string |
执行最近以 string 开头的命令 |
!?string |
执行最近包含 string 的命令 |
^old^new |
将上一条命令中 old 替换为 new 并执行 |
!$ |
上一条命令的最后一个参数 |
!^ |
上一条命令的第一个参数 |
!* |
上一条命令的所有参数 |
相关环境变量:
| 变量 | 说明 | 默认值 |
|---|---|---|
HISTSIZE |
内存中保存的条数 | 1000 |
HISTFILESIZE |
文件中保存的条数 | 2000 |
HISTFILE |
历史文件路径 | ~/.bash_history |
HISTCONTROL |
控制策略 | ignoredups |
HISTIGNORE |
忽略的命令模式 | 如 "ls:cd:pwd" |
HISTTIMEFORMAT |
时间戳格式 | 如 "%F %T " |
15.2 别名(alias)
| 命令 | 说明 |
|---|---|
alias |
查看所有别名 |
alias name='cmd' |
定义别名(当前会话有效) |
unalias name |
取消别名 |
unalias -a |
取消所有别名 |
\command |
跳过别名直接执行原始命令 |
bash
alias ll='ls -lha'
alias grep='grep --color=auto'
alias rm='rm -i' # 删除前确认
\ls # 跳过 alias,执行原始 ls
永久别名:写入
~/.bashrc或~/.bash_aliases,执行source ~/.bashrc生效。
15.3 Bash 常用快捷键
| 快捷键 | 功能 | 分类 |
|---|---|---|
Ctrl+A |
光标移到行首 | 移动 |
Ctrl+E |
光标移到行末 | 移动 |
Ctrl+B |
光标后退一个字符 | 移动 |
Ctrl+F |
光标前进一个字符 | 移动 |
Alt+B |
光标后退一个单词 | 移动 |
Alt+F |
光标前进一个单词 | 移动 |
Ctrl+U |
删除光标前所有字符 | 编辑 |
Ctrl+K |
删除光标后所有字符 | 编辑 |
Ctrl+W |
删除光标前一个单词 | 编辑 |
Alt+D |
删除光标后一个单词 | 编辑 |
Ctrl+Y |
粘贴被删除的文本 | 编辑 |
Ctrl+L |
清屏(同 clear) | 控制 |
Ctrl+C |
终止当前命令 | 控制 |
Ctrl+Z |
暂停当前命令(转后台) | 控制 |
Ctrl+D |
退出终端 / 输入 EOF | 控制 |
Ctrl+R |
反向搜索历史命令 | 搜索 |
Ctrl+S |
暂停屏幕输出 | 控制 |
Ctrl+Q |
恢复屏幕输出 | 控制 |
Tab |
自动补全 | 补全 |
Tab Tab |
显示所有匹配项 | 补全 |
十六、作业控制(Job Control)
16.1 作业控制流程
cmd &
Ctrl+Z
bg
fg
fg %N
Ctrl+C
⌨️ 运行命令
前台运行
后台运行
⏸ 暂停(Stopped)
🛑 终止
| 命令 | 说明 |
|---|---|
cmd & |
将命令放到后台运行 |
jobs |
列出当前会话的后台作业 |
jobs -l |
同上,并显示 PID |
fg %N |
将作业 N 切换到前台 |
bg %N |
让暂停的作业 N 在后台继续运行 |
Ctrl+Z |
暂停前台作业(发送 SIGTSTP) |
Ctrl+C |
终止前台作业(发送 SIGINT) |
kill %N |
终止作业 N |
disown %N |
让作业 N 脱离终端(关终端不影响) |
nohup cmd & |
命令不受终端挂起影响 |
bash
sleep 100 & # 后台运行
jobs # [1]+ Running sleep 100 &
fg %1 # 切到前台
Ctrl+Z # 暂停
bg %1 # 后台继续
kill %1 # 终止
十七、文本查看与 less/more 操作
17.1 more 常用操作
| 按键 | 功能 |
|---|---|
Enter |
向下 n 行(默认 1 行) |
Ctrl+F / Space |
向下滚动一屏 |
Ctrl+B |
返回上一屏 |
= |
输出当前行号 |
:f |
输出文件名和当前行号 |
V |
调用 vi 编辑器 |
q |
退出 |
bash
more +3 log2012.log # 从第 3 行开始
more +/day3 log2012.log # 从 "day3" 前两行开始
more -5 log2012.log # 每屏 5 行
ls -l | more -5 # 管道分页
17.2 less 常用操作
| 操作 | 说明 |
|---|---|
Space / f |
向后翻一页 |
b |
向前翻一页 |
d |
向后翻半页 |
u |
向前翻半页 |
j / Enter |
向后一行 |
k / y |
向前一行 |
/字符串 |
向下搜索 |
?字符串 |
向上搜索 |
n / N |
下一个 / 上一个匹配 |
G |
到最后一行 |
g |
到第一行 |
&pattern |
仅显示匹配行 |
ma |
标记 a |
'a |
跳到标记 a |
v |
调用编辑器编辑 |
q / ZZ |
退出 |
bash
less log2013.log
ps -ef | less
less log1.log log2.log # 多文件 :n 下一个 :p 上一个
十八、练习与速查
18.1 练习示例
- 用 date 单独获取年、月、日、时、分、秒:
bash
date +%Y; date +%m; date +%d; date +%H; date +%M; date +%S
- echo 是内部还是外部?如何两行输出?
bash
type echo # echo is a shell builtin
echo -e "The year is 2013.\nToday is 26."
printf "The year is %d.\nToday is %d.\n" 2013 26
- 编写一个循环脚本,打印 1 到 10:
bash
for i in {1..10}; do echo $i; done
18.2 综合速查表
| 目的 | 命令 |
|---|---|
| 判断命令类型 | type COMMAND |
| 内部命令帮助 | help COMMAND |
| 外部命令帮助 | COMMAND --help |
| 手册 | man COMMAND |
| 手册章节 | whatis COMMAND → man N COMMAND |
| 查看别名 | alias |
| 定义别名 | alias name='cmd' |
| 历史命令 | history,!!,!N |
| 变量赋值 | VAR=value |
| 导出变量 | export VAR=value |
| 查看变量 | echo $VAR |
| 退出码 | echo $?(0=成功) |
| 当前 PID | echo $$ |
| 后台运行 | cmd & |
| 前台恢复 | fg %N |
| 管道 | `cmd1 |
| 重定向 | > >> < 2> &> |
| 清屏 | Ctrl+L 或 clear |
| 终止命令 | Ctrl+C |
| 搜索历史 | Ctrl+R |