0Pricing
Linux Command Line & Bash Scripting Mastery · 课时

磁盘、文件系统与挂载自动化

检查块设备、管理 fstab 条目,并安全地编写 LVM 和挂载操作脚本。

磁盘、文件系统与挂载自动化 是 CoddyKit 上的免费 Linux Command Line & Bash Scripting Mastery 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Linux Command Line & Bash Scripting Mastery 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Linux Command Line & Bash Scripting Mastery 课程共包含 4 节课。

使用 lsblk 和 fdisk 理解块设备

在自动化磁盘操作之前,您必须能够检查系统中有哪些块设备。lsblk 和 fdisk -l 是两个必备工具。

  • lsblk — 以树状格式列出块设备,显示设备名称、大小、挂载点和类型(disk、part、lvm)
  • fdisk -l — 显示分区表和扇区详细信息(需要 root 权限)
  • blkid — 输出每个块设备的 UUID 和文件系统类型

在脚本中,您经常需要解析这些输出,以检测可用磁盘、检查分区是否已格式化,或在挂载前确定其 UUID。

#!/usr/bin/env bash
# Inspect all block devices and their UUIDs
set -euo pipefail

echo '=== Block Device Tree ==='
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,UUID

echo ''
echo '=== Partition Table Details ==='
sudo fdisk -l 2>/dev/null | grep -E '^Disk |^/dev/'

echo ''
echo '=== UUID Lookup via blkid ==='
sudo blkid | awk -F: '{print $1}' | while read -r dev; do
  uuid=$(sudo blkid -s UUID -o value "$dev" 2>/dev/null || echo 'N/A')
  fstype=$(sudo blkid -s TYPE -o value "$dev" 2>/dev/null || echo 'unknown')
  printf '%-20s UUID=%-38s TYPE=%s\n' "$dev" "$uuid" "$fstype"
done

使用 df 和 du 检查磁盘空间

df 和 du 是报告文件系统和目录使用情况的主要工具。在系统管理脚本中,您可以使用它们触发警报、强制执行配额,或决定何时分配更多空间。

  • df -h — 以人类易读的格式显示所有已挂载文件系统的使用情况
  • df -BG — 以 GB 为单位输出,便于进行一致的数值解析
  • du -sh /path — 汇总显示指定目录的大小
  • du -d 1 /var — 显示一层深度的详细使用情况(有助于找出占用空间较大的子目录)

df 输出中的已使用百分比列通常会被解析,以便在监控脚本中触发磁盘空间耗尽警报。

#!/usr/bin/env bash
# Alert if any mounted filesystem exceeds a usage threshold
set -euo pipefail

THRESHOLD=80   # percent

echo 'Checking filesystem usage...'
df -h --output=source,pcent,target | tail -n +2 | while IFS= read -r line; do
  device=$(awk '{print $1}' <<< "$line")
  pct=$(awk '{print $2}' <<< "$line" | tr -d '%')
  mount=$(awk '{print $3}' <<< "$line")

  # Skip pseudo filesystems
  [[ "$device" == tmpfs* || "$device" == devtmpfs* ]] && continue

  if (( pct >= THRESHOLD )); then
    echo "WARNING: $device mounted at $mount is ${pct}% full" >&2
  else
    echo "OK: $device at $mount is ${pct}% used"
  fi
done

读取并解析 /etc/fstab

/etc/fstab 是静态文件系统表,用于定义哪些设备会在启动时挂载、挂载到什么路径以及使用哪些选项。每行包含六个字段:

  • 设备 — UUID=...、LABEL=... 或 /dev/sdX
  • 挂载点 — 目录路径
  • 文件系统类型 — ext4、xfs、nfs、tmpfs 等
  • 选项 — defaults、ro、noexec、nofail 等
  • Dump — 0 或 1(备份标志)
  • Pass — 0、1 或 2(fsck 顺序)

