Linux 干货速查

面向 Ubuntu 开发主机 + BusyBox 嵌入式开发板的个人速查。

约定

  • ⚠️ 标记危险命令(误用会丢数据 / 断网 / 毁分区),执行前务必确认设备名和路径。
  • 命令行为在不同实现下可能不同,差异处标注:(GNU)Ubuntu 自带 / (BusyBox)板子 / (systemd)。
  • 拿不准的地方标注「待确认」,不猜。

目录

  1. Shell 与环境变量
  2. 文件与目录操作
  3. 文本搜索与处理
  4. 磁盘、分区与文件系统
  5. 内存、CPU 与 I/O 排查
  6. 网络配置与抓包
  7. 文件传输与共享
  8. systemd 与系统服务
  9. 设备管理:udev 与 uevent
  10. 交叉编译工具链
  11. 常见故障与排查案例

Shell 与环境变量

重定向

从文件读入 stdin:

grep "search_term" < file.txt   # 等价 grep "search_term" file.txt

注:原写法 cat < file.txt | grep ... 里的 cat 是多余的,直接 grep ... file.txt 即可(避免 useless use of cat)。

符号作用
> / >>覆盖 / 追加 stdout
2>重定向 stderr
2>&1stderr 合并到 stdout
&> filestdout+stderr 一起(bash 专有;BusyBox ash 不支持,用 > file 2>&1
< file从文件读 stdin

持久化环境变量

写进 ~/.bashrc(当前用户)或 /etc/profile(全局),常用于把工具链、代理等加进 export PATH / export XXX。工具链一键配置见 交叉编译工具链


文件与目录操作

分类:复制/移动/删除 · 链接 · 时间戳 · 归档压缩 · 查找

cp

复制文件/目录。

cp -a src/ dst/     # 归档式复制:保留权限/属主/软链接/时间戳(= -dpR)
  • -a:等于 -d -p -R 的集合
  • -d:源为软链接时,目标也建为软链接(对硬链接无效)
  • -r / -R:递归复制目录
  • -l:把目标建为源文件的硬链接,而非复制
  • -s:把目标建为源文件的软链接,而非复制

ln

创建链接。

ln -s mke2fs mkfs.ext2      # 软链接:ln -s [目标] [链接名]
  • -s:创建软链接(不加 -s 是硬链接)
  • 软链接特点:可跨分区/文件系统、可指向目录;源被删则变成"死链接"(ls 里常显红色)

touch

修改时间戳 / 创建空文件。

touch file            # 文件不存在则创建空文件;存在则更新 atime/mtime
touch -d "2026-01-01" file

权限:root 可保留复制的属主/属组,普通用户不行。

rm / 回收站

⚠️ rm -rf 不可恢复,删前确认路径;尤其变量为空时 rm -rf "$DIR"/ 可能变成 rm -rf /

日常建议用 trash-cli(开发主机)代替 rm

trash-put /path/to/file   # 删除到回收站
trash-list                # 查看回收站
trash-restore             # 恢复
trash-empty               # 清空
trash-empty <days>        # 清空 N 天前的

归档与压缩

tar

tar -zcvf out.tar.gz dir/    # 打包 + gzip
tar -zxvf out.tar.gz         # 解压 gzip
tar -Jxvf out.tar.xz         # 解压 xz
tar -ztvf out.tar.gz         # 只看内容不解压
  • -c 建立归档 / -x 解压 / -t 看内容 / -r 追加 / -u 更新
  • -f 指定档案名,必须是最后一个参数,后面紧跟文件名
  • -z gzip / -j bz2 / -J xz / -Z compress(.Z)
  • -v 显示过程 / -O 解到标准输出

(BusyBox)tar 是子集,部分构建不带 -J/-j/-Z,需外部 xz/gzip 配合。

unzip

unzip file.zip                 # 解压到当前目录
unzip file.zip -d /target/     # 解压到指定目录
  • -d 目录 指定输出目录 / -l 只列内容 / -o 覆盖不询问 / -n 不覆盖 / -q 安静 / -j 不建目录

7za

7za x archive.7z -r -o./       # 按原目录树解压到当前目录
  • x 按原始目录树解压(e 会把所有文件解到同一层)
  • -r 递归子目录 / -o 指定输出目录,-o 后无空格直接跟路径

find

find [路径] [条件] [动作]

# 删除当前目录下除 system 外的所有第一层项(无交互)⚠️
find . -mindepth 1 -maxdepth 1 ! -name system -exec rm -rf {} +
  • -mindepth 1:排除 . 自身
  • -maxdepth 1:只匹配第一层,不递归
  • ! -name system:排除名为 system 的项
  • -exec rm -rf {} +:批量删除匹配项

环境差异:{} +(批量传参)是(GNU)find;(BusyBox)find 的 -exec 多数构建只支持以 \; 结尾,即 -exec rm -rf {} \;(逐个执行,较慢)。

ls

列目录。

  • -a 含隐藏文件 / -l 详细 / -h 人类可读大小(配合 -l
  • -t 按修改时间 / -S 按大小 / -r 反序
  • -f 不排序直接输出(大目录更快,隐含 -a

文本搜索与处理

grep

文本搜索。

grep -n "pattern" file          # 带行号
grep -rn "pattern" .            # 递归搜索目录
grep -o "pattern" file          # 只输出匹配的部分
grep "pattern" f1 f2 f3         # 多文件

# 仅(GNU)grep 支持 include/exclude:
grep -rn "main()" . --include=*.{c,h,cpp}
grep -rn "main()" . --exclude="README" --exclude-from=filelist
  • -n 行号 / -r-R 递归 / -o 只出匹配部分 / -i 忽略大小写 / -v 反选 / -E 扩展正则

环境差异:(BusyBox)grep 支持 -n/-r/-o/-i/-v/-E不支持 --include/--exclude/--exclude-from

rg(ripgrep)

比 grep 快,默认递归、默认遵守 .gitignore。开发主机用,板子一般没有。

rg "pattern"                # 当前目录递归
rg -n "pattern" -g "*.c"    # 限定文件类型
rg -i "pattern"             # 忽略大小写

sort

对文本按行排序。

sort file.txt          # 升序
sort -u file.txt       # 排序并去重
sort -rn file.txt      # 按数值倒序
sort -t: -k2 file.txt  # 以 ":" 分隔,按第 2 列排
  • -u 去重 / -r 倒序 / -n 按数值 / -k N 按第 N 列 / -t C 指定分隔符

示例:

$ cat sort.txt
aaa:10:1.1
ccc:30:3.3
bbb:20:2.2
eee:50:5.5
eee:50:5.5

$ sort -u sort.txt      # 排序 + 去重
aaa:10:1.1
bbb:20:2.2
ccc:30:3.3
eee:50:5.5

scp

hexdump

十六进制查看二进制。

hexdump -C file.bin              # 十六进制 + ASCII
hexdump -C -s 0x100 -n 64 file   # 从偏移 0x100 起看 64 字节
  • -C 规范的十六进制+ASCII / -n length 处理长度 / -s offset 跳过开头字节

cloc

统计代码行数(开发主机)。

cloc --include-lang="C,C++" . --exclude-dir="Reference_project,3rdpart,SDK"
  • --include-lang 只统计指定语言 / --exclude-dir 排除目录
-------------------------------------------------------------------------------
Language          files      blank    comment       code
-------------------------------------------------------------------------------
C++                  62       2557       1224      11747
C                     1        134         61        633
-------------------------------------------------------------------------------
SUM:                 63       2691       1285      12380
-------------------------------------------------------------------------------
  • code:真正代码行(不含空行/注释) / comment:注释行 / blank:空行 / files:文件数

磁盘、分区与文件系统

df

看文件系统占用(排查"磁盘满"第一步)。

df -h        # 各文件系统占用,人类可读
df -h /      # 只看根
df -i        # 看 inode 占用(文件数满同样导致写失败)

du

看目录/文件占用。

du -h -d1        # 当前目录下一层各项大小
du -sh dir/      # 目录总大小
  • -h 人类可读 / -s 只出总计 / -d N 限制深度

环境差异:--max-depth=1 是(GNU)写法;-d1 在 GNU 和 BusyBox 均可用,更通用。

mount

挂载文件系统。

mount -o remount,rw /                                 # 只读 rootfs 重挂为可写(板子常用)
mount -t tmpfs -o size=64M tmpfs /mnt/ram             # 挂内存文件系统
mount -t nfs 192.168.2.100:/home/meian/nfs_share /mnt # 挂 NFS
  • -t 指定文件系统类型 / -o 选项
  • tmpfs:基于内存的临时文件系统,占用随写入增长,上限由 size 限定

mkfs / mke2fs

⚠️ 格式化会清空整个分区,认准设备名,写错分区会毁掉系统盘。

sudo mkfs.ext4 /dev/sdX1     # 格式化为 ext4
mke2fs -t ext4 /dev/sdX1     # 等价;mkfs.extN 本质是指向 mke2fs 的软链接

dd

⚠️ 按扇区裸写,of= 写错设备直接覆盖目标盘、不可恢复。lsblk 确认设备名,注意 /dev/sdX 是整盘、/dev/sdX1 是分区。

sudo dd if=image.img of=/dev/sdX bs=4M status=progress conv=fsync  # 烧写镜像
sudo dd if=/dev/mmcblk0p1 of=part1.img bs=4M                       # 备份分区为镜像

环境差异:status=progress 是(GNU)dd;(BusyBox)dd 无此选项。


内存、CPU 与 I/O 排查

free

看内存占用。输出格式因版本差异较大

新版(GNU / procps-ng,Ubuntu):关注 available(真正可立即分配的量,已扣除可回收缓存),比 free 列更有参考意义。

              total   used   free   shared  buff/cache   available
Mem:        16384000  ...    ...    ...     ...          ...
Swap:       ...

buff/cache = Buffers + Cached + SReclaimable

旧版(BusyBox / 老 procps,多见于板子):带 -/+ buffers 行。

             total     used     free   shared  buffers
Mem:        250444    95988   154456        8     1968
-/+ buffers:          94020   156424
Swap:            0        0        0
  • Mem 行total 总量 / used 已分配(含内核缓存)/ free 完全空闲 / shared 共享内存(tmpfs、shmget)/ buffers 块 I/O 缓冲
  • -/+ buffers 行:把 buffers 剔除后的视角——used = Mem.used - buffers(应用真正占用)、free = Mem.free + buffers(真正可立即分配)
  • Swap 行:全 0 表示未配置 swap

iostat

看 CPU 与块设备 I/O(来自 sysstat 包,BusyBox 默认无)。

~ # iostat
Linux 4.9.138 (Smart Home)      07/28/25        _armv7l_        (2 CPU)

avg-cpu:  %user   %nice %system %iowait  %steal   %idle
           5.45    0.00   11.98    0.00    0.00   82.57

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
mtdblock3         0.00         0.07         0.00       9058          0
sda               0.69         0.01         4.12       1530     540352
  • avg-cpu%user 用户态 / %system 内核态 / %iowait 等 I/O 空闲 / %idle 空闲 / %nice 低优先级用户态 / %steal 虚拟化被抢占
  • Devicetps 每秒 I/O 次数 / Blk_read/sBlk_wrtn/s 每秒读写块数(默认块 512B)/ Blk_readBlk_wrtn 开机以来累计

排查经验:%iowait 高 → 硬盘 I/O 瓶颈;%idle 高但响应慢 → 可能在等内存,考虑加内存;%idle 持续 <10 → CPU 处理能力不足。


网络配置与抓包

⚠️ 改网络配置可能断掉当前 SSH/telnet 连接,远程操作前想好恢复手段。

ifconfig / ip(配置 IP、网关、MAC)

# 设置 IP / 掩码
ifconfig eth0 192.168.2.206 netmask 255.255.255.0    # net-tools / BusyBox
ip addr add 192.168.2.206/24 dev eth0 && ip link set eth0 up   # iproute2(Ubuntu 推荐)

# 默认网关
route add default gw 192.168.2.1        # net-tools / BusyBox
ip route add default via 192.168.2.1    # iproute2

# 改 MAC(先 down 再改再 up)
ifconfig eth0 down
ifconfig eth0 hw ether 00:11:22:33:44:55
ifconfig eth0 up
# iproute2 等价:
ip link set eth0 down
ip link set eth0 address 00:11:22:33:44:55
ip link set eth0 up

环境差异:(BusyBox)板子一般只有 ifconfig/route;(GNU)Ubuntu 上 ifconfig 需装 net-tools,官方推荐 ip

udhcpc

(BusyBox)DHCP 客户端,向 DHCP 服务器申请 IP/掩码/网关/DNS。

udhcpc -i eth0 -b -p /tmp/udhcpc.eth0.pid
  • -i <iface>:指定网卡
  • -b:后台运行(未立刻拿到 IP 时转后台重试,避免同步调用卡死)
  • -p <file>:写 PID 到文件,便于按网卡精确 kill,避免误杀
  • -f:前台运行(默认调试用)
  • -q:拿到租约后立即退出(单次获取)

tcpdump

抓包(BusyBox 默认多无,需交叉编译;开发主机 sudo apt install tcpdump)。

tcpdump -i eth0 -nn                     # 抓 eth0,不解析主机名/端口名
tcpdump -i eth0 -nn host 192.168.2.100  # 只抓与某主机
tcpdump -i eth0 -nn port 69             # 抓 TFTP(69)
tcpdump -i any  -nn icmp                # 抓所有接口的 ping
tcpdump -i eth0 -w cap.pcap             # 存文件,拿到 PC 用 Wireshark 看

虚拟机设置静态 IP(netplan,Ubuntu 开发主机)

⚠️ 改错会导致虚拟机断网。

sudo vi /etc/netplan/01-network-manager-all.yaml
network:
  version: 2
  ethernets:
    ens33:                    # 替换为你的实际网卡名(ip a 查看)
      dhcp4: no
      addresses:
        - 192.168.2.222/24    # 静态 IP / 掩码
      routes:
        - to: default
          via: 192.168.2.2    # 默认网关
      nameservers:
        addresses: [8.8.8.8, 8.8.4.4]
sudo netplan apply

待确认 / 注意:旧写法 gateway4: 192.168.2.2 在 Ubuntu 22.04+(netplan 0.103+)已弃用,改用上面的 routes:。若文件名含 network-manager 且系统用 NetworkManager 渲染,networkd 语法未必生效,以实际 renderer 为准。


文件传输与共享

tftp(板子 ↔ PC)

(BusyBox)板子端上传/下载文件:

tftp -p -l /etc/smart_home.conf -r smart_home.conf 192.168.2.100
  • -p PUT(上传)/ -g GET(下载)
  • -l 板子上的本地文件 / -r PC 端 TFTP 目录里的文件名 / 末尾是 PC 的 IP

环境差异:以上是(BusyBox)tftp 语法;Ubuntu 的 tftp-hpa 客户端语法不同(交互式或 -m)。

PC 端(Ubuntu)tftpd-hpa 服务配置

sudo vi /etc/default/tftpd-hpa
TFTP_DIRECTORY="/srv/tftp"
TFTP_OPTIONS="--secure --create"
  • --create:允许新建文件(板子 PUT 上传时必须)
sudo systemctl restart tftpd-hpa

NFS(Ubuntu 做 server,板子挂载)

# 1. 安装
sudo apt update && sudo apt install nfs-kernel-server

# 2. 创建并放开共享目录
mkdir -p ~/nfs_share && chmod 777 ~/nfs_share

# 3. 配置导出
sudo vi /etc/exports
/home/meian/nfs_share 192.168.2.0/24(rw,sync,no_root_squash,no_subtree_check)

⚠️ 选项之间用英文逗号分隔,不能用中文逗号 ,否则导出解析失败。

  • rw 可读写 / sync 同步写 / no_root_squash 保留客户端 root 权限 / no_subtree_check 不检查子目录树
# 4. 刷新并查看
sudo exportfs -ra
showmount -e

# 服务管理
sudo systemctl status  nfs-kernel-server
sudo systemctl restart nfs-kernel-server

板子端挂载见 mount

Samba(Ubuntu 共享给 Windows/局域网)

sudo vi /etc/samba/smb.conf
[work]
   path = /home/plh/work
   browseable = yes
   writable = yes
   available = yes
   comment = smb share
sudo systemctl restart smbd
sudo smbpasswd -a plh          # 创建 Samba 用户
  • [work]:共享名(客户端"网络邻居"里看到的名字)
  • path:服务器上真实共享目录
  • browseableyes 出现在网络列表;no 需手动 \\server\work 访问
  • writable = yes(等价 read only = no):允许写/改/删

systemd 与系统服务

systemd 是系统启动后第一个进程(PID 1),负责启动和管理服务(daemon)。以下以 mihomo 代理为例。

1. 准备可执行文件(示例)

gzip -d mihomo-linux-amd64-compatible-v1.19.21.gz
mv mihomo-linux-amd64-compatible-v1.19.21 mihomo
chmod +x mihomo
sudo mv mihomo /usr/local/bin/

2. 编写 service 文件

sudo vi /etc/systemd/system/mihomo.service
[Unit]
Description=Mihomo Daemon
# 在网络就绪后再启动(代理依赖网络)
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/mihomo -d /home/meian/.config/mihomo
# 进程退出后自动重启
Restart=always
# 重启前等待秒数
RestartSec=3
# 不输出日志到终端
StandardOutput=null
StandardError=null

[Install]
WantedBy=multi-user.target

⚠️ systemd 不支持行内注释。注释必须独占一行、以 # 开头。像 Type=simple#服务类型After=network.target # ... 这类写法会把注释解析进值里导致出错。

字段含义

  • [Unit]:描述、依赖、启动顺序(After= 只定义顺序,不代表强依赖)
  • [Service]:怎么启动/重启
    • ExecStart:启动命令,必须绝对路径
    • Restart=always:进程挂掉自动重启
    • RestartSec:重启前等待秒数(不是最大重启次数;限制次数用 StartLimitBurst / StartLimitIntervalSec
  • [Install]WantedBy=multi-user.targetenable 时把本服务挂到"多用户模式"这个 target 下,实现开机自启(不是"挂载点")

3. 启动与管理

sudo systemctl daemon-reload      # 改动 unit 文件后必须执行
sudo systemctl start   mihomo     # 启动
sudo systemctl enable  mihomo     # 开机自启
sudo systemctl stop    mihomo     # 停止
sudo systemctl restart mihomo     # 重启
sudo systemctl status  mihomo     # 查看状态

daemon-reexec(重启 systemd 自身)一般不需要,改 unit 用 daemon-reload 即可。


设备管理:udev 与 uevent

内核通过 Netlink 协议族的 NETLINK_KOBJECT_UEVENT 类型,向用户态广播内核对象(kobject)相关的设备事件(uevent),用于热插拔监听。

uevent 消息格式

每条 uevent 是一组键值对,用 \0 分隔,核心字段:

  • ACTIONadd / remove / change
  • DEVPATH:sysfs 路径,如 /devices/pci0000:00/.../usb1/1-1
  • SUBSYSTEM:所属子系统,如 usb / block / input
  • 设备属性:如 DRIVER=usb-storagePRODUCT=1234/5678(厂商/产品 ID)
  • 其他元数据:如 ID_SERIALDEVNAME=sdb
ACTION=add\0
DEVPATH=/devices/pci0000:00/0000:00:14.0/usb1/1-1\0
SUBSYSTEM=usb\0
DRIVER=usb-storage\0
PRODUCT=1234/5678\0
...\0

监听代码(C++)

要点:socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT) 建套接字,nl_groups=1 订阅内核 uevent 组,SO_RCVTIMEO 设接收超时避免完全阻塞。

_hotplug_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_KOBJECT_UEVENT);
if (_hotplug_fd < 0) {
    DEBUG_ERROR("Failed to create netlink socket: %s", strerror(errno));
    _hotplug_running.store(false);
    return;
}

nladdr.nl_family = AF_NETLINK;
nladdr.nl_pid    = getpid();
nladdr.nl_groups = 1;  // NETLINK_KOBJECT_UEVENT 组

if (bind(_hotplug_fd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0) {
    DEBUG_ERROR("Failed to bind netlink socket: %s", strerror(errno));
    ::close(_hotplug_fd);
    _hotplug_fd = -1;
    _hotplug_running.store(false);
    return;
}

// 设置接收超时,避免完全阻塞
struct timeval tv;
tv.tv_sec  = 1;
tv.tv_usec = 0;
setsockopt(_hotplug_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

char buffer[4096];
while (_hotplug_running.load()) {
    memset(buffer, 0, sizeof(buffer));
    int len = recv(_hotplug_fd, buffer, sizeof(buffer) - 1, 0);

    if (len < 0) {
        int err = errno;
        if (err == EAGAIN || err == EWOULDBLOCK) continue;  // 超时,继续
        if (err == EINTR) continue;                          // 被信号中断,继续
        if (!_hotplug_running.load()) break;                 // 正常退出
        DEBUG_ERROR("recv error: %s (errno=%d), will retry", strerror(err), err);
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        continue;
    }
    if (len == 0) {                                          // socket 被关闭
        if (!_hotplug_running.load()) break;
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
        continue;
    }
    parseUevent(buffer);
}

if (_hotplug_fd >= 0) {
    ::close(_hotplug_fd);
    _hotplug_fd = -1;
}

交叉编译工具链

快速配置工具链

写进 ~/.bashrc,用时执行 rk3588 一键设置 ARCH / CROSS_COMPILE / PATH

rk3588() {
    # 按你的实际路径改
    local TC_ROOT="$HOME/work/toolchain/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu"
    local TC_BIN="$TC_ROOT/bin"

    export ARCH=arm64
    export CROSS_COMPILE=aarch64-none-linux-gnu-
    export PATH="$TC_BIN:$PATH"

    echo "ARCH=$ARCH"
    echo "CROSS_COMPILE=$CROSS_COMPILE"
    echo "TOOLCHAIN_BIN=$TC_BIN"

    which "${CROSS_COMPILE}gcc" || return 1
    "${CROSS_COMPILE}gcc" -v 2>&1 | head -n 3
}

查看工具链支持的 C++ 版本

# 看默认 C++ 标准(__cplusplus 宏)
g++ -dM -E -x c++ /dev/null | grep __cplusplus
#   199711=C++98  201103=C++11  201402=C++14  201703=C++17  202002=C++20

# 测试是否支持某标准(能编过即支持)
g++ -std=c++17 -x c++ -fsyntax-only /dev/null && echo OK

原写法 g++ -std=c++11 -E - < /dev/null 只能验证"是否接受 -std=c++11",不能直接看出默认/最高标准,用上面的 __cplusplus 更直观。交叉工具链把 g++ 换成 ${CROSS_COMPILE}g++

nm

列出二进制文件(可执行/库/目标文件)中的符号表。分析目标平台产物时用交叉版 ${CROSS_COMPILE}nm

aarch64-none-linux-gnu-nm -D -C libfoo.so
  • -D:只显示动态符号。库被 strip 后,不加 -D 可能看不到任何输出;加 -D 才能看到对外暴露的接口
  • -Cdemangle,把 C++ 修饰后的符号名还原成可读形式

常见故障与排查案例

排查速查对照

现象先看什么命令
磁盘满 / 写失败磁盘、inode 占用df -hdf -idu -h -d1
内存不足 / OOM真正可用内存free -h(看 available
系统卡、I/O 慢I/O 瓶颈iostat(看 %iowait
加了磁盘但系统没变大分区/文件系统未扩展见下方「虚拟机磁盘扩容」
设备插拔无反应热插拔事件监听 uevent,见 设备管理
板子 TFTP 上传失败服务端未允许新建文件tftpd-hpa 加 --create
systemd 服务不生效改 unit 未重载 / 行内注释daemon-reload;注释必须独占一行

虚拟机磁盘扩容

现象:在 VMware 给虚拟机硬盘"加了 20 GB",只是把底层 .vmdk 拉大了,Ubuntu 里的系统并不知道,需要手动扩分区 + 扩文件系统。

⚠️ 对正被使用的根分区做 parted/resizepart 有风险,务必先确认分区号,最好有快照/备份。

1. 确认磁盘已变大、分区还是旧大小

sudo fdisk -l /dev/sda
# Disk /dev/sda:200 GiB ...
# /dev/sda1  *  2048  377487359  377485312  180G  83 Linux   ← 分区仍是旧大小

2. 用 parted 把分区扩到磁盘末尾 ⚠️

sudo parted /dev/sda
(parted) print free            # 查看末尾的可用空间
(parted) resizepart 1 100%     # 把 1 号分区扩到 100%
# 警告: 分区正被使用。是否继续? → yes
(parted) quit

3. 扩展文件系统到分区大小

# ext2/3/4:
sudo resize2fs /dev/sda1
# xfs(若根是 xfs):
# sudo xfs_growfs /

df -h /                        # 确认已生效

说明:分区表变化后可能需要检查 /etc/fstabresize2fs 可在线扩展已挂载的 ext4;缩小则必须先卸载。