Linux系统管理与运维基础

Linux 系统管理与运维基础

本文系统归纳 Linux 日常管理与运维核心知识:Linux 哲学与开源协议(GPL/BSD/Apache/MIT)、用户与组管理(useradd/usermod/chage/密码策略)、Shell 类型与配置文件(profile/bashrc/读取顺序)、I/O 重定向与管道(文件描述符/exec/tee)、文件查找(find/locate/xargs)、Vim 编辑器(模式/操作/宏/寄存器/分屏)、系统监控与性能工具(top/free/vmstat/iostat/sar/lsof)、特殊权限要点、重要命令功能速查。大量 Mermaid 图表emoji 标注 辅助理解。每节附注意事项与使用场景。与同系列文档配合使用,内容只增不减


目录

  • [一、Linux 哲学与开源](#一、Linux 哲学与开源)
  • 二、用户与组管理
  • [三、Shell 类型与配置文件](#三、Shell 类型与配置文件)
  • [四、I/O 重定向与管道](#四、I/O 重定向与管道)
  • [五、文件查找(find / locate / xargs)](#五、文件查找(find / locate / xargs))
  • [六、Vim 编辑器](#六、Vim 编辑器)
  • 七、系统监控与性能工具
  • 八、特殊权限(SUID/SGID/Sticky)要点
  • 九、重要命令功能速查 (新增)
  • 十、代表性练习选编
    • [10.1 基础练习(原选编)](#10.1 基础练习(原选编))
    • [10.2 用户与组管理练习](#10.2 用户与组管理练习)
    • [10.3 I/O 重定向与管道练习](#10.3 I/O 重定向与管道练习)
    • [10.4 find / locate / xargs 练习](#10.4 find / locate / xargs 练习)
    • [10.5 文本处理与管道练习](#10.5 文本处理与管道练习)
    • [10.6 权限与属主练习](#10.6 权限与属主练习)
    • [10.7 系统监控与综合练习](#10.7 系统监控与综合练习)
  • 十一、相关文档索引

一、Linux 哲学与开源

1.1 Linux 重要哲学思想

| 思想 | 说明 |

|------|------|

| 一切皆文件 | 设备、管道、Socket 均以文件形式访问(/dev/null、/dev/sda...) |

| 纯文本配置 | 配置文件、数据多用纯文本,便于查看和脚本处理 |

| 小程序组合 | 每个工具只做一件事并做好,通过管道组合完成复杂任务 |

| 沉默原则 | 命令成功时不输出,只在出错时提示 |

| 避免交互 | 命令优先接受参数和选项,便于脚本自动化 |

1.2 开源协议详解

协议分类
类别 特点 代表协议
Copyleft(强传染) 衍生作品必须同样开源 GPL、LGPL
宽松(Permissive) 衍生作品可以闭源商用 MIT、BSD、Apache
五大协议详细对比
协议 闭源发布 专利保护 传染性 核心要求 典型项目
GPL v2/v3 不允许 v3 有 衍生作品必须 GPL 开源 Linux 内核、GCC
LGPL 允许动态链接 - 修改 LGPL 部分须开源 glibc
BSD (2/3-Clause) 允许 保留版权声明(3-Clause:不得用原作者推广) FreeBSD
Apache 2.0 允许 保留协议 + 标注修改 + NOTICE 文件 Kubernetes、Hadoop
MIT 允许 仅需保留版权声明(最宽松) React、Vue.js、Node.js
选择建议
场景 推荐协议
个人开源库/前端框架 MIT
企业商业项目(需专利保护) Apache 2.0
确保衍生作品永远开源 GPL
最大商业灵活性 BSD

1.3 内核与发行版

概念 说明
Linux 内核 由 Linus Torvalds 创建,访问 www.kernel.org 获取最新版本
GNU 项目 提供编译器 GCC、libc、Bash、coreutils 等用户空间工具
GNU/Linux 完整操作系统 = Linux 内核 + GNU 工具 + 其他软件
发行版 内核 + 软件包 + 包管理器 + 安装/配置工具;同一内核可被不同发行版使用
主要发行版
发行版 包管理 说明
RHEL / CentOS / Rocky Linux yum/dnf (rpm) 企业级稳定,CentOS 为 RHEL 免费版,CentOS 停维后 Rocky/Alma 接替
Fedora dnf (rpm) RHEL 上游社区版,软件较新
SUSE / openSUSE zypper (rpm) 企业级,欧洲流行
Debian apt (deb) 社区驱动,稳定性高
Ubuntu / Mint apt (deb) 基于 Debian,Ubuntu 桌面流行,Mint 更友好
Arch Linux pacman 滚动更新,极简,DIY
Gentoo portage(源码编译) 高度可定制,编译安装
LFS - 不是发行版,是指导从源码构建系统的书

二、用户与组管理

2.0 用户与组管理概览

2.1 用户类型

类型 UID 范围(典型) 说明
root 0 超级管理员,拥有一切权限
系统用户 1~999 服务运行账户,不可登录
普通用户 1000+ 日常使用账户

范围由 /etc/login.defs 中的 UID_MINUID_MAX 定义。

2.2 用户管理命令

命令 说明 常用选项
useradd 添加用户 -u UID、-g 主组、-G 附加组、-s shell、-d 家目录、-m 创建家目录、-M 不创建、-r 系统用户、-c 注释、-e 过期日期
usermod 修改用户 -u -g -G-a 追加而非覆盖附加组)、-s-d-m 迁移家目录)、-L 锁定、-U 解锁
userdel 删除用户 -r 同时删除家目录和邮箱
passwd 修改密码 -n 最短天数、-x 最长天数、-l 锁定、-u 解锁、--stdin 从管道读密码
id 查看用户信息 -u 仅 UID、-g 仅 GID、-G 所有组

示例

bash 复制代码
useradd -c "Fedora Community" -s /bin/tcsh fedora
useradd -r -s /sbin/nologin hbase             # 系统用户,不可登录
usermod -u 4004 -g linux -G distro,fedora mandriva
usermod -aG docker myuser                      # 追加附加组(不覆盖已有组)
passwd -n 2 -x 50 fedora                       # 最短 2 天、最长 50 天
echo "newpass" | passwd --stdin username        # 非交互设密码(RHEL系)
2.2.1 使用场景汇总
场景 推荐命令组合 说明
新员工入职 useradd -m -s /bin/bash -c "姓名" userpasswd userusermod -aG 项目组 user 创建账户、设密码、加入项目组
员工离职 usermod -L userusermod -e 2026-01-01 user 锁定账户或设失效日期
临时禁用 usermod -L user;恢复用 usermod -U user 不删账号,仅禁止登录
重命名用户 usermod -l 新名 -d /home/新名 -m 旧名 改登录名并迁移家目录
批量加组 for u in a b c; do usermod -aG dev $u; done 脚本中追加附加组
仅查 UID id -u username 脚本中判断用户是否存在
2.2.2 练习
  1. 创建用户 tom,家目录 /home/tom,Shell 为 /bin/bash,注释为 "Tom Dev"。
  2. 将用户 tom 追加到组 dockerwheel(不覆盖原有组)。
  3. 锁定用户 tom,再解锁;查看 /etc/shadow 中该行变化。
  4. 使用 id 仅输出 tom 的 UID 和所有组 GID。

参考答案(点击展开)

bash 复制代码
# 1
useradd -m -s /bin/bash -c "Tom Dev" tom

# 2
usermod -aG docker tom && usermod -aG wheel tom

# 3
usermod -L tom; grep tom /etc/shadow   # 密码前有 !
usermod -U tom; grep tom /etc/shadow   # ! 消失

# 4
id -u tom; id -G tom

注意usermod -G覆盖 所有附加组!要追加 请用 usermod -aG

2.3 组管理命令

命令 说明 使用场景
groupadd 创建组;-g 指定 GID;-r 系统组 🏗️ 新建项目团队组
groupmod -n 改名;-g 改 GID 🔧 组更名/合并
groupdel 删除组(不能删除用户的主组) 🗑️ 项目结束清理
gpasswd 组管理:-a 加成员、-d 删成员、-A 设管理员 👥 团队成员变动
newgrp 临时切换主组(登录级别,用 exit 退回) 🔄 切换工作上下文
gpasswd 命令详解

gpasswd 用于管理组成员和组管理员,是管理 /etc/group/etc/gshadow 的前端工具:

选项 说明 示例
-a user 将用户加入组 gpasswd -a alice dev
-d user 从组中移除用户 gpasswd -d alice dev
-A user 设用户为组管理员 gpasswd -A bob dev
-M u1,u2 设置组成员列表(覆盖) gpasswd -M alice,bob dev
gpasswd group 设置组密码 gpasswd developers
newgrp 命令详解

newgrp 临时切换当前用户的有效主组,之后创建的文件会属于新组:

bash 复制代码
$ id
uid=1000(alice) gid=1000(alice) groups=1000(alice),5000(developers)

$ newgrp developers         # 临时切换主组
$ touch project.txt         # 该文件属组变为 developers
$ id -gn                    # 显示 developers
$ exit                      # 退出,恢复原主组

使用场景:多团队协作时,临时切换主组,确保创建的文件属于正确的项目组。

bash 复制代码
groupadd -g 5000 developers
gpasswd -a alice developers         # 将 alice 加入组
gpasswd -A bob developers           # bob 成为组管理员
newgrp developers                    # 临时切换主组
组管理使用场景与练习
使用场景 示例
新建项目组并指定 GID groupadd -g 5000 devops
将多个用户加入同一组 gpasswd -a alice devopsgpasswd -a bob devops
设组管理员(可自行加人) gpasswd -A alice devops
一次性设置组成员(覆盖) gpasswd -M alice,bob,carol devops
临时以某组身份创建文件 newgrp devops → 创建文件 → exit

练习

  1. 创建组 backup(GID 6000),将用户 operator 加入并设为组管理员。
  2. 使用 newgrp backup 后创建文件 /tmp/from_backup.txt,用 ls -l 确认属组为 backup,再 exit 恢复。

参考答案

bash 复制代码
groupadd -g 6000 backup
gpasswd -a operator backup
gpasswd -A operator backup

newgrp backup
touch /tmp/from_backup.txt
ls -l /tmp/from_backup.txt   # 属组应为 backup
exit

UPG(User Private Group):Red Hat 系为每个用户自动创建同名专用组,用户创建的文件属于该组。

2.4 密码策略:chage 命令详解

chage 是什么?

chagech ange age )用于管理用户密码的生命周期策略,控制密码何时过期、何时必须更改。

chage 使用场景与练习
使用场景 示例
合规策略:90 天改密、提前 7 天提醒 chage -m 7 -M 90 -W 7 user
临时账号:年底自动失效 chage -E 2026-12-31 tempuser
外包/实习:密码过期后 3 天锁定 chage -I 3 user
审计:查看某用户密码状态 chage -l user
初始密码分发:首次登录必须改密 chage -d 0 user

练习

  1. 查看当前用户密码过期信息(chage -l $USER)。
  2. 将用户 student 设置为 60 天后密码过期,过期前 5 天警告。
  3. 设置用户 guest 在 2026-06-30 账号失效。

参考答案

bash 复制代码
chage -l $USER
chage -M 60 -W 5 student
chage -E 2026-06-30 guest

2.5 重要配置文件

文件 说明 格式要点
/etc/passwd 用户信息(7 字段) 用户名:x:UID:GID:注释:家目录:shell
/etc/shadow 密码哈希(9 字段) 用户名:密码哈希:最后修改:最短:最长:警告:过期:锁定:保留
/etc/group 组信息(4 字段) 组名:x:GID:成员列表
/etc/gshadow 组密码 组名:密码:管理员:成员
/etc/login.defs 用户/密码默认值 UID_MIN/MAX、PASS_MAX_DAYS 等
/etc/skel/ 家目录模板 新用户家目录从此复制

2.6 手动添加用户(原理演示)

以添加用户 hive(UID=5000),主组 hive,附加组 mygroup 为例:

bash 复制代码
# 1. 添加组
echo "hive:x:5000:" >> /etc/group

# 2. 添加用户
echo "hive:x:5000:5000:Hive:/home/hive:/bin/bash" >> /etc/passwd

# 3. 生成密码哈希
openssl passwd -6 -salt 'random_salt'    # SHA-512(推荐)
# 将生成的哈希写入 /etc/shadow

# 4. 创建家目录
cp -r /etc/skel/ /home/hive
chown -R hive:hive /home/hive/
chmod 700 /home/hive/

生产中直接用 useradd,手动操作仅用于理解原理。

2.7 umask 与默认权限

umask 是什么?

umasku ser file creation mask)定义了新建文件/目录时要**屏蔽(去除)**的权限位。它不是减法,而是按位"遮罩"。
📄 文件最大权限 666

📂 目录最大权限 777
🎭 umask 022
📄 文件实际 644

📂 目录实际 755

概念 说明
文件默认最大权限 666(无执行位)
目录默认最大权限 777
实际权限 最大权限 - umask(按位取反再与)
用户 典型 umask 文件权限 目录权限
root 022 644 755
普通用户 002 664 775
bash 复制代码
umask             # 查看(如 0022)
umask -S          # 符号显示(u=rwx,g=rx,o=rx)
umask 027         # 设置:文件 640,目录 750
umask 使用场景与练习
使用场景 典型 umask 文件权限 目录权限
默认(root) 022 644 755
严格(仅自己) 077 600 700
组可写(协作) 002 664 775
脚本中临时收紧 umask 027 640 750

练习

  1. 当前 umask 为 022 时,新建文件 touch /tmp/f1、目录 mkdir /tmp/d1,分别用 ls -l 查看权限并写出数字。
  2. 执行 umask 077 后再次创建 /tmp/f2/tmp/d2,观察权限变化。
  3. 若希望新文件为 640、新目录为 750,应设置 umask 为多少?(答:027)

/etc/bashrc 中的逻辑 :若 UID > 199 且用户名 == 主组名(UPG),则 umask=002,否则 022。

2.8 属主属组与 chmod

bash 复制代码
# chown
chown user:group file            # 同时改属主属组
chown -R user:group dir/         # 递归
chown --reference=ref file       # 参考某文件

# chmod 符号法
chmod u+x,g-w,o= file           # 属主加 x,组去 w,其他清空
chmod a+r file                   # 所有人加读

# chmod 数字法
chmod 755 script.sh              # rwxr-xr-x
chmod 600 secret.txt             # rw-------
chown / chmod 使用场景与练习
使用场景 示例
部署应用:二进制属主 root、可执行 chown root:root /usr/local/bin/appchmod 755 /usr/local/bin/app
配置文件仅 root 可写 chmod 644 /etc/app.confchmod 600(敏感时)
目录下所有文件继承属主属组 chown -R nginx:nginx /var/www/app
参考某文件权限 chmod --reference=/etc/passwd /tmp/other
脚本可执行 chmod u+x deploy.sh

练习

  1. /tmp/testfile 改为属主读写的 600,再用符号法改为属主可执行(u+x)。
  2. 将目录 /opt/shared 及其下所有文件属主改为 nobody,属组改为 nogroup
  3. 创建文件 secret.txt,要求仅属主可读写,数字法应写多少?(答:600)

参考答案

bash 复制代码
chmod 600 /tmp/testfile; chmod u+x /tmp/testfile
chown -R nobody:nogroup /opt/shared
touch secret.txt; chmod 600 secret.txt

三、Shell 类型与配置文件

3.0 Shell 配置体系概览

3.1 四种 Shell 组合

交互式 非交互式
登录式 ssh 登录、su - user、tty 终端 极少见
非登录式 图形终端、su user、tmux 执行脚本

su - vs su

命令 类型 读取配置
su - usersu -l user 登录式 Shell 完整读取 profile + bashrc
su user 非登录式 Shell 仅读取 bashrc

3.2 配置文件分类

类别 全局 个人 典型用途
profile 类 /etc/profile、/etc/profile.d/*.sh /.bash_profile、/.profile 环境变量、PATH、启动命令
bashrc 类 /etc/bashrc ~/.bashrc 别名、函数、本地变量、PS1

3.3 配置文件读取顺序

登录式 Shell

text 复制代码
/etc/profile
  → /etc/profile.d/*.sh
    → ~/.bash_profile
      → ~/.bashrc
        → /etc/bashrc

非登录式 Shell

text 复制代码
~/.bashrc → /etc/bashrc → /etc/profile.d/*.sh

作用范围越小的配置越后加载,可覆盖前面的设定。

3.4 常见自定义

需求 文件 示例
设置 PATH ~/.bash_profile export PATH="$HOME/bin:$PATH"
定义别名 ~/.bashrc alias ll='ls -alF'alias cls='clear'
登录欢迎语 ~/.bash_profile echo "Welcome, $(whoami)! $(date)"
设置 umask ~/.bash_profile umask 027
设置 PS1 ~/.bashrc PS1='[\u@\h \W]\$ '
加载函数库 ~/.bashrc source ~/lib/utils.sh

修改后需 source ~/.bashrc 或重新登录才生效。

3.5 注意事项

注意点 说明
环境变量放 profile 非登录式 Shell 不读 profile,但 bashrc 会被读
别名放 bashrc 每次打开终端都生效
脚本中不读配置 非交互式不读 bashrc(除非脚本中显式 source)
cron 任务无 PATH 脚本中需定义完整 PATH

四、I/O 重定向与管道

4.0 I/O 重定向整体概览

4.1 文件描述符

FD 名称 默认设备 说明
0 stdin 键盘 标准输入
1 stdout 显示器 标准输出
2 stderr 显示器 标准错误输出
3~9 - - 用户可自定义

原理 :I/O 重定向本质是改变文件描述符表中 FD 指向的具体文件(通过 dup2() 系统调用)。程序只关心 FD 编号,不关心它指向谁。

4.2 输出重定向

符号 含义 示例
> 覆盖 stdout ls > out.txt
>> 追加 stdout echo "line" >> out.txt
2> 覆盖 stderr cmd 2> err.txt
2>> 追加 stderr cmd 2>> err.txt
&> stdout + stderr 同文件 cmd &> all.txt
> file 2>&1 同上(POSIX 写法) cmd > all.txt 2>&1
&>> 追加 stdout + stderr cmd &>> all.txt

注意顺序cmd > file 2>&1 正确(先重定向 1 到文件,再把 2 复制到 1)。cmd 2>&1 > file 错误(2 复制的是原来的 1=屏幕)。

4.3 输入重定向

符号 含义 示例
< 从文件读取 sort < names.txt
<< Here Document 见下
<<< Here String grep "hello" <<< "$var"

4.4 Here Document

bash 复制代码
cat << EOF
Hello, $USER
Today is $(date +%F)
EOF

# 写入文件
cat >> /tmp/config.txt << 'EOF'
# 单引号 EOF 防止变量展开
server=localhost
port=8080
EOF
Here Document / Here String 使用场景与练习
场景 示例
多行输入给命令 cat << EOF ... EOF
脚本中生成配置文件(不展开变量) cat << 'EOF' ... EOF
单行字符串作 stdin grep "root" <<< "$(cat /etc/passwd)"
从变量读入一行 read -r line <<< "$var"
生成 SQL 片段 mysql ... << EOF ... SELECT ...; ... EOF

练习

  1. 用 Here Document 将三行文字(Hello、World、End)写入 /tmp/hello.txt
  2. 用 Here String 对字符串 "apple banana apple" 做 grep "apple" 并统计出现次数(结合 wc -l)。
  3. << 'END' 形式把字面量 $HOME$(whoami) 写入 /tmp/literal.txt(不展开变量)。

参考答案

bash 复制代码
cat > /tmp/hello.txt << EOF
Hello
World
End
EOF

grep "apple" <<< "apple banana apple" | wc -l

cat > /tmp/literal.txt << 'END'
$HOME
$(whoami)
END

4.5 exec 命令详解

exec 是什么?

exec 是 Bash 内建命令,有两大核心功能

功能 语法 说明 使用场景
替换进程 exec command 用 command 替换当前 Shell,PID 不变,Shell 消失 Docker 入口脚本、Wrapper 脚本
永久重定向 stdout exec > file 后续所有 stdout 都写入 file 日志脚本、批量输出到文件
永久重定向 stderr exec 2> file 后续所有 stderr 都写入 file 错误日志收集
永久重定向全部 exec > file 2>&1 stdout + stderr 都写入 file 脚本全量日志
打开自定义 FD exec 3> file 打开 FD 3 用于写入 同时写多个文件
关闭 FD exec 3>&- 关闭 FD 3 释放资源
读取文件 FD exec 3< file 打开 FD 3 用于读取 逐行读取文件
读写 FD exec 3<> file 打开 FD 3 可读可写 双向操作同一文件
功能一:exec 替换进程

📦 新命令 🐚 Shell进程 PID=1234 📦 新命令 🐚 Shell进程 PID=1234 Shell 自身被替换 新进程运行 Shell 已不存在 exec 后面的代码不会执行 exec /usr/bin/python3 app.py PID 仍然是 1234

bash 复制代码
# 例1:用 exec 启动程序,替换当前 Shell
exec /usr/bin/python3 app.py
echo "这行永远不会执行!"  # Shell 已被 python3 替换

# 例2:Docker 入口脚本(非常常见!)
#!/bin/bash
# docker-entrypoint.sh
echo "🚀 Initializing..."
# 设置环境变量、生成配置文件等...
export DB_HOST=mysql
envsubst < /etc/myapp/config.tmpl > /etc/myapp/config.conf

# 最后用 exec 启动应用,替换 Shell
# 这样容器的 PID 1 就是应用本身,能正确接收信号
exec java -jar /app/server.jar "$@"

# 例3:Wrapper 脚本(设置环境后启动命令)
#!/bin/bash
export LD_LIBRARY_PATH=/opt/mylib:$LD_LIBRARY_PATH
export JAVA_HOME=/usr/lib/jvm/java-17
exec "$@"    # 用传入的命令替换当前 Shell

为什么 Docker 入口脚本要用 exec?

  • Docker 发送 SIGTERM 给 PID 1 进程来停止容器
  • 不用 exec:PID 1 是 bash,应用收不到信号,无法优雅退出
  • 用 exec:PID 1 直接就是应用进程,能正确响应信号
功能二:exec 永久 I/O 重定向
bash 复制代码
# 例1:脚本日志------所有输出自动写日志文件
#!/bin/bash
LOG="/var/log/myapp/$(date +%F).log"
exec > "$LOG" 2>&1                   # 🔒 stdout + stderr → 日志文件
echo "📅 Script started at $(date)"
echo "👤 Running as: $(whoami)"
ls /nonexistent 2>&1                 # 错误也写入日志
echo "✅ Script finished"

# 例2:同时保留屏幕输出------先备份再恢复
#!/bin/bash
exec 3>&1                       # 📌 FD 3 = 原始 stdout(屏幕)的备份
exec > /tmp/script.log 2>&1     # 🔒 stdout/stderr → 文件

echo "This goes to file only"   # 写文件
echo "Also to file" >&2         # stderr 也写文件

echo "I want screen!" >&3       # 💡 通过 FD 3 仍可输出到屏幕!

exec 1>&3 3>&-                  # 🔓 恢复 stdout → 屏幕,关闭 FD 3
echo "Back to screen"           # 屏幕可见

# 例3:自定义 FD 写入多个文件
#!/bin/bash
exec 3> /tmp/success.log        # FD 3 → 成功日志
exec 4> /tmp/error.log          # FD 4 → 错误日志

for f in /etc/*.conf; do
    if [ -r "$f" ]; then
        echo "✅ readable: $f" >&3
    else
        echo "❌ not readable: $f" >&4
    fi
done

exec 3>&-                       # 关闭 FD 3
exec 4>&-                       # 关闭 FD 4

# 例4:从文件逐行读取(不用 while read 管道)
exec 3< /etc/passwd             # FD 3 用于读取
while IFS=: read -r user _ uid _ _ _ shell <&3; do
    echo "👤 $user (UID=$uid) → $shell"
done
exec 3<&-                       # 关闭 FD 3
exec 注意事项
⚠️ 注意点 说明
exec 替换不可逆 exec command 后,Shell 消失,后续代码不执行
永久重定向影响全局 exec > file 后所有输出都去文件,要恢复需提前备份 FD
FD 泄漏 打开的自定义 FD 记得用 exec N>&- 关闭
子进程继承 FD 子进程会继承父进程打开的 FD,注意安全
脚本调试困难 永久重定向后屏幕无输出,调试时可能困惑

4.6 管道与 tee 命令详解

管道(Pipe)是什么?

管道 | 将前一个命令的 stdout 连接到后一个命令的 stdin ,形成数据流水线。

bash 复制代码
# 管道:前一命令 stdout → 后一命令 stdin
cut -d: -f1 /etc/passwd | sort | uniq
tee 命令是什么?

tee 像一个 T 型水管接头🔧,将数据流同时 分向两个方向:屏幕 文件。

选项 说明 示例
tee file 覆盖写入文件,同时屏幕显示 `ls -l
tee -a file 追加写入文件 `echo "new"
tee f1 f2 同时写入多个文件 `echo "hi"
sudo tee 解决 sudo > 无权限问题 `echo "line"
bash 复制代码
# tee:分流,既输出屏幕又写文件
ls -l | tee /tmp/listing.txt

# tee -a 追加
echo "new line" | tee -a /tmp/log.txt

# 💡 常见技巧:sudo 写系统文件
# ❌ 错误:sudo echo "127.0.0.1 myhost" > /etc/hosts  (重定向在 sudo 之外)
# ✅ 正确:
echo "127.0.0.1 myhost" | sudo tee -a /etc/hosts

# 管道只传 stdout,要传 stderr 需:
cmd 2>&1 | tee log.txt       # stdout + stderr 都进管道
cmd |& tee log.txt            # Bash 4+ 简写

使用场景

  • 长时间运行的命令,想实时看输出 同时记录日志
  • 需要用 sudo 写入系统配置文件
  • 将同一份数据同时写入多个文件
tee 更多示例与使用场景
场景 示例
管道中保存中间结果并继续处理 `ls -l
同时写入多个文件 `echo "backup done"
只保存到文件、不显示在屏幕 `cmd
捕获命令的 stdout+stderr `cmd 2>&1
实时跟踪日志并保存 `tail -f /var/log/syslog
结合 sudo 写 root 文件 `echo "options"
I/O 与 tee 练习
  1. ls /etc 的结果同时保存到 /tmp/etclist.txt 并在屏幕显示。
  2. date 的输出追加到 /tmp/dates.log,且屏幕也要看到。
  3. 用 tee 实现:执行 find /etc -name "*.conf" 的结果既保存到文件又统计行数(wc -l)。
  4. 不切换 root,向 /etc/hosts 追加一行 127.0.0.1 mytest(用 tee)。

参考答案

bash 复制代码
ls /etc | tee /tmp/etclist.txt
date | tee -a /tmp/dates.log
find /etc -name "*.conf" | tee /tmp/confs.txt | wc -l
echo "127.0.0.1 mytest" | sudo tee -a /etc/hosts

4.7 重定向顺序陷阱图解

记忆口诀 :先定向、后复制。2>&1 复制的是此刻 FD 1 指向的目标。

4.8 set -C 防覆盖

bash 复制代码
set -C                # 开启:禁止 > 覆盖已有文件
echo "x" > exist.txt  # 报错!
echo "x" >| exist.txt # >| 强制覆盖
set +C                # 关闭

使用场景:防止脚本中误覆盖重要文件,特别是日志和配置文件。


五、文件查找(find / locate / xargs)

5.0 文件查找工具对比

5.1 locate vs find

对比项 locate find
数据来源 数据库(/var/lib/mlocate) 实时遍历目录
更新 updatedb(cron 每日) 无需
匹配 模糊匹配路径 精确、多条件
速度 极快 较慢
使用场景 快速定位已知文件名 条件复杂、需精确匹配

5.2 find 完整用法

text 复制代码
find [路径] [条件] [动作]
按名称
条件 说明 示例
-name 精确匹配(大小写敏感) find / -name "*.conf"
-iname 忽略大小写 find / -iname "readme*"
-regex 正则匹配完整路径 find . -regex ".*\.txt$"
-path 匹配路径 find /usr -path "*local*"
按属主/权限
条件 说明
-user / -group 属主 / 属组
-nouser / -nogroup 无属主 / 无属组
-perm 644 精确匹配 644
-perm -644 包含 644 所有位
-perm /644 任一位匹配即可
按类型/大小/时间
条件 说明
-type f/d/l/b/c/s/p 文件类型
-size +10M 大于 10MB
-size -1k 小于 1KB
-mtime -7 7 天内修改过
-mtime +30 30 天前修改
-mmin -10 10 分钟内修改
-newer file 比 file 更新
-maxdepth N 最大搜索深度
组合条件
bash 复制代码
# 与(默认)
find . -name "*.log" -size +1M

# 或
find . -name "*.txt" -o -name "*.md"

# 非
find . -not -user root

# 分组
find /usr -not \( -user root -o -user bin \)
处理动作
动作 说明
-print 默认,打印路径
-ls 类似 ls -dils 格式
-delete 直接删除
-exec CMD {} \; 对每个结果执行命令
-ok CMD {} \; 同上,需确认
bash 复制代码
find /etc -size +1M -exec ls -lh {} \;
find /tmp -mtime +30 -delete
find . -name "*.bak" -ok rm {} \;
find / \( -nouser -o -nogroup \) -exec chown root:root {} \;
find 使用场景与练习
使用场景 示例
清理临时/旧文件 find /tmp -mtime +7 -type f -delete
找大文件 find / -type f -size +100M 2>/dev/null
找空文件/空目录 find . -empty
找 7 天内修改的配置 find /etc -name "*.conf" -mtime -7
忽略权限错误 find / -name "*.log" 2>/dev/null
限制深度 find /usr -maxdepth 2 -name "*.h"
按 inode 查 find . -inum 12345

练习

  1. /etc 下查找大于 1MB 的普通文件并列出 ls -lh
  2. 查找当前目录下 30 天未修改的 .log 文件并删除(先去掉 -delete-print 确认)。
  3. 查找 /home 下属主为 student 且扩展名为 .sh 的文件。
  4. 查找系统中无属主的文件(-nouser),仅列出前 10 个。

参考答案

bash 复制代码
find /etc -type f -size +1M -exec ls -lh {} \;
find . -name "*.log" -mtime +30 -delete   # 确认后改用 -delete
find /home -user student -name "*.sh"
find / -nouser 2>/dev/null | head -10

5.3 xargs 命令详解

xargs 是什么?

xargsstdin 读取数据,将其拆分后作为参数传递给后面的命令。它是连接"管道"和"不接受 stdin 的命令"之间的桥梁。

选项 说明 示例
xargs 默认将 stdin 作为参数传给 echo `echo "a b c"
-n N 每次最多传 N 个参数 `...
-I {} {} 占位符替换每个参数 `...
-0 以 NULL 分隔(配合 -print0 `find . -print0
-p 执行前确认 `...
-t 打印将要执行的命令 `...
-P N 并行执行 N 个进程 `...
bash 复制代码
# 比 -exec 更高效:批量传参
find . -name "*.log" | xargs rm -f
find . -name "*.txt" | xargs grep "error"

# 文件名含空格时(⚠️ 必须用 -print0 + -0)
find . -name "*.log" -print0 | xargs -0 rm -f

# 限制每次传入参数数
find . -name "*.jpg" | xargs -n 5 ls -l

# -I {} 占位符:逐个复制到 /backup
find . -name "*.conf" | xargs -I {} cp {} /backup/

# 💡 并行压缩:4 个进程同时 gzip
find . -name "*.log" | xargs -P 4 -n 1 gzip

# 💡 统计多个文件的行数
find . -name "*.py" | xargs wc -l

xargs vs -exec 对比

| 对比项 | find -exec {} \; | find | xargs |
|------|--------------------|-------------------|
| 调用方式 | 每个文件调用一次命令 | 批量传参,调用次数少 |
| 性能 | 较慢 | ⚡ 更快 |
| 空格处理 | 自动处理 | 需 -print0 + -0 |
| 灵活性 | 简单 | 支持 -n/-P/-I |

locate 使用场景与练习
使用场景 示例
快速找命令路径 locate -i passwd(-i 忽略大小写)
更新数据库后查找 sudo updatedblocate nginx.conf
限制条数 locate -n 20 "*.conf"

练习

  1. 用 locate 查找系统中名为 passwd 的文件(忽略大小写),数一数有多少个。
  2. 查找名字中包含 grub 的路径,只显示前 5 条。

参考答案

bash 复制代码
locate -i passwd | wc -l
locate -n 5 grub
find + xargs 综合练习
  1. 将当前目录及子目录下所有 .txt 文件复制到 /backup(文件名含空格时用 -print0/-0)。
  2. 查找 /var/log 下 7 天前的 .log 文件并用 gzip 压缩(用 xargs,每次传一个参数)。
  3. 用 xargs 对 find . -name "*.c" 的结果执行 wc -l,得到每个文件行数及总行数。

参考答案

bash 复制代码
find . -name "*.txt" -print0 | xargs -0 -I {} cp {} /backup/
find /var/log -name "*.log" -mtime +7 | xargs -n 1 gzip
find . -name "*.c" | xargs wc -l

六、Vim 编辑器

6.0 Vim 模式切换总览

6.1 三种基本模式

模式 进入方式 用途 退出
普通模式 打开文件默认、Esc 移动、删除、复制 -
插入模式 i/a/o/I/A/O/s/c 输入文本 Esc
命令行模式 : 保存/退出/替换/设置 Esc 或 Enter

额外模式:可视模式 (v/V/Ctrl-v)、替换模式(R)。

6.2 打开与关闭

操作 命令
打开 vim file
打开定位第 N 行 vim +N file
打开定位末行 vim + file
打开定位匹配行 vim +/pattern file
保存退出 :wq:xZZ
不保存退出 :q!
强制保存 :w!
全部退出 :qa

6.3 移动(普通模式)

范围 命令
字符 h j k l(左下上右)
单词 w 词首、b 前词首、e 词尾
行内 0 行首、^ 首非空、$ 行尾
行间 NG 第 N 行、G 末行、gg 首行
翻屏 Ctrl+f/b 全屏、Ctrl+d/u 半屏
匹配括号 % 跳转到配对括号

6.4 编辑操作

操作 命令 说明
删除 dd #dd d$ dw dG 删行/N 行/到行尾/词/到末行
复制 yy #yy y$ yw 用法同 d
粘贴 p(后)P(前) 整行粘贴在下/上方
修改 cc cw c$ 删除并进入插入模式
删字符 x(后)X(前)
撤销 u 多次 u 可连续撤销
重做 Ctrl+r
重复 . 重复上次编辑操作

6.5 查找与替换

vim 复制代码
/pattern          " 向下搜索
?pattern          " 向上搜索
n / N             " 下一个 / 上一个
*                 " 搜索光标下的单词

" 替换
:s/old/new/       " 当前行第一个
:s/old/new/g      " 当前行全部
:%s/old/new/g     " 全文替换
:%s/old/new/gc    " 全文替换并逐个确认
:3,10s/old/new/g  " 第 3~10 行

分隔符可替换::%s#/usr/bin#/bin#g(用 # 避免转义 /)。

6.6 可视模式

模式 快捷键 选择方式
字符可视 v 按字符选择
行可视 V 整行选择
块可视 Ctrl-v 矩形块选择
vim 复制代码
" 块可视:给多行行首加注释
Ctrl-v → 选择多行 → I → # → Esc

" 块可视:给多行行尾加分号
Ctrl-v → 选择多行 → $ → A → ; → Esc

6.7 寄存器

寄存器 说明
"" 匿名寄存器(默认)
"0 最近一次复制
"1~"9 最近 9 次删除
"a~"z 26 个命名寄存器(大写追加)
"+ / "* 系统剪贴板
"_ 黑洞寄存器(删除不保存)
"/ 最近搜索模式
"% 当前文件名
vim 复制代码
"ayy              " 复制到寄存器 a
"ap               " 从寄存器 a 粘贴
"Ayy              " 追加到寄存器 a
"+yy              " 复制到系统剪贴板
"+p               " 从系统剪贴板粘贴
:reg              " 查看所有寄存器
Ctrl-r a          " 插入模式中插入寄存器 a

6.8 宏录制

vim 复制代码
qa                " 开始录制到寄存器 a
... 操作 ...
q                 " 停止录制
@a                " 执行宏 a
@@                " 重复上次宏
99@a              " 执行 99 次(遇错自动停止)

6.9 多文件与分屏

vim 复制代码
" 多文件
vim file1 file2
:next / :prev / :first / :last
:qa               " 全部退出

" 分屏
Ctrl-w s          " 水平分
Ctrl-w v          " 垂直分
Ctrl-w w          " 切换窗口
Ctrl-w q          " 关闭当前窗口
vim -o f1 f2      " 水平分屏打开
vim -O f1 f2      " 垂直分屏打开

6.10 与 Shell 交互及读写

vim 复制代码
:r /path/to/file           " 读入文件内容
:r !date                   " 插入命令输出
:20,30w /tmp/snippet.txt   " 导出指定行
:! ls -l                   " 执行 Shell 命令

6.11 常用设置与 vimrc

设置 命令
行号 :set nu / :set nonu
忽略大小写 :set ic / :set noic
自动缩进 :set ai / :set noai
搜索高亮 :set hlsearch / :set nohlsearch
语法高亮 :syntax on / :syntax off
Tab 宽度 :set tabstop=4 shiftwidth=4 expandtab

配置文件:全局 /etc/vimrc、个人 ~/.vimrc

Vim 使用场景与练习
场景 操作
打开并跳到第 50 行 vim +50 file:50
打开并定位到某字符串 vim +/pattern file
多文件时下一个/上一个 :next / :prev
块可视:多行行首加 # Ctrl-v → 选行 → I → # → Esc
全文替换且逐个确认 :%s/old/new/gc
只对 10--20 行替换 :10,20s/old/new/g
读入命令输出到当前缓冲 :r !date
保存选中行到文件 可视选中后 :w! >> /tmp/sel.txt

练习

  1. 在 Vim 中把全文的 foo 替换为 bar,且每次替换前确认(gc)。
  2. 用块可视在 5 行行首插入 # (注释)。
  3. 不退出 Vim,执行 :r !ls -l 把当前目录列表插入到光标下。

参考答案

vim 复制代码
:%s/foo/bar/gc
Ctrl-v → 选 5 行 → I → # → 空格 → Esc
:r !ls -l

七、系统监控与性能工具

7.0 监控工具地图

7.1 监控工具总览

工具 主要监控对象 使用场景
top / htop 进程、CPU、内存 实时查看系统负载与进程
free 内存、Swap 快速查看内存使用
vmstat CPU、内存、I/O、Swap 整体性能概览
iostat 磁盘 I/O、CPU 磁盘瓶颈排查
sar 综合(CPU/内存/网络/磁盘) 历史性能分析
uptime 负载 快速查看 1/5/15 分钟负载
du / df 磁盘空间 磁盘使用排查
lsof 打开文件/端口 查端口占用/恢复文件

7.2 top 详解

输出行解读

内容 关键指标
第 1 行 系统时间、运行时长、用户数、负载 load average > CPU 核数则过载
第 2 行 进程数(running/sleeping/zombie) zombie > 0 需关注
第 3 行 CPU 状态 us+sy > 80% 则 CPU 忙;wa > 10% 则 I/O 等待多
第 4 行 内存 buff/cache 可回收,不等于"被占"
第 5 行 Swap used 持续增长说明内存不足

交互命令

按键 作用
1 显示各逻辑 CPU
P 按 CPU 排序
M 按内存排序
T 按时间排序
k 杀进程
c 显示完整命令行
q 退出
top / free / vmstat / iostat 使用场景与练习
工具 使用场景 示例
top 实时看 CPU/内存占用最高的进程 进入 top 后按 P(CPU)或 M(内存)
top 批处理模式(脚本中) `top -b -n 1
free 快速看内存是否紧张 free -h,关注 available
vmstat 持续观察整体负载 vmstat 2(每 2 秒刷新)
vmstat 采样若干次 vmstat 1 5(共 5 次)
iostat 看磁盘 I/O 瓶颈 iostat -x 2 3(扩展输出,每 2 秒,3 次)
iostat 仅 CPU iostat -c 1 3

练习

  1. 用一条命令输出当前负载(1/5/15 分钟)和内存概要(可用内存)。
  2. vmstat 1 3 观察输出,说明 rbwa 分别代表什么。
  3. free -h 写出「实际可用内存」对应哪一列。
  4. top -b -n 1 取前 15 行保存到 /tmp/top_snapshot.txt

参考答案

bash 复制代码
uptime; free -h | grep Mem
# r=运行队列 b=阻塞进程 wa=I/O 等待
# available 列
top -b -n 1 | head -15 > /tmp/top_snapshot.txt

7.3 free 详解

bash 复制代码
free -h    # 人类可读格式
字段 含义
total 物理内存总量
used 已使用(含 buff/cache)
free 完全空闲
buff/cache 缓冲/缓存(可回收)
available 实际可用(free + 可回收 buff/cache)

看 available 而非 free。available 低于总内存 20% 时应关注。

7.4 vmstat 详解

bash 复制代码
vmstat 2 5    # 每 2 秒采样,共 5 次
字段 含义 告警阈值
r 运行队列长度 > CPU 核数 → CPU 忙
b 阻塞进程数 > 0 持续 → I/O 瓶颈
swpd 已用虚拟内存 > 0 → 物理内存不足
si / so 每秒 swap 换入/出 > 0 持续 → 内存紧张
bi / bo 每秒块读/写 突增 → I/O 操作频繁
cs 每秒上下文切换 过高 → 线程/进程过多
us 用户态 CPU
sy 内核态 CPU us+sy > 80% → CPU 忙
id 空闲 CPU < 20% → 过载
wa I/O 等待 > 30% → I/O 瓶颈

7.5 iostat 详解

bash 复制代码
iostat -d -x -k 2 3    # 每 2 秒,共 3 次,详细磁盘信息
指标 含义 告警
r/s, w/s 每秒读/写请求数
rkB/s, wkB/s 每秒读/写数据量
await 平均 I/O 等待(ms) > svctm 很多则队列长
svctm 平均服务时间(ms)
%util I/O 使用率 > 70% → 瓶颈

7.6 du / df

bash 复制代码
df -Th                          # 文件系统类型 + 可读
df -ih                          # inode 使用情况
du -sh /var/log                 # 目录总大小
du -h --max-depth=1 /var        # 一级子目录大小
du -sh /var/log/* | sort -rh    # 排序找大目录
du / df 使用场景与练习
场景 示例
看根分区与各挂载点使用率 df -h
看 inode 是否耗尽 df -ih
找目录下最大的子目录 `du -sh /var/*
只看一级子目录大小 du -h --max-depth=1 /usr
排除某类型 du -sh /var/log/* 或结合 find

练习

  1. 统计 /var 下占用空间最大的前 3 个子目录。
  2. 查看根分区 / 的 inode 使用率(df -ih /)。
  3. 用 du 计算当前用户家目录总大小(人类可读)。

参考答案

bash 复制代码
du -sh /var/* 2>/dev/null | sort -rh | head -3
df -ih /
du -sh $HOME

7.7 lsof 命令详解

lsof 是什么?

lsof = L is t O pen F iles,列出系统中所有被进程打开的文件 。由于 Linux "一切皆文件",所以 lsof 能查看:普通文件、目录、网络连接(Socket)、管道、设备等。

选项 说明 使用场景
lsof -i :PORT 查看端口占用 🌐 排查端口冲突:"谁占了 80 端口?"
lsof -i tcp 查看所有 TCP 连接 🌐 网络排查
lsof -u USER 某用户打开的文件 👤 审计用户行为
lsof +D DIR 某目录下被打开的文件 📂 排查 umount "device busy"
lsof -p PID 某进程打开的文件 ⚙️ 分析进程资源
lsof FILE 谁在使用某文件 📄 排查文件锁
lsof -c NAME 按命令名过滤 ⚙️ 查看 nginx/java 打开了什么
bash 复制代码
lsof -i :80                     # 查看 80 端口被谁占用
lsof -i :8080 -i :3306          # 同时查多个端口
lsof -u username                # 某用户打开的文件
lsof +D /var/log                # 某目录下被打开的文件
lsof -p PID                     # 某进程打开的文件
lsof /path/to/file              # 谁在使用某文件
lsof -c nginx                   # nginx 进程打开的所有文件

# 💡 查看进程打开的网络连接
lsof -i -a -p $(pgrep nginx)

# 💡 查找删除但未释放的大文件(磁盘满排查利器!)
lsof +L1    # 列出 link count < 1 的文件(已删除但仍被占用)

误删文件恢复 :若文件被删但仍有进程持有 FD,可从 /proc/PID/fd/N 恢复:

bash 复制代码
# 1. 找到被删文件的进程和 FD
lsof | grep deleted
# 2. 从 /proc 恢复
cp /proc/PID/fd/N /tmp/recovered_file

场景:误删了正在被 nginx 使用的日志文件,但 nginx 仍持有文件句柄,可以用此方法恢复。

lsof 使用场景与练习
场景 示例
端口被占用排查 lsof -i :80lsof -i :8080
某用户打开的文件 lsof -u nginx
某进程打开的文件与网络 lsof -p $(pgrep nginx)
谁在用某目录(umount 失败时) lsof +D /mnt/data
查找已删除仍被占用的文件(磁盘满) lsof +L1 或 `lsof

练习

  1. 查看 22 端口被哪个进程占用。
  2. 列出当前用户打开的所有文件数(lsof -u $USER \| wc -l)。
  3. 若某文件被删但进程仍占用,写出从 /proc 恢复的步骤。

参考答案

bash 复制代码
lsof -i :22
lsof -u $USER | wc -l
# 1) lsof | grep deleted 找到 PID 和 FD
# 2) cp /proc/PID/fd/FD /path/recovered

7.8 性能排查思路(USE 法则)

uptime 负载 > 核数
正常
free 的 available 低
正常
iostat %util > 70%
正常
sar -n DEV 检查
正常
🚨 系统变慢了!
🔥 CPU 负载高?
top 按 P 排序

找高 CPU 进程
🧠 内存不足?
top 按 M 排序

找内存大户

检查 swap 使用
💾 磁盘 I/O 慢?
iotop 找 I/O 大户

检查 await
🌐 网络问题?
ss 查连接数

检查带宽/延迟
⚙️ 应用层问题

查看日志/strace

USE 法则(Utilization, Saturation, Errors):对每个资源检查利用率、饱和度、错误数。

步骤 方法 工具
1. 🔥 CPU 查负载、us/sy/wa uptimetopvmstat
2. 🧠 内存 查 available、swap free -hvmstat
3. 💾 磁盘 I/O 查 %util、await iostatiotop
4. 🌐 网络 查带宽、连接数 sar -n DEVss
5. ⚙️ 进程 定位消耗资源的进程 toppidstatlsof

八、特殊权限(SUID/SGID/Sticky)要点

权限 数字 对文件效果 对目录效果 设置
SUID 4 进程属主=文件属主(如 /usr/bin/passwd - chmod u+s FILE
SGID 2 进程属组=文件属组 新建文件继承目录属组 chmod g+s DIR
Sticky 1 - 仅属主和 root 可删除文件(如 /tmp chmod o+t DIR
bash 复制代码
# 查找系统中所有 SUID 程序(安全审计)
find / -perm -4000 -type f -ls 2>/dev/null

# 团队共享目录(SGID + Sticky)
mkdir /shared
chgrp team /shared
chmod 3775 /shared    # SGID(2) + Sticky(1) = 3
  • 有 x 时显示 s/t,无 x 时显示 S/T(后者无实际执行意义)。
  • 详见《Linux文件系统与FHS详解》中"文件权限与特殊权限"章节。

九、重要命令功能速查

对本文涉及的重要命令进行功能解释,快速了解"这个命令是干什么的"。

9.1 进程与 Shell 相关

命令 全称/来源 🎯 一句话解释 使用场景
exec execute ⚡ 替换当前进程或永久重定向 I/O Docker 入口、日志重定向、FD 管理
source / . - 📥 在当前 Shell 中执行脚本(不新建子进程) 加载环境变量、函数库
export - 📤 将变量导出为环境变量,子进程可见 设置 PATH、JAVA_HOME
eval evaluate 🔄 二次解析并执行字符串为命令 动态构建命令
set - ⚙️ 设置 Shell 选项(-e/-u/-x/-o pipefail) 脚本加固
trap - 🪤 捕获信号并执行指定动作 清理临时文件、优雅退出
nohup no hang up 🔌 让命令忽略 SIGHUP,终端关闭仍运行 后台长时间任务
disown - 🏃 将后台任务从 Shell 作业表中移除 防止退出时杀进程
bg / fg background / foreground 🔀 将作业切到后台/前台运行 作业控制
source vs exec vs bash 对比
方式 命令 新进程? 环境继承 Shell 继续?
source source script.sh. script.sh ❌ 不创建 变量影响当前 Shell ✅ 继续
bash bash script.sh ✅ 创建子进程 子进程变量不影响父进程 ✅ 继续
exec exec script.sh 替换当前进程 Shell 消失 ❌ 不返回
bash 复制代码
# source:加载 .bashrc 到当前 Shell
source ~/.bashrc          # 修改立即生效

# bash:子进程执行脚本
bash test.sh              # 脚本中定义的变量不影响当前 Shell

# exec:替换当前 Shell
exec bash test.sh         # 当前 Shell 被替换,不会返回
9.1.1 更多示例与练习(进程与 Shell 命令)
命令 示例 使用场景
source source /etc/profile.d/java.sh 加载 Java 环境到当前 Shell
export export DEBUG=1 脚本中传递调试开关给子进程
nohup nohup ./longrun.sh & 后台跑长时间任务,关闭终端不退出
disown jobs; disown %1 把已启动的后台任务从作业表移除
trap trap 'rm -f /tmp/$$.tmp' EXIT 脚本退出时删除临时文件

练习 :用 nohup 在后台运行 sleep 300,用 jobsps 确认;再用 disown 将该项目从 jobs 中移除。

9.2 文件操作相关

命令 全称/来源 🎯 一句话解释 使用场景
tee T 型管道 🔧 将 stdin 同时输出到屏幕文件 记录日志同时实时查看
xargs ex tended arg uments 🔗 将 stdin 转为命令行参数 配合 find 批量操作
install - 📦 复制文件并设置权限/属主(一步到位) 部署二进制、创建目录
mktemp make temporary 🗑️ 安全创建临时文件/目录 脚本中临时文件
stat status 📊 显示文件的详细元数据(inode/权限/时间) 查看文件详细信息
file - 🔍 识别文件真实类型(不看扩展名) 判断未知文件格式
ln link 🔗 创建硬链接或符号链接 共享文件、快捷方式
bash 复制代码
# install:复制+设权限(部署常用)
install -m 755 myapp /usr/local/bin/    # 复制并设 755
install -d -m 700 /opt/myapp/config     # 创建目录并设权限
install -o root -g root -m 644 config.conf /etc/myapp/

# mktemp:安全创建临时文件
TMPFILE=$(mktemp)                  # /tmp/tmp.XXXXXXXXXX
TMPDIR=$(mktemp -d)                # 创建临时目录
echo "data" > "$TMPFILE"
rm -f "$TMPFILE"                   # 用完记得清理

# stat:查看文件详细信息
stat /etc/passwd
# 输出:大小、块数、inode、权限、时间等

# file:识别文件类型
file /bin/ls                       # ELF 64-bit LSB executable
file /etc/passwd                   # ASCII text
file image.png                     # PNG image data
9.2.1 更多示例与练习(文件操作命令)
命令 示例 使用场景
tee `dmesg tee -a /tmp/dmesg.log
xargs `printf '%s\n' a b c xargs -I {} echo item: {}`
install install -m 755 -o root script.sh /usr/local/bin/ 部署脚本并设属主与权限
mktemp T=$(mktemp -u); echo $T 只生成临时路径不创建文件(-u)
stat stat -c '%i %n' file 只输出 inode 和文件名
file file -b /bin/ls 简短类型描述(-b 无文件名)

练习 :用 install -d 创建目录 /opt/myapp/{bin,conf,log}(需 shell 大括号展开),并用 install -m 644 将当前目录下某配置文件复制到 /opt/myapp/conf/

9.3 文本处理相关

命令 全称/来源 🎯 一句话解释 使用场景
grep g lobal r egular e xpression print 🔍 按正则过滤文本行 日志搜索、数据过滤
sed s tream editor ✂️ 流式编辑器,按行处理文本 批量替换、删除行
awk Aho, Weinberger, Kernighan 📊 按列处理文本,内建编程语言 数据统计、报表生成
cut - ✂️ 按分隔符/字符位置截取列 提取特定字段
sort - 🔢 排序文本行 数据排列
uniq unique 🔄 去除/统计相邻重复行 去重(需先 sort)
tr translate 🔤 转换/删除字符 大小写转换、字符替换
wc w ord count 📏 统计行数/词数/字符数 快速统计
bc b asic calculator 🧮 命令行计算器(支持浮点) Shell 中做浮点运算
bash 复制代码
# bc:Shell 中唯一方便做浮点运算的工具
echo "scale=2; 10/3" | bc          # 3.33
echo "3.14 * 2.5" | bc             # 7.85
echo "sqrt(144)" | bc              # 12

# tr:字符级转换
echo "hello" | tr 'a-z' 'A-Z'     # HELLO
echo "hello   world" | tr -s ' '  # 压缩连续空格
echo $PATH | tr ':' '\n'          # PATH 每行显示

# cut + sort + uniq 组合
cut -d: -f7 /etc/passwd | sort | uniq -c | sort -rn
# 统计系统中每种 shell 被多少用户使用
9.3.1 更多示例与练习(文本处理命令)
命令 示例 使用场景
grep grep -r "ERROR" /var/log --include="*.log" 递归在日志中搜错误
sed sed -i.bak 's/old/new/g' file 原地替换并备份为 file.bak
awk awk -F: '$3>=1000 {print $1}' /etc/passwd 打印 UID≥1000 的用户名
cut cut -d: -f1,3 /etc/passwd 取用户名和 UID 两列
sort sort -t: -k3 -n /etc/passwd 按第 3 列数字排序
uniq `sort file uniq -d`
tr tr -d '\r' < win.txt > unix.txt 去掉 Windows 回车符
wc wc -l < file 仅输出行数(无文件名)
bc `echo "2^10" bc`

练习 :用 awk/etc/passwd 中输出「用户名:UID」且仅 UID 小于 100 的系统用户;用 grep -c 统计包含 nologin 的行数。

9.4 系统管理相关

命令 全称/来源 🎯 一句话解释 使用场景
chage ch ange age 📅 管理密码生命周期策略 密码过期、强制修改
chown ch ange owner 👤 修改文件属主和属组 权限管理
chmod ch ange mode 🔐 修改文件权限 设置 rwx
umask u ser file creation mask 🎭 设置新建文件的默认权限掩码 控制默认权限
lsof l is t o pen files 🔍 列出被进程打开的文件 端口排查、恢复删除文件
useradd - 👤 添加系统用户 创建用户账户
usermod - 🔧 修改用户属性 改组、改 Shell、锁定
passwd password 🔑 修改用户密码 设置/重置密码
su s witch user 🔄 切换用户身份 切 root、测试权限
sudo su peruser do 🛡️ 以其他用户身份执行命令 临时提权
9.4.1 更多示例与练习(系统管理命令)
命令 示例 使用场景
chage chage -l root 审计 root 密码策略
chown chown -R apache:apache /var/www 部署 Web 目录属主
chmod chmod g+w file 给组增加写权限
umask umask 077; touch f; ls -l f 验证新文件为 600
lsof `lsof -i -P -n grep LISTEN`
useradd useradd -m -s /bin/bash -c "Dev" u1 创建带家目录的普通用户
usermod usermod -L u1 锁定账户
passwd passwd -l u1 锁定(同 usermod -L)
su su - appuser -c "whoami" 以 appuser 执行单条命令
sudo sudo -u nobody id 以 nobody 查看 id

练习 :创建用户 deploy,家目录 /home/deploy,加入组 docker;将其 shell 改为 /bin/bash;用 chage -d 0 deploy 强制首次登录改密。


十、代表性练习选编

10.1 基础练习(原选编)

  1. 取出系统中所有用户的 shell,每种只显示一次并排序
bash 复制代码
cut -d: -f7 /etc/passwd | sort -u
  1. 取 /etc/passwd 倒数第 9 个用户的用户名和 shell,保存并显示
bash 复制代码
tail -9 /etc/passwd | head -1 | cut -d: -f1,7 | tee /tmp/users
  1. find 练习:查找 /etc 下最近一周修改且不属于 root 和 student 的文件:
bash 复制代码
find /etc -mtime -7 -not -user root -not -user student
  1. vim 替换练习:全文替换 URL:
vim 复制代码
:%s@ftp://instructor\.example\.com/pub@http://172.16.0.1/yum@g
  1. 统计 /var 下各一级子目录大小并排序
bash 复制代码
du -sh /var/* 2>/dev/null | sort -rh | head -10
  1. 查找系统中无属主的文件并修改
bash 复制代码
find / \( -nouser -o -nogroup \) -exec chown root:root {} \;
  1. 强制用户下次登录修改密码
bash 复制代码
chage -d 0 username

10.2 用户与组管理练习

  1. 创建系统用户 redis,不允许登录(shell 为 /sbin/nologin),不创建家目录。
  2. 将用户 alice 的主组改为 developers,并追加到组 docker(不覆盖原有组)。
  3. 查看用户 bob 的 UID、主组 GID、所有组 GID(一行一个命令)。
  4. 设置用户 temp 的账号在 2026-12-31 过期;并设置密码 90 天过期、提前 7 天警告。
  5. id 判断用户 nobody 是否存在,在脚本中可用 if id "nobody" &>/dev/null; then ...

参考答案

bash 复制代码
useradd -r -s /sbin/nologin -M redis
usermod -g developers -aG docker alice
id -u bob; id -g bob; id -G bob
chage -E 2026-12-31 temp; chage -M 90 -W 7 temp
id nobody &>/dev/null && echo "exists" || echo "not exists"

10.3 I/O 重定向与管道练习

  1. ls /usr/bin标准输出 保存到 /tmp/out.txt标准错误 保存到 /tmp/err.txt
  2. 将命令 cmd 的 stdout 和 stderr 都追加到 /tmp/all.log(用 >>2>&1)。
  3. 用 Here Document 生成文件 /tmp/motd.txt,内容为两行:Welcome$(date)(要求 date 被展开)。
  4. 用管道和 tee:把 df -h 的结果保存到 /tmp/df.txt,同时在屏幕上显示。
  5. 实现:echo "a:b:c" 通过管道传给 cut,按冒号分隔取第 2 列(得到 b)。

参考答案

bash 复制代码
ls /usr/bin > /tmp/out.txt 2> /tmp/err.txt
cmd >> /tmp/all.log 2>&1
cat > /tmp/motd.txt << EOF
Welcome
$(date)
EOF
df -h | tee /tmp/df.txt
echo "a:b:c" | cut -d: -f2

10.4 find / locate / xargs 练习

  1. 查找 /etc 下所有以 .conf 结尾的普通文件,忽略权限错误,只输出路径。
  2. 查找当前目录下 7 天内修改过的、大于 1MB 的文件。
  3. 用 find 和 xargs 将 /tmp 下所有 .bak 文件删除(考虑文件名含空格:-print0-0)。
  4. 用 find 查找属主为 root 且权限为 755 的可执行文件(-perm -755),在 /usr/bin 下找。
  5. 用 locate 查找包含 cron 的路径,限制输出 10 条。

参考答案

bash 复制代码
find /etc -type f -name "*.conf" 2>/dev/null
find . -mtime -7 -size +1M -type f
find /tmp -name "*.bak" -print0 | xargs -0 rm -f
find /usr/bin -user root -perm -755 -type f
locate cron | head -10

10.5 文本处理与管道练习

  1. 统计 /etc/passwd 的行数;统计其中包含 /bin/bash 的行数。
  2. 显示 /etc/passwd 的第 3 到第 7 行(用 sed -n '3,7p'head -7 | tail -5)。
  3. /etc/passwd 按冒号取第 1 列,排序后去重,再统计每种用户名的数量(sort | uniq -c)。
  4. 将字符串 "Hello World" 中的小写字母转为大写(用 tr 'a-z' 'A-Z')。
  5. grep/etc/passwd 中匹配 UID 为三位数的行(例如 grep ':[0-9]\{3\}:':x:[0-9]\{3\}:)。

参考答案

bash 复制代码
wc -l /etc/passwd; grep -c /bin/bash /etc/passwd
sed -n '3,7p' /etc/passwd
cut -d: -f1 /etc/passwd | sort | uniq -c
echo "Hello World" | tr 'a-z' 'A-Z'
grep -E ':[0-9]{3}:' /etc/passwd

10.6 权限与属主练习

  1. 将文件 script.sh 设为:属主可读可写可执行,属组可读可执行,其他人无权限(数字法)。
  2. 将目录 /srv/shared 及其下所有内容属主改为 www-data,属组改为 www-data
  3. 当前 umask 为 022 时,新建目录的权限是多少?新建普通文件的权限是多少?(答:755、644)
  4. 查找系统中带 SUID 的可执行文件(find / -perm -4000 -type f 2>/dev/null),数一数有多少个。
  5. 创建目录 /tmp/team,要求:属组可写、且新建文件继承该组(SGID)、仅属主和 root 可删文件(Sticky)。写出 chmod 数字(如 3770 或 2775 等)。

参考答案

bash 复制代码
chmod 750 script.sh
chown -R www-data:www-data /srv/shared
# 755 目录,644 文件
find / -perm -4000 -type f 2>/dev/null | wc -l
mkdir /tmp/team; chgrp somegroup /tmp/team; chmod 3770 /tmp/team  # 或 2775 等

10.7 系统监控与综合练习

  1. 用一条命令显示:当前时间、运行时长、负载,以及内存总量和可用内存(uptime + free -h 一行)。
  2. vmstat 1 5 的输出保存到 /tmp/vmstat.log
  3. 查看 80 端口被哪个进程占用;查看 root 用户当前打开的文件数。
  4. 统计 /var 下各一级子目录占用的磁盘空间,按从大到小排序并取前 5。
  5. 综合题:查找 /etc 下最近 24 小时内修改过的、大于 10KB 的配置文件(.conf),将路径列表保存到 /tmp/recent_confs.txt

参考答案

bash 复制代码
uptime; free -h | grep -E "Mem|total|available"
vmstat 1 5 > /tmp/vmstat.log
lsof -i :80; lsof -u root | wc -l
du -sh /var/* 2>/dev/null | sort -rh | head -5
find /etc -name "*.conf" -mtime 0 -size +10k -type f 2>/dev/null > /tmp/recent_confs.txt

相关推荐
Maynor9963 小时前
OpenClaw 第2章:环境搭建
运维·人工智能·飞书
人间打气筒(Ada)3 小时前
SQL Server 之创建和管理数据表
运维·服务器·数据库·windows·sql语句·sql server·windows server
China_Yanhy3 小时前
入职 Web3 运维日记 · 第 13 日:洗钱风云 —— 链上合规 (KYT) 与多签钱包的权力游戏
运维·web3
网云工程师手记3 小时前
防火墙安全区域划分规范与接口配置实操指南
运维·服务器·网络·安全·网络安全
猫头虎3 小时前
猫头虎AI分享:[转载]2025 年 HAMi 社区年度回顾 | 从 GPU 调度器到云原生 AI 基础设施的中流砥柱
运维·人工智能·云原生·开源·gateway·github·ai编程
Howrun7773 小时前
Linux_UDP聊天服务器
linux·服务器·udp
yuanmenghao3 小时前
Linux 性能实战 | 第 19 篇:ftrace 内核跟踪入门 [特殊字符]
linux·python·性能优化
心本无晴.3 小时前
ClawdBot:从桌面自动化到个人AI助手的进化之路
运维·人工智能·自动化
济6173 小时前
ARM Linux 驱动开发篇---TFTP挂载内核设备树,NFS挂载文件系统教程--解决高版本 Ubuntu的nfs挂载系统失败-- Ubuntu20.04
linux·arm开发·驱动开发