1、Shell 的定义(需背诵)
shell程序是一种命令行接口,是向用户提供管理和操作系统的一个接口,位于应用程序的最外层,所以也称为壳程序。
2、echo 的使用(输出字符串 / 变量)
核心功能:在终端输出指定内容,默认结尾换行。
基本语法与常用场景:
| 用法 | 效果说明 | 示例 | 输出结果 |
|---|---|---|---|
echo "字符串" | 输出字符串(双引号支持变量 / 转义字符) | name=zhangsan; echo "Hello $name" | Hello zhangsan |
echo '字符串' | 输出字符串(单引号原样输出,不解析变量) | name=zhangsan; echo 'Hello $name' | Hello $name |
echo -n "字符串" | 输出不换行 | echo -n "Hello "; echo "World" | Hello World(同一行) |
echo $变量名 | 输出变量值 | PATH=/usr/bin; echo $PATH | /usr/bin |
3、文件的创建、写入(覆盖 / 追加)、删除
(1)文件创建
- 空文件创建:
touch 文件名(若文件不存在则创建,存在则更新修改时间)示例:touch test.txt(创建 test.txt 空文件) - 直接创建并写入内容(结合重定向):
echo "内容" > 文件名(见下文 “写入”)
(2)文件写入(覆盖 / 追加)
核心通过 重定向符号 实现,无需打开编辑器:
| 操作类型 | 符号 | 语法示例 | 说明 |
|---|---|---|---|
| 覆盖写入 | > | echo "新内容" > test.txt | 清空文件原有内容,写入新内容(文件不存在则创建) |
| 追加写入 | >> | echo "追加内容" >> test.txt | 在文件末尾添加新内容,不覆盖原有内容 |
| 多行写入 | cat > 文件名 | cat > test.txt 回车后输入多行,按 Ctrl+D 结束 | 手动输入多行内容,覆盖写入文件 |
(3)文件删除
- 普通删除(需确认):
rm 文件名(删除单个文件,默认无提示)示例:rm test.txt - 强制删除(无提示):
rm -f 文件名(忽略不存在的文件,不报错)示例:rm -f test.txt - 删除多个文件:
rm 文件名1 文件名2或rm *.txt(通配符匹配)示例:rm a.txt b.txt(删除两个文件)、rm *.log(删除所有 .log 后缀文件)
⚠️ 注意:rm 删除文件不可逆,慎用 rm -rf *(删除当前目录所有文件)。
4、创建多级文件夹(需添加的选项)
- 核心命令:
mkdir(make directory) - 关键选项:
-p(parents,递归创建父目录) - 语法:
mkdir -p 一级目录/二级目录/... - 示例:需求:创建
a/b/c三级目录(当前目录无 a 目录)命令:mkdir -p a/b/c效果:自动创建 a 目录、a 下的 b 目录、b 下的 c 目录,无需手动逐级创建。
若不加 -p:直接执行 mkdir a/b/c 会报错(提示 “没有那个文件或目录”)。
5、三种文件内容查看命令(cat、more、less)的用法和特点
示例:
- 查看小文件:
cat test.txt - 查看中大型文件:
more log.txt或less log.txt - 搜索文件中的 “error”:
less log.txt→ 输入/error→ 按 n 跳转下一个匹配项。
6、tail、wc 和 grep 命令的使用
(1)tail:查看文件末尾内容(默认最后 10 行)
核心场景:实时查看日志文件(如应用日志、系统日志)。
| 用法 | 说明 | 示例 |
|---|---|---|
tail 文件名 | 查看文件最后 10 行(默认) | tail app.log(查看 app.log 最后 10 行) |
tail -n 行数 文件名 | 查看指定行数的末尾内容 | tail -n 20 app.log(查看最后 20 行) |
tail -f 文件名 | 实时跟踪文件更新(日志滚动时自动刷新) | tail -f app.log(实时看应用日志) |
tail -F 文件名 | 跟踪文件(文件被删除重建后仍能继续跟踪) | tail -F app.log(比 -f 更稳定) |
⚠️ 终止实时跟踪:按 Ctrl+C。
(2)wc:统计文件的行、词、字节数
核心功能:Word Count(统计),默认输出「行数 词数 字节数 文件名」。
| 选项 | 说明 | 语法示例 | 输出结果说明(以 test.txt 为例) |
|---|---|---|---|
| -l | 仅统计行数 | wc -l test.txt | 5 test.txt(表示文件有 5 行) |
| -w | 仅统计词数 | wc -w test.txt | 12 test.txt(表示文件有 12 个词) |
| -c | 仅统计字节数 | wc -c test.txt | 68 test.txt(表示文件 68 字节) |
| -m | 仅统计字符数(含中文) | wc -m test.txt | 56 test.txt(中文按 1 个字符算) |
示例:统计当前目录下 .txt 文件总数(结合管道):ls *.txt | wc -l。
(3)grep:按关键词搜索文件内容(文本过滤神器)
核心功能:Global Regular Expression Print(全局正则表达式匹配并打印)。
| 用法 | 说明 | 示例 | ||
|---|---|---|---|---|
grep "关键词" 文件名 | 搜索文件中包含关键词的行(区分大小写) | grep "error" app.log(找含 error 的行) | ||
grep -i "关键词" 文件名 | 忽略大小写搜索 | grep -i "Error" app.log(匹配 Error/error 等) | ||
grep -n "关键词" 文件名 | 显示匹配行的行号 | grep -n "error" app.log(输出 12:error: xxxx) | ||
grep -v "关键词" 文件名 | 反向匹配(显示不包含关键词的行) | grep -v "info" app.log(过滤掉含 info 的行) | ||
grep -r "关键词" 目录 | 递归搜索目录下所有文件中的关键词 | grep -r "username" /etc/(搜索 /etc 下所有含 username 的文件) | ||
grep -E "正则表达式" 文件名 | 支持扩展正则(如 | 表示或) | `grep -E "error | warning"app.log`(匹配 error 或 warning) |
示例:搜索当前目录下所有 .sh 文件中含 “echo” 的行,并显示行号:grep -rn "echo" *.sh。
7、重定向符(Linux 输入 / 输出重定向)
重定向符的核心作用是 改变命令的默认输入 / 输出方向(默认输入是键盘,默认输出是终端屏幕),常用的有 4 类,重点掌握前 3 个:
| 重定向符 | 作用说明 | 语法示例 | 核心场景 |
|---|---|---|---|
> | 标准输出覆盖重定向 | echo "内容" > 文件 | 清空文件原有内容,写入新内容(文件不存在则创建) |
>> | 标准输出追加重定向 | echo "内容" >> 文件 | 在文件末尾添加新内容,不覆盖原有内容 |
< | 标准输入重定向 | 命令 < 文件 | 让命令从文件读取输入,而非键盘 |
2> | 标准错误输出重定向 | 命令 2> 错误日志 | 捕获命令执行的错误信息,写入文件(屏蔽屏幕报错) |
关键补充:
- 标准输出(stdout):命令执行成功的结果(默认显示在屏幕),编号为
1,可省略(如1> 文件等价于> 文件); - 标准错误(stderr):命令执行失败的提示(默认显示在屏幕),编号为
2,必须显式写(如2> error.log); - 同时重定向输出和错误:
命令 > 输出日志 2> 错误日志(分开存储)或命令 > 日志 2>&1(合并存储到同一个日志)。
示例:
- 覆盖写入:
ls /home > file_list.txt(将 /home 目录列表覆盖写入 file_list.txt); - 追加写入:
date >> log.txt(将当前日期追加到 log.txt 末尾); - 输入重定向:
wc -l < test.txt(统计 test.txt 的行数,从文件读入而非手动输入); - 错误重定向:
ls /不存在的目录 2> error.log(将 “没有那个文件或目录” 的错误写入 error.log,屏幕不显示报错)。
8、三种通配符(*、?、[])
通配符用于 匹配文件 / 目录名(简化批量操作),核心是 “模糊匹配文件名”,而非匹配文件内容(文件内容匹配用 grep):
| 通配符 | 功能说明 | 示例 | 匹配结果 |
|---|---|---|---|
* | 匹配 0 个或多个任意字符(包括空字符) | ls *.txt | 所有后缀为 .txt 的文件(如 a.txt、test123.txt、.txt 隐藏文件) |
? | 匹配 1 个任意字符(必须有且仅有 1 个) | ls a?.txt | 以 a 开头、中间 1 个字符、后缀 .txt 的文件(如 ab.txt、a1.txt,不匹配 aa2.txt) |
[] | 匹配 括号内任意 1 个字符(支持单个字符 / 范围) | 1. ls [ab].txt2. ls [0-9].txt3. ls [a-z].txt | 1. 匹配 a.txt 或 b.txt2. 匹配 0.txt、1.txt...9.txt3. 匹配 a.txt、b.txt...z.txt |
补充说明:
[]中可写多个单个字符(如[abc]匹配 a/b/c 任一),也可写范围(如[A-Z]匹配大写字母、[0-9a-z]匹配数字和小写字母);- 反向匹配:
[^](匹配括号外的任意 1 个字符),示例ls [^ab].txt匹配非 a.txt、非 b.txt 的文件。
实操场景:
- 批量删除后缀为 .log 的文件:
rm *.log; - 批量复制文件名长度为 3 位的 .txt 文件:
cp ???.txt /tmp/(如 123.txt、abc.txt); - 批量查看以 2025 开头、中间 2 个数字、后缀 .log 的文件:
cat 2025[0-9][0-9].log(如 202501.log、202512.log)。
9、$ 引用变量和单双引号的区别
核心结论:** 单引号(' ')是 “强引用”,原样输出所有内容;双引号(" ")是 “弱引用”,会解析 变量、转义字符等特殊符号, 符号的核心作用是 “引用变量的值”。
分点拆解:
(1)$ 引用变量的作用
$变量名 或 ${变量名} 用于 获取变量存储的值(${} 是明确变量边界,避免歧义):
- 示例:
name="张三"; echo $name→ 输出张三; - 避免歧义:
age=20; echo "年龄是${age}岁"→ 输出年龄是20岁(若写echo "年龄是$age岁"也可,但复杂场景推荐${})。
(2)单引号(' ')的特点
-
不解析任何特殊字符:包括
$变量、\转义字符、()等,全部原样输出; -
示例:
bash
name="张三" echo '$name' # 输出 $name(不解析变量) echo 'Hello\nWorld' # 输出 Hello\nWorld(不解析换行符)
(3)双引号(" ")的特点
-
会解析
$变量、\转义字符(如\n换行、\t制表符)、$()(命令替换)等特殊符号; -
示例:
bash
name="张三" echo "$name" # 输出 张三(解析变量) echo "Hello\nWorld" # 输出 Hello\nWorld(默认不解析转义?需结合 echo -e) echo -e "Hello\nWorld" # 输出 Hello(换行)World(启用转义) echo "当前目录:$(pwd)" # 输出 当前目录:/home/user(解析命令替换)
(4)三者核心区别对比表
| 符号 / 用法 | 是否解析 $ 变量 | 是否解析转义字符 | 示例 | 输出结果 |
|---|---|---|---|---|
| 无引号 | 是 | 部分(仅 \ 换行等少数) | name=李四; echo $name\n123 | 李四 \n123 |
| 双引号 " " | 是 | 是(需配合 echo -e) | name=李四; echo -e "$name\n123" | 李四123 |
| 单引号 ' ' | 否 | 否 | name=李四; echo -e '$name\n123' | $name\n123 |
记忆口诀:
- 单引号:“所见即所得”,里面所有内容都不变;
- 双引号:“智能解析”,里面的变量、转义符会生效;
- $ 符号:“变量取值器”,必须在双引号或无引号下才会解析变量。
10、vim 的三种工作模式和转换关系
vim 是 Linux 下的全功能编辑器,核心通过 三种工作模式 实现编辑操作,模式间转换是使用关键:
(1)三种工作模式的定义
(2)模式转换关系(核心记忆)
plaintext
命令模式(默认)
↓ 按 i/a/o/I/A/O
插入模式
↓ 按 Esc
命令模式
↓ 按 :
末行模式
↓ 执行命令(如 :wq)或按 Esc
命令模式
⚠️ 关键:任何模式下按 Esc 都能返回命令模式(不确定当前模式时,多按几次 Esc 即可)。
11、shell 脚本的编写(细节题)、shell 脚本启动 4 种方式
(1)shell 脚本编写(完整流程 + 细节)
shell 脚本是批量执行命令的文本文件,后缀通常为 .sh,编写核心步骤和细节如下:
① 编写步骤(以 test.sh 为例)
- 首行指定解释器(必须,告诉系统用哪个 shell 执行):开头写
#!/bin/bash(Linux 默认 bash 解释器,固定格式,#!叫 “幻数”); - 添加注释(可选但推荐,
#开头,说明脚本功能、作者、日期等); - 编写执行命令(核心,按需求写一系列 Linux 命令或逻辑语句);
- 保存文件(如
test.sh); - 添加执行权限(脚本默认无执行权限,需手动授权)。
② 编写示例(完整脚本)
bash
#!/bin/bash
# 脚本功能:创建文件夹并写入文件
# 作者:xxx
# 日期:2025-11-12
# 创建文件夹(-p 避免已存在报错)
mkdir -p ./test_dir
# 写入内容到文件
echo "这是 shell 脚本测试文件" > ./test_dir/info.txt
# 输出执行结果
echo "脚本执行完成!文件路径:$(pwd)/test_dir/info.txt"
③ 关键细节(易错点)
- 首行
#!/bin/bash不能少,否则可能报错 “command not found”; - 路径尽量用 绝对路径(如
/home/user/test.sh),避免相对路径导致执行失败; - 变量赋值时 等号前后不能有空格(正确:
name="test",错误:name = "test"); - 脚本中若调用其他命令,确保命令已安装(如
docker、git),否则会执行失败。
(2)shell 脚本启动 4 种方式(含优缺点)
前提:脚本已编写完成(如 test.sh),推荐先 cd 到脚本所在目录。
| 启动方式 | 语法示例 | 核心原理 | 优缺点 |
|---|---|---|---|
| 1. 绝对路径执行 | /home/user/test.sh | 直接指定脚本的完整路径,系统按路径找到脚本执行 | ✅ 最规范,无歧义❌ 需写全路径(可配合 pwd 简化) |
| 2. 相对路径执行 | ./test.sh | ./ 表示 “当前目录”,告诉系统在当前目录找脚本 | ✅ 简单常用,适合脚本在当前目录的场景❌ 必须在脚本所在目录执行 |
3. bash/sh 解释器执行 | bash test.sh 或 sh test.sh | 直接调用 shell 解释器(bash/sh),脚本无需执行权限 | ✅ 无需授权(跳过 chmod +x 步骤)✅ 兼容性好(即使首行没指定解释器也能执行)❌ 依赖解释器名称(如 zsh 脚本需用 zsh test.sh) |
4. source 或 . 执行 | source test.sh 或 . test.sh | 让脚本在 当前 shell 进程 中执行(其他方式是新建子进程) | ✅ 脚本中定义的变量、环境变量会生效(如 export PATH=)❌ 可能污染当前 shell 环境(变量不会自动销毁) |
补充说明:
- 方式 1 和 2 必须先给脚本加执行权限:
chmod +x test.sh(否则报错 “权限不够”); - 方式 3 无需加权限(解释器直接读取脚本内容执行);
- 场景推荐:日常执行脚本用方式 2(
./test.sh),需要环境变量生效用方式 4(source test.sh)。
12、shell 特殊位置变量的含义和作用(n # ?)
shell 中的 “位置变量” 是脚本执行时,通过命令行传递给脚本的参数,核心常用的有以下 4 个:
| 变量名 | 含义 | 作用 | 示例(基于脚本 test.sh) |
|---|---|---|---|
$0 | 脚本本身的文件名(含路径,取决于执行方式) | 获取当前脚本名称,常用于脚本自检、日志输出 | 执行 ./test.sh a b c → echo $0 输出 ./test.sh;执行 /home/user/test.sh a b c → 输出 /home/user/test.sh |
$n | 第 n 个命令行参数(n ≥ 1,n=1 是第一个参数,n=2 是第二个,以此类推) | 接收脚本外部传递的参数(如文件路径、阈值等) | 执行 ./test.sh 张三 20 男 →echo $1 输出 张三(第一个参数)、echo $2 输出 20(第二个参数)、echo $3 输出 男(第三个参数) |
$# | 命令行参数的总个数(不含脚本名 $0) | 判断传递的参数是否足够,避免脚本执行出错 | 执行 ./test.sh a b c → echo $# 输出 3(共 3 个参数);常用逻辑:if [ $# -ne 2 ]; then echo "请输入2个参数!"; exit 1; fi(参数个数不是 2 则退出) |
$? | 上一条命令执行的 退出状态码 | 判断上一条命令是否执行成功(核心调试工具) | 1. 执行成功:ls /home → echo $? 输出 0(所有成功执行的命令退出码都是 0);2. 执行失败:ls /不存在的目录 → echo $? 输出非 0(如 123,不同错误对应不同码);常用逻辑:rm -f test.txt; if [ $? -eq 0 ]; then echo "删除成功"; fi |
关键补充:
- 若参数个数超过 9 个(如第 10 个参数),需用
${10}表示(不能写$10,会被解析为$1加0); $?仅表示 “上一条命令” 的状态,执行新命令后会被覆盖(如cmd1; cmd2; echo $?输出的是cmd2的状态码)。
13、文件测试语句判断文件是否存在(-d 怎么使用)
shell 中通过 文件测试运算符 判断文件 / 目录的属性(存在性、类型、权限等),核心用于 if 语句中,先明确常用测试运算符,再重点说明 -d 的用法:
(1)常用文件测试运算符(核心)
| 运算符 | 作用 | 示例 |
|---|---|---|
-e | 判断文件 / 目录 是否存在(exist) | [ -e test.txt ] → 存在返回真(0),不存在返回假(非 0) |
-d | 判断目标 是否为目录(directory) | [ -d test_dir ] → 是目录返回真,否则假 |
-f | 判断目标 是否为普通文件(file,非目录、非设备文件) | [ -f test.txt ] → 是普通文件返回真 |
-r | 判断文件 是否有读权限(read) | [ -r test.txt ] → 有读权限返回真 |
-w | 判断文件 是否有写权限(write) | [ -w test.txt ] → 有写权限返回真 |
-x | 判断文件 是否有执行权限(execute) | [ -x test.sh ] → 有执行权限返回真 |
(2)-d 的具体使用(判断是否为目录)
语法格式(两种等价,推荐第一种):
bash
# 格式1:[] 前后必须有空格,变量建议加双引号(避免路径含空格报错)
if [ -d "目录路径" ]; then
执行命令(目录存在时)
else
执行命令(目录不存在时)
fi
# 格式2:[[ ]] (bash 扩展语法,支持更复杂判断,同样需要空格)
if [[ -d "目录路径" ]]; then
执行命令
fi
示例 1:判断目录是否存在,存在则输出信息,不存在则创建
bash
#!/bin/bash
dir_path="./data"
# 判断 ./data 是否为目录
if [ -d "$dir_path" ]; then
echo "目录 $dir_path 已存在!"
else
echo "目录 $dir_path 不存在,正在创建..."
mkdir -p "$dir_path" # -p 确保多级目录也能创建
echo "目录创建成功!"
fi
示例 2:结合 -e 和 -d 判断 “是否存在且为目录”(更严谨)
bash
dir_path="./logs"
if [ -e "$dir_path" ] && [ -d "$dir_path" ]; then
echo "$dir_path 是已存在的目录"
elif [ -e "$dir_path" ] && [ ! -d "$dir_path" ]; then # ! 表示否定
echo "$dir_path 存在,但不是目录!"
else
echo "$dir_path 不存在,创建目录..."
mkdir -p "$dir_path"
fi
关键注意:
[ ]前后必须有空格(错误:[-d $dir_path],正确:[ -d $dir_path ]);- 目录路径建议用双引号包裹(如
"$dir_path"),避免路径中包含空格导致判断失败。
14、if、for 语句的结构(shell 脚本逻辑控制)
shell 脚本的 if(条件判断)和 for(循环)是核心逻辑语句,语法有固定格式(注意空格和分号),以下是 标准结构 + 实用示例:
(1)if 语句(条件判断)
shell 的 if 支持单分支、双分支、多分支,核心是 “条件为真(退出码 0)则执行对应代码块”。
① 单分支结构(满足条件才执行)
bash
if [ 条件表达式 ]; then
条件为真时执行的命令(可多行)
fi # 结束标记(必须写)
示例:判断文件是否有写权限,有则追加内容
bash
file="test.txt"
if [ -w "$file" ]; then
echo "文件有写权限,追加内容..."
echo "追加的内容" >> "$file"
fi
② 双分支结构(满足 / 不满足条件分别执行)
bash
if [ 条件表达式 ]; then
条件为真时执行的命令
else
条件为假时执行的命令
fi
示例:判断参数个数是否正确
bash
if [ $# -eq 1 ]; then # $# 是参数个数,-eq 表示“等于”
echo "传入的参数是:$1"
else
echo "错误!请传入1个参数,当前传入 $# 个参数"
exit 1 # 非0退出码表示脚本执行失败
fi
③ 多分支结构(多个条件判断)
bash
if [ 条件1 ]; then
条件1为真执行
elif [ 条件2 ]; then # else if 的缩写
条件1为假、条件2为真执行
else
所有条件都为假执行
fi
示例:根据分数判断等级
bash
score=85
if [ $score -ge 90 ]; then # -ge 表示“大于等于”
echo "等级:优秀"
elif [ $score -ge 80 ]; then
echo "等级:良好"
elif [ $score -ge 60 ]; then
echo "等级:及格"
else
echo "等级:不及格"
fi
④ if 条件表达式的常用运算符
- 数值比较:
-eq(等于)、-ne(不等于)、-gt(大于)、-lt(小于)、-ge(≥)、-le(≤); - 字符串比较:
==(等于)、!=(不等于)、-z(字符串为空)、-n(字符串非空); - 逻辑组合:
&&(并且)、||(或者)(需在[ ]外使用,如[ 条件1 ] && [ 条件2 ])。
(2)for 语句(循环)
shell 的 for 循环主要用于 “遍历列表”(文件、参数、数字范围等),有两种常用格式:
① 格式 1:遍历列表(最常用)
bash
for 变量名 in 列表内容; do
循环体命令(变量名表示当前遍历的元素)
done # 结束标记
示例 1:遍历命令行参数($@ 表示所有参数)
bash
echo "传入的所有参数:"
for arg in $@; do
echo "参数:$arg"
done
示例 2:遍历指定文件列表
bash
# 遍历当前目录下所有 .txt 文件
for file in *.txt; do
echo "文件名称:$file,行数:$(wc -l < $file)"
done
示例 3:遍历数字范围(两种写法)
bash
# 写法1:直接写范围(1到5)
for i in 1 2 3 4 5; do
echo "数字:$i"
done
# 写法2:用 {起始..结束}(bash 支持,更简洁)
for i in {1..10}; do
echo "计数:$i"
done
# 写法3:步长(如1到10,步长2)
for i in {1..10..2}; do
echo "奇数:$i" # 输出 1 3 5 7 9
done
② 格式 2:C 语言风格循环(适合数值递增 / 递减)
bash
for (( 初始化; 循环条件; 递增/递减 )); do
循环体命令
done
示例:计算 1 到 10 的总和
bash
sum=0
for (( i=1; i<=10; i++ )); do
sum=$((sum + i)) # $(( )) 用于数值计算
done
echo "1到10的总和:$sum" # 输出 55
关键注意:
for循环的in后面可以是任意列表(参数、文件、数字、字符串);- C 语言风格的
for中,变量赋值不用$,计算用$(( )); - 循环体中变量必须加
$引用(如$file、$i)。