1. 为什么需要获取文件大小和MD5值
在日常Linux系统管理和开发工作中,文件大小和MD5值的获取是两项基础但至关重要的操作。作为系统管理员,我经常需要处理以下典型场景:
- 当服务器磁盘空间告急时,快速定位占用空间过大的文件
- 部署应用时需要验证下载的软件包是否完整无损
- 批量处理文件前需要确认文件特征是否符合预期
- 系统巡检时需要核对关键配置文件的完整性
获取文件大小的传统方法是使用ls -l命令,但这个命令的输出格式需要额外处理才能提取纯数字。而MD5校验则更复杂,需要调用专门的哈希计算工具。本文将分享几个经过实战检验的脚本代码,它们能帮你用最简洁的方式完成这些任务。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 获取文件大小的四种实用方法
2.1 使用stat命令获取精确字节数
stat命令是获取文件元数据的瑞士军刀,它的输出包含文件的所有基础信息。以下是获取文件大小的标准方法:
bash复制file_size=$(stat -c %s "/path/to/file")
echo "File size: $file_size bytes"
参数说明:
-c:指定输出格式%s:表示只输出文件大小(字节数)
实际案例:
bash复制$ stat -c %s /var/log/syslog
142857
注意:不同Linux发行版的stat命令参数可能略有差异。在BSD系统(如MacOS)上需要使用
-f %z替代-c %s。
2.2 通过wc命令计算字节数
对于文本文件,wc -c是另一种可靠的选择:
bash复制size=$(wc -c < filename)
echo $size
这种方法的特点是会读取文件内容,因此对于大文件会比较耗时。建议只在处理文本文件时使用。
2.3 使用du命令获取磁盘占用空间
当需要获取文件实际占用的磁盘空间时(考虑文件系统块大小),du命令更合适:
bash复制real_size=$(du -b file | cut -f1)
参数说明:
-b:以字节为单位显示cut -f1:只提取第一列的数字
2.4 纯Bash实现(不依赖外部命令)
在受限环境中,可以使用纯Bash实现:
bash复制get_file_size() {
[ -e "$1" ] || { echo "File not found"; return 1; }
local size=$((
$(LC_ALL=C ls -dn -- "$1" | awk '{print $5}') +0
))
echo $size
}
这个方法通过解析ls -dn的输出获取第五列(大小列),适合在嵌入式等精简环境中使用。
3. 计算文件MD5值的三种方案
3.1 使用md5sum命令(最标准方法)
Linux系统通常自带md5sum工具:
bash复制md5_value=$(md5sum /path/to/file | awk '{print $1}')
echo "MD5: $md5_value"
典型输出:
code复制d41d8cd98f00b204e9800998ecf8427e
重要提示:计算大文件MD5时会占用大量CPU资源,建议在系统空闲时执行。
3.2 使用openssl工具(跨平台方案)
当系统没有md5sum时,openssl是很好的替代:
bash复制openssl md5 /path/to/file | awk '{print $NF}'
这个方法的优势是openssl通常预装在大多数服务器上,且命令格式在不同操作系统上保持一致。
3.3 纯Python实现(适合批量处理)
对于需要集成到Python脚本中的场景:
python复制import hashlib
def get_md5(filepath):
hash_md5 = hashlib.md5()
with open(filepath, "rb") as f:
for chunk in iter(lambda: f.read(4096), b""):
hash_md5.update(chunk)
return hash_md5.hexdigest()
print(get_md5("/path/to/file"))
这段代码采用分块读取方式,即使处理大文件也不会耗尽内存。4096字节的块大小是经过测试的较优值。
4. 实战案例:监控目录文件变化
结合文件大小和MD5检查,我们可以实现一个简单的目录监控脚本:
bash复制#!/bin/bash
# 用法:./monitor.sh /path/to/directory
target_dir=$1
snapshot_file="/tmp/dir_snapshot_$(basename $target_dir).txt"
take_snapshot() {
find "$1" -type f -exec stat -c '%n %s' {} \; \
-exec md5sum {} \; | awk '{print $1,$2,$3}'
}
compare_snapshots() {
diff <(sort "$1") <(sort "$2")
}
if [ -f "$snapshot_file" ]; then
echo "[$(date)] Detected changes in $target_dir:"
compare_snapshots "$snapshot_file" <(take_snapshot "$target_dir")
else
echo "Creating initial snapshot..."
fi
take_snapshot "$target_dir" > "$snapshot_file"
这个脚本会:
- 记录目录下所有文件的大小和MD5值
- 下次运行时对比变化
- 输出发生变更的文件列表
5. 性能优化与注意事项
5.1 处理大文件的技巧
当处理GB级别的大文件时,需要注意:
- 使用
/dev/shm等内存文件系统存放临时文件 - 避免频繁I/O操作,尽量使用管道传递数据
- 给命令添加
ionice -c3降低磁盘优先级
5.2 MD5校验的局限性
虽然MD5仍然广泛使用,但需要注意:
- 已知存在碰撞漏洞(不同文件产生相同MD5)
- 对安全性要求高的场景应改用SHA-256
- 校验大文件时耗时较长
替代方案示例:
bash复制sha256sum /path/to/file | awk '{print $1}'
5.3 跨平台兼容性问题
不同系统上的工具行为差异:
- MacOS的
md5命令输出格式与Linux不同 - BSD系统的
stat参数不同 - 旧版BusyBox可能功能受限
解决方案是使用前检查工具是否存在:
bash复制command -v md5sum >/dev/null || alias md5sum="openssl md5"
6. 扩展应用:文件完整性校验系统
基于上述技术,我们可以构建简单的文件完整性监控系统:
python复制#!/usr/bin/env python3
import os
import hashlib
import sqlite3
from pathlib import Path
DB_FILE = "file_checks.db"
def init_db():
conn = sqlite3.connect(DB_FILE)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS file_checks
(path TEXT PRIMARY KEY, size INTEGER, md5 TEXT, mtime REAL)''')
conn.commit()
return conn
def check_files(directory):
conn = init_db()
changes = []
for filepath in Path(directory).rglob('*'):
if filepath.is_file():
stat = filepath.stat()
file_md5 = hashlib.md5(filepath.read_bytes()).hexdigest()
c = conn.cursor()
c.execute('''SELECT size, md5 FROM file_checks
WHERE path=?''', (str(filepath),))
row = c.fetchone()
if row:
if row[0] != stat.st_size or row[1] != file_md5:
changes.append((str(filepath), "modified"))
else:
changes.append((str(filepath), "new"))
c.execute('''REPLACE INTO file_checks
VALUES (?, ?, ?, ?)''',
(str(filepath), stat.st_size, file_md5, stat.st_mtime))
conn.commit()
conn.close()
return changes
这个Python脚本会:
- 建立SQLite数据库记录文件特征
- 扫描目录检测新增/修改的文件
- 返回变更列表供后续处理
我在生产环境中使用类似的脚本来监控/etc目录下的配置文件变更,配合邮件通知功能,可以及时发现潜在的配置篡改。
