一、什么是 Shell?
咱们可以把计算机系统比作一家复杂的餐厅:Linux 内核是后厨里掌勺的总厨师,负责处理所有硬件资源(比如 CPU、内存、硬盘)的调度和运算;而用户就是来就餐的顾客,需要通过某种方式向厨师传递需求(比如 “炒一盘菜”“盛一碗汤”)。
Shell 正是连接顾客(用户)和厨师(内核)的 “服务员”—— 它是一个命令解释器,会把用户输入的命令翻译成内核能理解的语言,内核执行完毕后,再把结果通过 Shell 反馈给用户。
举个更具体的例子:当你想查看 “/home” 目录下的文件时,输入ls /home命令,这个过程的本质是:
Shell 接收ls /home命令并解析
向内核发送 “读取 /home 目录文件列表” 的请求
内核调用文件系统模块获取数据
内核将文件列表返回给 Shell
Shell 将结果格式化后显示在终端上
除了执行单个命令,Shell 还能批量处理命令(通过脚本),甚至实现复杂的逻辑判断和循环操作,这也是它比图形界面更高效的核心原因。
二、Shell 的种类
目前常见的 Shell 有十多种,除了之前提到的 bash、sh、zsh,还有 ksh、csh、tcsh 等,它们在语法和功能上各有侧重:
Shell 类型
特点与适用场景
bash
1989 年发布,是 Bourne Shell(sh)的增强版兼容 sh 语法,新增数组、函数、命令补全等功能支持通配符(*、?)和管道组合几乎所有 Linux 发行版(Ubuntu、CentOS 等)的默认 Shell推荐新手优先掌握
sh
1979 年随 Unix 诞生的原始 Shell语法简单但功能有限(无数组、无函数)现在多作为符号链接指向 bash 或其他兼容 Shell仅在老旧系统或特定脚本中使用
zsh
1990 年发布,兼容 bash 但功能更强大支持主题美化(如 agnoster 主题)、插件扩展(通过 oh-my-zsh)智能命令补全(如目录、参数自动提示)拼写纠错(输入错误命令时自动提示)适合追求高效和个性化的进阶用户
ksh
1983 年由 AT&T 开发,融合 sh 和 csh 的优点支持脚本调试和数学运算在商业 Unix 系统(如 AIX)中较常见
csh/tcsh
语法类似 C 语言,适合编程习惯的用户tcsh 是 csh 的增强版,支持命令历史和补全因兼容性问题,现在使用较少
查看系统已安装的 Shell:
cat /etc/shells # 列出系统支持的所有Shell
切换默认 Shell(需注销后生效):
chsh -s /bin/zsh # 将默认Shell改为zsh
三、Shell 的基本命令
1. 文件与目录操作命令
ls(列出目录内容)
核心功能:显示指定目录下的文件和子目录,默认显示当前目录。
常用选项:
-a:显示所有文件(包括以.开头的隐藏文件,如.bashrc)
-l:以长格式显示(权限、所有者、大小、修改时间等)
-h:配合-l使用,以人性化单位显示大小(如 K、M、G)
-t:按修改时间排序(最新的在前面)
-r:反向排序(如配合-t实现按时间倒序)
-d:仅显示目录本身(而非目录内内容)
示例:
ls -la ~ # 显示主目录下所有文件(包括隐藏)的详细信息
ls -lht /var/log # 以人性化单位显示/var/log目录下文件,按修改时间排序
ls -d /etc/*conf # 显示/etc目录下所有以conf结尾的目录(而非内容)
cd(切换目录)
核心功能:切换当前工作目录,路径可以是绝对路径(从/开始)或相对路径(相对于当前目录)。
特殊用法:
cd 或 cd ~:切换到当前用户的主目录(如/home/yourname)
cd ..:切换到上一级目录
cd -:切换到上一次所在的目录
cd ./docs:切换到当前目录下的 docs 子目录(./可省略)
cd /usr/local:切换到绝对路径/usr/local
示例:
cd ~/Downloads # 进入主目录下的Downloads文件夹
cd ../pictures # 进入上一级目录下的pictures文件夹
cd - # 在两个目录间快速切换
pwd(显示当前目录)
核心功能:打印当前工作目录的绝对路径,避免 “迷路”。
示例:
pwd # 输出:/home/yourname/work/project
mkdir(创建目录)
核心功能:创建新目录,支持一次性创建多级目录。
常用选项:
-p:递归创建目录(父目录不存在时自动创建)
示例:
mkdir blog # 创建名为blog的目录
mkdir -p blog/{posts,images} # 同时创建blog目录及其中的posts和images子目录
rmdir(删除空目录)
核心功能:仅删除空目录,若目录非空会报错。
示例:
rmdir empty_folder # 删除空目录empty_folder
rm(删除文件 / 目录)
核心功能:删除文件或目录(需谨慎使用,删除后难以恢复)。
常用选项:
-f:强制删除(不提示确认)
-r:递归删除目录及其中所有内容
-i:删除前提示确认
示例:
rm old.txt # 删除文件old.txt(会提示确认)
rm -f temp.log # 强制删除temp.log(不提示)
rm -rf old_dir # 递归删除old_dir目录及所有内容(危险操作!)
cp(复制文件 / 目录)
核心功能:复制文件或目录到指定位置。
常用选项:
-i:目标文件存在时提示是否覆盖
-r:递归复制目录(必须用于目录复制)
-v:显示复制过程
示例:
cp note.txt backup/ # 复制note.txt到backup目录
cp -i report.pdf ~/docs/ # 复制report.pdf到主目录的docs,若存在则提示
cp -rv project/ /media/usb/ # 递归复制project目录到U盘,显示复制过程
mv(移动 / 重命名文件 / 目录)
核心功能:移动文件 / 目录到新位置,或重命名(目标位置与源位置相同则为改名)。
示例:
mv file.txt docs/ # 移动file.txt到docs目录
mv oldname.txt newname.txt # 将文件重命名为newname.txt
mv pics/ images/ # 将目录pics重命名为images
touch(创建文件 / 更新时间)
核心功能:创建空文件,或更新已有文件的访问 / 修改时间。
示例:
touch readme.md # 创建空文件readme.md
touch -d "2023-01-01" oldfile # 将oldfile的时间修改为2023年1月1日
2. 文件内容查看命令
cat(连接并显示文件内容)
核心功能:一次性显示文件所有内容,适合查看小型文件。
常用选项:
-n:显示行号
-b:仅显示非空行的行号
示例:
cat story.txt # 查看story.txt内容
cat -n config.ini # 显示config.ini内容并带行号
more/less(分页查看文件)
核心功能:分页显示大文件内容(避免内容一次性刷屏)。
more:只能向前翻页,支持空格(翻页)、Enter(换行)、q(退出)
less:更强大,支持前后翻页(PgUp/PgDn)、搜索(/ 关键词)、q(退出)
示例:
more large_log.txt # 分页查看大日志文件
less /etc/manpath.config # 用less查看配置文件,按/搜索关键词
head/tail(查看文件首尾内容)
核心功能:
head:显示文件开头部分(默认前 10 行)
tail:显示文件结尾部分(默认后 10 行)
常用选项:
-n N:指定显示 N 行(如-n 20显示 20 行)
-f:实时跟踪文件新增内容(常用于查看日志)
示例:
head -n 5 scores.csv # 查看scores.csv的前5行
tail -n 3 error.log # 查看error.log的最后3行
tail -f /var/log/syslog # 实时监控系统日志新增内容(按Ctrl+C退出)
grep(搜索文本内容)
核心功能:在文件或命令输出中搜索匹配指定模式的行。
常用选项:
-i:忽略大小写(如同时匹配 “Hello” 和 “hello”)
-n:显示匹配行的行号
-r:递归搜索目录下所有文件
-v:显示不匹配的行
--color:高亮显示匹配的内容
示例:
grep "error" app.log # 在app.log中搜索包含error的行
grep -in "warning" /var/log/* # 在/var/log下所有文件中搜索warning(忽略大小写并显示行号)
grep -rv "test" src/ # 在src目录下递归搜索不包含test的行
四、管道和重定向
1. 管道(|)
管道的本质是 “将前一个命令的标准输出作为后一个命令的标准输入”,可以串联多个命令实现复杂功能。
多层管道示例:
# 统计当前目录下所有.txt文件的总行数
ls -l *.txt | grep -v "^d" | wc -l
# 解析:
# 1. ls -l *.txt:列出所有.txt文件的详细信息
# 2. grep -v "^d":排除目录(只保留文件,^d表示以d开头的行,即目录)
# 3. wc -l:统计行数(每个文件对应一行,即文件总数)
# 查看系统中占用内存最高的前5个进程
ps aux | sort -k4nr | head -n 5
# 解析:
# 1. ps aux:显示所有进程的详细信息
# 2. sort -k4nr:按第4列(内存占用)从大到小排序(n表示数字排序,r表示反向)
# 3. head -n 5:取前5行
2. 重定向
输出重定向
>:覆盖式重定向(目标文件存在则清空原有内容)
>>:追加式重定向(目标文件存在则在末尾添加内容)
示例:
# 将当前目录结构保存到file_list.txt(覆盖原有内容)
ls -lR > file_list.txt
# 记录系统时间到日志(追加模式)
date >> system_log.txt
输入重定向(<)
将文件内容作为命令的标准输入。
示例:
# 统计words.txt中单词总数(等价于cat words.txt | wc -w)
wc -w < words.txt
# 从data.csv中读取内容作为mysql导入数据
mysql -u root -p < data.csv
错误重定向
2>:重定向标准错误输出(覆盖模式)
2>>:追加标准错误输出
2>&1:将标准错误输出合并到标准输出
示例:
# 执行命令时,将错误信息保存到error.log(不显示在终端)
sudo apt install unknown-package 2> error.log
# 将标准输出和错误都保存到all.log(常用日志记录方式)
python script.py > all.log 2>&1
# 将正确输出保存到success.log,错误输出保存到fail.log
./backup.sh > success.log 2> fail.log
五、Shell 脚本
Shell 脚本是包含一系列 Shell 命令的文本文件,通过逻辑控制实现自动化任务,扩展名通常为.sh。
1. 脚本基础要素
解释器声明:首行#!/bin/bash(指定用 bash 解释器,必须放在第一行)
注释:以#开头的行(除首行声明外),用于说明脚本功能,不被执行
命令序列:按执行顺序排列的 Shell 命令
可执行权限:需通过chmod +x script.sh赋予执行权限
2. 变量与参数
自定义变量
#!/bin/bash
# 定义变量(等号两侧不能有空格)
name="Alice"
age=30
# 使用变量(加$符号)
echo "姓名:$name"
echo "年龄:$age"
# 变量重新赋值
age=31
echo "更新后的年龄:$age"
# 命令替换(将命令输出赋值给变量,用$()或``)
current_time=$(date +"%Y-%m-%d %H:%M:%S")
echo "当前时间:$current_time"
环境变量
系统预定义的变量,用于存储系统配置信息,通常全大写。
PATH:可执行程序的搜索路径(输入命令时系统会在这些路径中查找)
HOME:当前用户的主目录
USER:当前用户名
PWD:当前工作目录(同 pwd 命令)
LANG:系统语言设置
示例:
echo $HOME # 输出:/home/yourname
echo $PATH # 输出:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin...
# 向PATH添加自定义目录(临时生效,重启终端后失效)
export PATH=$PATH:/home/yourname/scripts
# 永久生效需写入配置文件(如~/.bashrc或~/.bash_profile)
echo 'export PATH=$PATH:/home/yourname/scripts' >> ~/.bashrc
source ~/.bashrc # 立即生效(无需重启终端)
位置参数
脚本运行时传递的参数,通过$1(第一个参数)、$2(第二个参数)...$n(第 n 个参数)访问。
$0:脚本本身的文件名
$#:参数的总个数
$*:所有参数的集合(作为单个字符串)
$@:所有参数的集合(作为独立字符串)
示例(greet.sh):
#!/bin/bash
echo "脚本名:$0"
echo "参数总数:$#"
echo "第一个参数:$1"
echo "第二个参数:$2"
echo "所有参数:$@"
运行脚本:
chmod +x greet.sh
./greet.sh "Hello" "World"
# 输出:
# 脚本名:./greet.sh
# 参数总数:2
# 第一个参数:Hello
# 第二个参数:World
# 所有参数:Hello World
3. 条件判断(if 语句)
#!/bin/bash
# 判断文件是否存在
filename="data.txt"
if [ -f "$filename" ]; then
echo "$filename 是一个普通文件"
elif [ -d "$filename" ]; then
echo "$filename 是一个目录"
else
echo "$filename 不存在"
fi
# 常用判断条件:
# -f file:是否为普通文件
# -d dir:是否为目录
# -e path:路径是否存在
# -r file:是否有读权限
# -w file:是否有写权限
# -z str:字符串是否为空
# $a -eq $b:a等于b(数字比较)
# $a -gt $b:a大于b
# str1 == str2:字符串相等(注意用双等号)
4. 循环结构
for 循环
#!/bin/bash
# 批量重命名.jpg文件为编号格式(如1.jpg、2.jpg)
i=1
for file in *.jpg; do
if [ -f "$file" ]; then # 确保是文件而非目录
mv "$file" "$i.jpg"
echo "重命名 $file 为 $i.jpg"
i=$((i + 1)) # 变量自增
fi
done
while 循环
#!/bin/bash
# 倒计时脚本
count=10
while [ $count -gt 0 ]; do
echo "倒计时:$count 秒"
sleep 1 # 暂停1秒
count=$((count - 1))
done
echo "倒计时结束!"
5. 函数
#!/bin/bash
# 定义函数(计算两数之和)
add() {
local sum=$(( $1 + $2 )) # local声明局部变量
echo $sum
}
# 调用函数
result=$(add 5 3)
echo "5 + 3 = $result" # 输出:5 + 3 = 8
6. 实战脚本示例:日志分析工具
#!/bin/bash
# 功能:分析Nginx访问日志,统计访问量最高的前10个IP
# 检查日志文件是否存在
log_file="/var/log/nginx/access.log"
if [ ! -f "$log_file" ]; then
echo "错误:日志文件 $log_file 不存在"
exit 1 # 退出脚本并返回错误码1
fi
echo "正在分析日志文件:$log_file"
echo "访问量最高的前10个IP:"
# 提取IP(日志中第一列通常是IP)并统计排序
awk '{print $1}' "$log_file" | sort | uniq -c | sort -nr | head -n 10
# 解析:
# 1. awk '{print $1}':提取每行第一列(IP地址)
# 2. sort:排序IP(便于后续去重)
# 3. uniq -c:统计每个IP出现的次数(-c表示计数)
# 4. sort -nr:按次数从大到小排序
# 5. head -n 10:取前10名
运行方式:
chmod +x nginx_analysis.sh
sudo ./nginx_analysis.sh # 需root权限访问nginx日志
7. 脚本调试技巧
执行脚本时添加-x参数:bash -x script.sh(显示每一行执行的命令及参数,便于定位错误)
在关键位置添加echo命令:输出变量值或执行状态(如echo "当前处理文件:$file")
使用set -e:脚本中任何命令执行失败(返回非 0 状态)时立即退出脚本
六、Shell 高级技巧
1. 别名(alias)
为常用命令创建简写,提高效率。
# 临时生效(重启终端后失效)
alias ll='ls -lha' # 用ll代替ls -lha
alias rm='rm -i' # 让rm默认提示确认
# 永久生效(写入配置文件)
echo "alias ll='ls -lha'" >> ~/.bashrc
source ~/.bashrc # 立即生效
2. 历史命令
history:查看所有历史命令
!n:执行历史记录中第 n 条命令(如!100执行第 100 条)
!keyword:执行最近一条以 keyword 开头的命令(如!ls执行最近的 ls 命令)
Ctrl+R:反向搜索历史命令(输入关键词匹配)
3. 命令补全
按Tab键自动补全命令、文件名或目录名,按两次Tab显示所有可能的选项。
# 输入以下内容后按Tab,会自动补全为完整文件名
cat docu[Tab] # 若存在document.txt,会补全为cat document.txt
4. 快捷键
Ctrl+C:终止当前正在执行的命令
Ctrl+D:退出当前 Shell(等价于 exit 命令)
Ctrl+Z:暂停当前命令(放入后台,可用 fg 命令恢复)
Ctrl+A:光标跳到命令行开头
Ctrl+E:光标跳到命令行结尾
Ctrl+U:删除光标前的所有内容
Ctrl+K:删除光标后的所有内容
七、总结
Shell 是 Linux 系统的 “灵魂交互工具”,从简单的文件操作到复杂的自动化脚本,掌握它能极大提升工作效率。学习时建议遵循 “边学边练” 的原则:
先熟练掌握基础命令(ls、cd、pwd、cp、mv、rm 等)理解管道和重定向的用法,学会组合命令解决问题逐步学习脚本编程(变量、条件、循环、函数),从简单脚本开始实践积累实用技巧(别名、快捷键、历史命令),形成自己的高效工作流
随着实践深入,你会发现 Shell 不仅是命令行工具,更是一种 “自动化思维” 的载体 —— 很多重复劳动都能通过几行脚本解放双手。现在就打开终端,开始你的 Shell 探索之旅吧!