Câu chuyện quen thuộc: Server đầy disk vào lúc 2 giờ sáng
Hồi còn quản lý con server CentOS 7 cũ của công ty, mình đã gặp cảnh này nhiều lần hơn muốn nhớ: chuông báo thức lúc 2 giờ sáng, disk /var đã 98%, ứng dụng bắt đầu văng lỗi. Mở terminal ra, dùng df -h xong rồi ngồi lần mò từng thư mục bằng ls -lh. Mất cả tiếng đồng hồ mới tìm được đám file log từ 6 tháng trước chiếm gần 40GB.
Nếu biết dùng find đúng cách từ đầu, cái việc đó chỉ mất 30 giây. Không phải find cơ bản kiểu find /var -name "*.log" — mà là phiên bản đầy đủ: kết hợp nhiều tiêu chí, lọc theo thời gian và kích thước, rồi pipe thẳng sang xargs để xử lý luôn một thể.
Tại sao find cơ bản không giải quyết được?
Mấy năm đầu mình cũng chỉ biết dùng find ở mức này:
find /var/log -name "*.log"
Thực tế vấn đề không đơn giản vậy. Bạn không chỉ cần tìm file .log, mà cần tìm file .log cũ hơn 30 ngày, kích thước trên 100MB, và thuộc về user nginx. Chạy lệnh trên thì ra vài trăm file — cả mới lẫn cũ, cả nhỏ lẫn lớn — rồi lại phải ngồi lọc tay.
Sau khi tìm ra rồi thì làm gì? Copy từng dòng rồi rm? Nếu có 200 file thì sao? find nâng cao giải quyết cả hai — lọc chính xác từ đầu, xử lý ngay trong cùng một lệnh.
Các tùy chọn lọc nâng cao của lệnh find
Lọc theo thời gian
Mỗi lần dọn server là đụng tới nhóm này đầu tiên:
-mtime +N— file được sửa đổi hơn N ngày trước-mtime -N— file được sửa đổi trong vòng N ngày gần đây-atime +N— file không được truy cập trong hơn N ngày-newer file_ref— file mới hơn một file tham chiếu
# Tìm file log cũ hơn 30 ngày
find /var/log -name "*.log" -mtime +30
# Tìm file không được truy cập trong 60 ngày
find /home -atime +60 -type f
Lọc theo kích thước
Đơn vị có thể là c (bytes), k (KB), M (MB), G (GB):
# Tìm file lớn hơn 100MB
find /var -size +100M -type f
# Tìm file nhỏ hơn 1KB (thường là file rác rỗng)
find /tmp -size -1k -type f
Lọc theo quyền và owner
# Tìm file có SUID bit — quan trọng cho bảo mật
find / -perm -4000 -type f 2>/dev/null
# Tìm file thuộc về user nginx
find /var/log -user nginx -type f
# Tìm file có quyền 777 (thường là lỗi config)
find /var/www -perm 777 -type f
Kết hợp nhiều điều kiện cùng lúc
Ít người khai thác phần này — nhưng đây mới là chỗ find trở nên thật sự mạnh. Nó hỗ trợ toán tử logic -and (mặc định), -or, và -not:
# AND ngầm định: file .log VÀ lớn hơn 50MB VÀ cũ hơn 7 ngày
find /var/log -name "*.log" -size +50M -mtime +7
# OR: tìm file .log hoặc .gz
find /var/log \( -name "*.log" -o -name "*.gz" \) -mtime +30
# NOT: tìm file không phải .log
find /var/log -not -name "*.log" -type f
# Kết hợp phức tạp: file .log hoặc .txt, cũ hơn 14 ngày, lớn hơn 10MB
find /data \( -name "*.log" -o -name "*.txt" \) -mtime +14 -size +10M
Xử lý kết quả: -exec so với xargs
Dùng -exec: đơn giản, an toàn với tên file đặc biệt
-exec chạy lệnh cho từng file tìm được. {} là placeholder cho tên file, kết thúc bằng \;:
# Xóa file log cũ hơn 30 ngày
find /var/log -name "*.log" -mtime +30 -exec rm -f {} \;
# Đổi quyền tất cả file PHP về 644
find /var/www -name "*.php" -exec chmod 644 {} \;
# In chi tiết từng file tìm được
find /tmp -size +10M -exec ls -lh {} \;
# Nén file log cũ thay vì xóa
find /var/log -name "*.log" -mtime +7 -exec gzip {} \;
Thay \; bằng + để gom nhiều file vào một lần chạy — nhanh hơn đáng kể vì giảm số lần fork process:
# Gọi rm một lần với nhiều file (hiệu quả hơn)
find /var/log -name "*.log" -mtime +30 -exec rm -f {} +
Dùng xargs: linh hoạt hơn khi cần kiểm soát
Pipe kết quả sang xargs khi cần giới hạn số file xử lý mỗi lần, hoặc chạy nhiều tiến trình song song:
# Pipe kết quả find sang xargs rm
find /var/log -name "*.log" -mtime +30 | xargs rm -f
# An toàn hơn với tên file có dấu cách: dùng -print0 và -0
find /data -name "*.tmp" -print0 | xargs -0 rm -f
# Chạy song song với -P: xử lý 4 file cùng lúc
find /backup -name "*.sql" -print0 | xargs -0 -P 4 gzip
# Giới hạn số file mỗi lần: -n 10
find /logs -name "*.log" -print0 | xargs -0 -n 10 rm -f
Khi nào dùng cái nào?
- Dùng
-exec {} \;khi lệnh cần xử lý từng file riêng lẻ (nhưgzip,mvđến thư mục cụ thể) - Dùng
-exec {} +hoặcxargskhi lệnh nhận nhiều argument cùng lúc (nhưrm,chmod) — ít lần fork hơn, nhanh hơn rõ rệt - Dùng
xargs -0kết hợp-print0khi tên file có thể chứa dấu cách hoặc ký tự đặc biệt — đây là best practice trên production
Pipeline hoàn chỉnh cho tình huống thực tế
Dọn dẹp log server định kỳ
Đây chính xác là script mình viết sau cái đêm thức đến 3 giờ sáng đó. Chạy qua cron mỗi tuần, không bao giờ bị đầy disk vì log nữa:
#!/bin/bash
# Xóa log cũ hơn 30 ngày, lớn hơn 1MB
find /var/log -name "*.log" -mtime +30 -size +1M -print0 | xargs -0 rm -f
# Nén log từ 7-30 ngày (giữ lại nhưng tiết kiệm space)
find /var/log -name "*.log" -mtime +7 -mtime -30 -size +1M -print0 | xargs -0 gzip
# Xóa file .gz cũ hơn 90 ngày
find /var/log -name "*.gz" -mtime +90 -delete
Kiểm tra bảo mật: tìm file nguy hiểm
# Tìm tất cả file có SUID/SGID — chạy sau khi cài gói mới
find / -type f \( -perm -4000 -o -perm -2000 \) 2>/dev/null | sort
# Tìm file world-writable trong web root
find /var/www -perm -o+w -type f
# Tìm file PHP mới tạo trong 24h — detect webshell
find /var/www -name "*.php" -mtime -1 -type f
Batch rename hoặc move file
# Di chuyển file ảnh cũ hơn 1 năm sang thư mục archive
find /uploads -name "*.jpg" -mtime +365 -exec mv {} /archive/images/ \;
# Thay đổi ownership hàng loạt
find /var/www/html -type f -exec chown www-data:www-data {} +
# Tìm và xóa thư mục rỗng
find /data -type d -empty -delete
Pattern nên nhớ khi dùng find trên production
Cấu trúc mình lặp lại nhiều nhất:
find [đường_dẫn] [điều_kiện_lọc] -print0 | xargs -0 [lệnh_xử_lý]
Luôn dùng -print0 | xargs -0 thay vì pipe thường — an toàn hơn với tên file bất thường. Trước khi thực sự xóa hay sửa, thay lệnh cuối bằng ls -lh để xem trước danh sách. Trên production, một lệnh rm nhầm không có cách nào undo.
Những tác vụ bảo trì ngày trước mất cả tiếng đồng hồ — giờ là script 5 dòng chạy cron tự động. find không phức tạp, chỉ cần đúng syntax là xong.