用于添加或验证 fstab 条目的脚本必须妥善处理注释(以 # 开头的行)和空行。请始终优先使用 UUID 而不是设备名称,以应对重启后设备顺序可能发生变化的情况。

#!/usr/bin/env bash
# Parse /etc/fstab and display non-comment entries in a readable table
set -euo pipefail

FSTAB=/etc/fstab

printf '%-40s %-20s %-10s %s\n' 'DEVICE' 'MOUNTPOINT' 'FSTYPE' 'OPTIONS'
printf '%s\n' '-------------------------------------------------------------------------------------'

while IFS= read -r line; do
  # Skip blank lines and comments
  [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue

  read -r device mountpt fstype options _dump _pass <<< "$line"
  printf '%-40s %-20s %-10s %s\n' "$device" "$mountpt" "$fstype" "$options"
done < "$FSTAB"

安全地添加 fstab 条目

手动编辑 /etc/fstab 容易出错。错误的条目可能会导致系统无法启动。安全的自动化脚本应当做到:

  • 追加之前检查条目是否已经存在(幂等性)
  • 进行任何修改之前备份原始文件
  • 使用 UUID,而不是设备路径
  • 将 nofail 添加到挂载选项中,这样磁盘缺失时不会阻止系统启动
  • 以试运行方式运行 mount -a,或执行测试挂载,在重启前进行验证

写入条目后,始终使用 findmnt --verify 进行验证(现代 systemd 发行版通常提供此命令),以便立即发现语法错误。

#!/usr/bin/env bash
# Safely append a new entry to /etc/fstab (idempotent)
set -euo pipefail

DEVICE_PATH='/dev/sdb1'
MOUNTPOINT='/mnt/data'
FSTYPE='ext4'
OPTIONS='defaults,nofail'
FSTAB='/etc/fstab'

# Resolve UUID for stable identification
UUID=$(sudo blkid -s UUID -o value "$DEVICE_PATH")
if [[ -z "$UUID" ]]; then
  echo "ERROR: Could not resolve UUID for $DEVICE_PATH" >&2
  exit 1
fi

ENTRY="UUID=$UUID  $MOUNTPOINT  $FSTYPE  $OPTIONS  0  2"

# Idempotency: skip if UUID already referenced in fstab
if grep -qsF "UUID=$UUID" "$FSTAB"; then
  echo "INFO: fstab already contains UUID=$UUID — skipping."
  exit 0
fi

# Backup
cp -p "$FSTAB" "${FSTAB}.bak.$(date +%Y%m%d%H%M%S)"

# Create mountpoint if needed
sudo mkdir -p "$MOUNTPOINT"

# Append entry
echo "$ENTRY" | sudo tee -a "$FSTAB" > /dev/null
echo "INFO: Added: $ENTRY"

# Validate
sudo findmnt --verify --verbose || echo 'WARNING: findmnt verify reported issues'

在脚本中挂载和卸载文件系统

mount 和 umount 命令本身很直接,但脚本必须处理边界情况:

  • 设备可能已经挂载——再次挂载会失败;请使用 findmnt 或 mountpoint 检查
  • 挂载点可能处于忙碌状态(存在打开的文件)——umount 会失败;请使用 lsof +D /mnt/target 查找相关进程
  • 使用 mount -o remount,ro /mnt/data 可以在不卸载的情况下切换为只读模式
  • 最后再使用 umount -l /mnt/data(延迟卸载)——它会解除命名空间的连接,但会等待引用关闭

在自动化操作中,始终检查 mount 的退出代码,并使用 logger 将失败记录到 syslog。

#!/usr/bin/env bash
# Mount a device only if not already mounted; log outcome
set -euo pipefail

DEVICE='/dev/sdb1'
MOUNTPOINT='/mnt/data'

log() { logger -t disk-mount "$*"; echo "[$(date '+%F %T')] $*"; }

# Check if already mounted
if mountpoint -q "$MOUNTPOINT"; then
  log "INFO: $MOUNTPOINT is already mounted — nothing to do."
  exit 0
fi

# Ensure mountpoint directory exists
sudo mkdir -p "$MOUNTPOINT"

# Attempt mount
if sudo mount "$DEVICE" "$MOUNTPOINT"; then
  log "OK: Mounted $DEVICE at $MOUNTPOINT"
else
  log "ERROR: Failed to mount $DEVICE at $MOUNTPOINT"
  exit 1
fi

# Show what is now mounted there
df -h "$MOUNTPOINT"

LVM 简介:物理卷、卷组和逻辑卷

LVM(逻辑卷管理器)在原始块设备与文件系统之间增加了一个灵活的抽象层。其三级层次结构如下:

  • 物理卷(PV)——使用 pvcreate 初始化的原始磁盘或分区
  • 卷组(VG)——使用 vgcreate 将一个或多个 PV 汇集到一起
  • 逻辑卷(LV)——使用 lvcreate 从 VG 中划分出的虚拟分区;您可以对它进行格式化和挂载

其主要优势在于:您可以在在线状态下扩展 LV,无需卸载;还可以向 VG 添加新磁盘,而无需重新格式化。这使 LVM 成为生产环境存储自动化不可或缺的工具。

检查命令包括:pvs、vgs、lvs,以及对应的详细显示命令 pvdisplay、vgdisplay 和 lvdisplay。

编写 LVM 卷创建脚本

自动化设置 LVM 必须遵循严格的顺序:pvcreate → vgcreate → lvcreate → mkfs → mount。每一步都必须成功后才能执行下一步——请使用 set -euo pipefail,并验证每个命令的输出。

  • 调用 pvcreate 前,始终检查目标磁盘上没有现有的分区表
  • 在非交互式脚本中使用 -y 标志,以禁止交互式提示
  • 指定 -L(固定大小),或指定 -l 100%FREE 以使用所有剩余空间
  • 执行 mkfs 后,使用 LV 的设备路径:/dev/<vgname>/<lvname>
#!/usr/bin/env bash
# Automate LVM setup: PV -> VG -> LV -> mkfs -> mount
set -euo pipefail

DISK='/dev/sdc'          # raw disk, no existing partitions
VG_NAME='vg_appdata'
LV_NAME='lv_appdata'
LV_SIZE='10G'
MOUNTPOINT='/mnt/appdata'
FSTYPE='xfs'

echo "[1/6] Initializing Physical Volume on $DISK"
sudo pvcreate -y "$DISK"

echo "[2/6] Creating Volume Group: $VG_NAME"
sudo vgcreate "$VG_NAME" "$DISK"

echo "[3/6] Creating Logical Volume: $LV_NAME (${LV_SIZE})"
sudo lvcreate -y -L "$LV_SIZE" -n "$LV_NAME" "$VG_NAME"

echo "[4/6] Formatting as $FSTYPE"
sudo mkfs."$FSTYPE" "/dev/$VG_NAME/$LV_NAME"

echo "[5/6] Mounting at $MOUNTPOINT"
sudo mkdir -p "$MOUNTPOINT"
sudo mount "/dev/$VG_NAME/$LV_NAME" "$MOUNTPOINT"

echo "[6/6] Done. Disk usage:"
df -h "$MOUNTPOINT"

# Show LVM summary
vgs && lvs

在线扩展逻辑卷

LVM 最强大的功能之一是在线调整大小——可以在逻辑卷已挂载且正在使用时,同时扩展逻辑卷及其文件系统。操作流程如下:

  1. 使用 lvextend 扩展 LV(-r 标志会在同一步骤中调整文件系统大小)
  2. 如果不使用 -r,请单独调整文件系统大小:ext4 使用 resize2fs,xfs 使用 xfs_growfs

重要限制:

  • xfs 只能扩展,不能缩小——请仔细规划容量
  • ext4 可以缩小,但只能在未挂载时进行
  • 扩展之前,始终使用 vgdisplay -s 验证 VG 中有可用空间
#!/usr/bin/env bash
# Extend an LV and its xfs filesystem online
set -euo pipefail

VG_NAME='vg_appdata'
LV_NAME='lv_appdata'
EXTEND_BY='5G'
LV_DEV="/dev/$VG_NAME/$LV_NAME"

# Confirm VG has enough free space
FREE_GB=$(vgs --noheadings --units g -o vg_free "$VG_NAME" | tr -d ' g')
echo "VG free space: ${FREE_GB}G"
if (( $(echo "$FREE_GB < 5" | bc -l) )); then
  echo 'ERROR: Not enough free space in VG' >&2
  exit 1
fi

echo "Extending LV by $EXTEND_BY..."
sudo lvextend -L "+${EXTEND_BY}" "$LV_DEV"

echo 'Growing xfs filesystem online...'
sudo xfs_growfs "$LV_DEV"

echo 'New size:'
df -h "$LV_DEV"
lvs "$LV_DEV"

创建和格式化文件系统

完成分区或 LVM 设置后,您需要使用文件系统格式化块设备。Linux 管理中常见的选择包括:

  • ext4——成熟、支持日志记录,并支持缩小;许多发行版的默认选择(mkfs.ext4)
  • xfs——性能高,适合大文件和并行 I/O;RHEL/CentOS 的默认选择(mkfs.xfs)
  • btrfs——写时复制,内置快照功能(mkfs.btrfs)
  • tmpfs——由 RAM 支持,在 fstab 中指定,无需使用 mkfs

始终设置有意义的文件系统标签(-L 标志),这样设备就可以在 fstab 中通过 LABEL= 引用,作为 UUID 的备用方式。

#!/usr/bin/env bash
# Format a partition and assign a label; print resulting UUID
set -euo pipefail

PARTITION='/dev/sdb1'
FSTYPE='ext4'
LABEL='appdata'

# Safety check: refuse to format a currently mounted device
if findmnt --source "$PARTITION" > /dev/null 2>&1; then
  echo "ERROR: $PARTITION is currently mounted. Unmount first." >&2
  exit 1
fi

echo "Formatting $PARTITION as $FSTYPE with label '$LABEL'..."
sudo mkfs."$FSTYPE" -L "$LABEL" -F "$PARTITION"

# Retrieve and display the new UUID
NEW_UUID=$(sudo blkid -s UUID -o value "$PARTITION")
echo "Formatted successfully."
echo "Label : $LABEL"
echo "UUID  : $NEW_UUID"
echo "Use this in fstab: UUID=$NEW_UUID  /mnt/$LABEL  $FSTYPE  defaults,nofail  0  2"

使用 autofs 自动挂载 NFS

对于网络文件系统,使用 fstab 在启动时挂载可能会导致延迟或失败,尤其是在 NFS 服务器暂时无法访问时。autofs 通过按需挂载并在超时后卸载来解决这一问题。

  • 主映射文件:/etc/auto.master——定义挂载点目录及其映射文件
  • 直接映射文件:/etc/auto.nfs——为每个子目录指定选项和 NFS 服务器路径
  • 修改后使用 systemctl reload autofs 重新加载
  • 访问挂载点时,挂载内容会自动出现在配置的目录下

在脚本中,您可以根据 NFS 共享列表动态生成映射文件,然后重新加载 autofs,这对于在多台主机上配置共享存储非常有用。

#!/usr/bin/env bash
# Generate an autofs NFS map file from a share list and reload autofs
set -euo pipefail

NFS_SERVER='192.168.1.50'
AUTO_MAP='/etc/auto.nfs'
AUTO_MASTER='/etc/auto.master'
MOUNT_BASE='/nfs'

# Define shares: localname:remote_path
declare -A SHARES=(
  [homes]='/export/homes'
  [media]='/export/media'
  [backups]='/export/backups'
)

# Write map file
{
  echo '# Generated by disk-automation script'
  for localname in "${!SHARES[@]}"; do
    remote="${SHARES[$localname]}"
    echo "$localname  -rw,soft,timeo=30  ${NFS_SERVER}:${remote}"
  done
} | sudo tee "$AUTO_MAP" > /dev/null

echo "Wrote $AUTO_MAP"

# Ensure master map references this file
if ! grep -qF "$AUTO_MAP" "$AUTO_MASTER"; then
  echo "$MOUNT_BASE  $AUTO_MAP" | sudo tee -a "$AUTO_MASTER" > /dev/null
  echo "Updated $AUTO_MASTER"
fi

sudo systemctl reload autofs && echo 'autofs reloaded'

使用 LVM 快照进行安全备份

LVM快照提供逻辑卷在某一时刻的副本,因此可以在不卸载实时文件系统的情况下进行一致性备份。快照使用写时复制技术捕获创建时的状态。

  • 创建:lvcreate -s -n lv_snap -L 2G /dev/vg_data/lv_data
  • 以只读方式挂载快照进行备份:mount -o ro /dev/vg_data/lv_snap /mnt/snap
  • 针对快照挂载点运行 rsync 或 tar
  • 备份后删除快照:umount /mnt/snap && lvremove -f /dev/vg_data/lv_snap

将快照大小保持在源 LV 的 10% 到 20%。如果快照空间用尽,快照就会失效——请使用 lvs -o lv_name,snap_percent 进行监控。

#!/usr/bin/env bash
# Create an LVM snapshot, back up via tar, then remove snapshot
set -euo pipefail

VG='vg_appdata'
ORIGIN_LV='lv_appdata'
SNAP_LV='lv_appdata_snap'
SNAP_SIZE='2G'
SNAP_MOUNT='/mnt/snap_backup'
BACKUP_DEST='/var/backups/appdata'
DATESTAMP=$(date +%Y%m%d_%H%M%S)

trap 'sudo umount "$SNAP_MOUNT" 2>/dev/null; sudo lvremove -f "/dev/$VG/$SNAP_LV" 2>/dev/null' ERR EXIT

echo '[1] Creating snapshot...'
sudo lvcreate -s -n "$SNAP_LV" -L "$SNAP_SIZE" "/dev/$VG/$ORIGIN_LV"

echo '[2] Mounting snapshot read-only...'
sudo mkdir -p "$SNAP_MOUNT"
sudo mount -o ro "/dev/$VG/$SNAP_LV" "$SNAP_MOUNT"

echo '[3] Archiving to backup destination...'
sudo mkdir -p "$BACKUP_DEST"
sudo tar -czf "$BACKUP_DEST/appdata_${DATESTAMP}.tar.gz" -C "$SNAP_MOUNT" .

echo '[4] Cleaning up snapshot...'
sudo umount "$SNAP_MOUNT"
sudo lvremove -f "/dev/$VG/$SNAP_LV"

echo "Backup complete: $BACKUP_DEST/appdata_${DATESTAMP}.tar.gz"

知识检查:安全的 fstab 和挂载自动化

测试您对本课所介绍的安全磁盘、文件系统和挂载自动化实践的理解。

课程回顾:磁盘、文件系统和挂载自动化

在本课中,您为 Linux 系统上的安全、可编写脚本的磁盘和存储管理构建了一套完整工具。重点如下:

  • 先检查:lsblk、blkid、df 和 du 会提供进行任何更改前所需的信息。
  • 遵循 fstab 规范:始终使用 UUID,始终包含 nofail,编辑前始终备份,并使用 findmnt --verify 验证。
  • 安全挂载:挂载前检查 mountpoint -q,使用 logger 记录,并使用 lsof 处理设备忙碌错误。
  • LVM 的优势:PV → VG → LV 这一处理流程支持在线扩展和基于快照的备份,无需停机。
  • 文件系统选择很重要:xfs 适合高性能场景(只能扩展),ext4 灵活(可在离线时缩小),btrfs 适合原生支持快照的工作负载。
  • 按需使用 NFS:autofs 只在访问网络共享时挂载,从而避免启动延迟。
  • 快照备份:LVM 快照提供一致的实时备份,但请始终监控 snap_percent,并在备份后及时删除快照。

结合这些模式,您就可以可靠地自动化整个存储生命周期:发现、配置、挂载、调整大小和备份。

常见问题解答

「磁盘、文件系统与挂载自动化」课时是免费的吗?

是的 — 「磁盘、文件系统与挂载自动化」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Linux Command Line & Bash Scripting Mastery 课程的其余内容,请升级到 CoddyKit PRO。 Linux Command Line & Bash Scripting Mastery 课程共包含 4 节课。

「磁盘、文件系统与挂载自动化」这节课中我会学到什么?

检查块设备、管理 fstab 条目,并安全地编写 LVM 和挂载操作脚本。 你通过在浏览器中直接运行的动手代码来练习 Linux Command Line & Bash Scripting Mastery,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Linux Command Line & Bash Scripting Mastery 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Linux Command Line & Bash Scripting Mastery 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「磁盘、文件系统与挂载自动化」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Linux Command Line & Bash Scripting Mastery 课中编写并运行代码吗?

能。每节 Linux Command Line & Bash Scripting Mastery 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 自动化用户与用户组配置
  2. 控制 systemd 服务并编写单元文件
  3. 磁盘、文件系统与挂载自动化
  4. 构建系统健康检查与告警脚本
← 返回 Linux Command Line & Bash Scripting Mastery