Hai công cụ này thường đi cùng nhau: find trả lời "những file nào thoả điều kiện?", còn xargs trả lời "làm gì đó với chúng". Nghe đơn giản, nhưng cặp đôi này là nơi ẩn một trong những cái bẫy nguy hiểm nhất của dòng lệnh — ghép chúng ẩu có thể xoá nhầm file. Bài này (phần 5 loạt Unix) chạy thật find và xargs để nắm cả sức mạnh lẫn cạm bẫy: tìm theo nhiều tiêu chí, chạy lệnh trên kết quả, và đặc biệt là cách xử lý tên file có dấu cách một cách an toàn.
find: tìm theo mọi tiêu chí
find duyệt cây thư mục và lọc theo điều kiện: tên, loại, kích thước, thời gian sửa, quyền... Vài dạng hay dùng:
find proj -name "*.go" # theo tên (dùng glob)
find proj -type d # chỉ thư mục (type f = file thường)
find proj -size +1k # lớn hơn 1KB (-1k = nhỏ hơn)
find proj -mtime -7 # sửa trong 7 ngày qua
find proj -name "*.go" -exec wc -l {} \; # chạy lệnh trên MỖI kết quả
-exec ... {} \; chạy một lệnh cho từng file tìm được ({} là chỗ điền tên file). Đây là cách find tự "làm gì đó" mà không cần xargs, nhưng chạy một tiến trình mỗi file nên chậm khi có nhiều file.
xargs: biến stdin thành đối số
Đây là chỗ nhiều người mới bối rối: vì sao ls | rm không xoá gì? Vì rm đọc tên file từ đối số dòng lệnh, không phải từ stdin. Pipe chỉ đưa dữ liệu vào stdin. xargs là cầu nối: nó đọc stdin và biến thành đối số cho lệnh:
find . -name "*.tmp" | xargs rm # gom kết quả thành đối số cho rm
find . -name "*.log" | xargs -I{} mv {} /backup/ # {} = từng mục

Hình 1: find lọc theo tên/loại/kích thước/thời gian, -exec chạy lệnh mỗi kết quả; xargs biến stdin thành đối số (vì rm đọc đối số, không đọc stdin); bẫy tên có dấu cách và cờ -P chạy song song.
Đo thật: cái bẫy tên có dấu cách
Đây là phần quan trọng nhất. xargs mặc định tách đầu vào theo khoảng trắng — nên một file tên "thu muc co dau cach/rac.tmp" bị vỡ thành nhiều đối số riêng. Đo thật cho thấy rõ:

Hình 2: Chạy thật — find | xargs vỡ tên "thu muc co dau cach/rac.tmp" thành 5 đối số (proj/thu, muc, co, dau, cach/rac.tmp); -print0 | xargs -0 giữ nguyên tên; xargs -P6 chạy 6 việc trong 0,51s so với 3,05s tuần tự.
- Cách sai (
find | xargs): một file duy nhất biến thành 5 đối số rời rạc. Nếu lệnh làrm, nó sẽ cố xoáproj/thu,muc,co... — vừa báo lỗi vừa có nguy cơ xoá nhầm những thứ khớp các mảnh đó. Đây là lỗi kinh điển gây mất dữ liệu. - Cách đúng (
-print0 | xargs -0):find -print0ngăn cách các tên bằng ký tự NUL (\0) thay vì xuống dòng/khoảng trắng, vàxargs -0đọc theo NUL. Vì NUL không bao giờ xuất hiện trong tên file, mỗi tên — kể cả có dấu cách — được giữ nguyên vẹn thành đúng một đối số.
Quy tắc vàng: luôn dùng find ... -print0 | xargs -0 khi tên file có thể chứa dấu cách hay ký tự lạ. Hoặc dùng find ... -exec ... {} + (biến thể + gom nhiều file vào một lệnh, an toàn với dấu cách).
xargs -P: chạy song song
Một sức mạnh ít dùng: -P N chạy N tiến trình song song. Đo thật với 6 việc, mỗi việc sleep 0.5s:
-P1(tuần tự): 3,05 giây — 6 việc nối đuôi nhau.-P6(song song): 0,51 giây — cả 6 chạy cùng lúc, nhanh gần 6 lần.
Với các tác vụ độc lập tốn thời gian (resize ảnh, nén file, tải nhiều URL), xargs -P là cách đơn giản nhất để dùng hết nhiều lõi CPU mà không cần viết code song song.
Đánh đổi cần cân nhắc
-exec {} \; vs -exec {} + vs xargs. -exec ... \; chạy một tiến trình mỗi file (chậm nhưng đơn giản); -exec ... + gom nhiều file vào một lần gọi (nhanh, an toàn dấu cách); xargs linh hoạt nhất (song song, điều khiển batch). Với thao tác đơn giản an toàn, -exec + gọn; cần song song thì xargs -P.
Song song không phải lúc nào cũng nhanh hơn. -P chỉ lợi khi tác vụ độc lập và bị chặn bởi CPU/mạng, không phải bởi đĩa. Với tác vụ nặng I/O trên một ổ đĩa, chạy nhiều tiến trình cùng lúc có thể chậm hơn do tranh đĩa. Và đừng đặt -P quá cao — quá số lõi thường không thêm lợi mà tốn bộ nhớ.
Kiểm trước khi xoá. Với lệnh phá huỷ (rm, mv đè), luôn chạy find ... -print0 | xargs -0 echo (hoặc ls) trước để xem danh sách sẽ bị tác động, rồi mới đổi echo thành rm. Một mẫu find sai kết hợp xargs rm có thể quét sạch nhầm thư mục trong tích tắc — không có thùng rác ở dòng lệnh.
Ba ý mang về
- find lọc, xargs biến kết quả thành đối số:
findtìm theo tên/loại/kích thước/thời gian (-execchạy lệnh mỗi kết quả);xargscần thiết vì nhiều lệnh (rm) đọc đối số chứ không đọc stdin — nênls | rmkhông chạy. - Luôn
-print0 | xargs -0với tên có dấu cách: đo thật,find | xargsvỡ một tên có dấu cách thành 5 đối số (nguy cơ xoá nhầm), còn-print0/-0ngăn bằng NUL giữ tên nguyên vẹn. Hoặc dùng-exec {} +. xargs -Pchạy song song gần như miễn phí: đo thật 6 việc chạy-P6trong 0,51s so với 3,05s tuần tự (~6×) — hợp cho tác vụ độc lập; nhưng luôn thử bằngechotrước khi ghép với lệnh phá huỷ.
Nguồn
- man7.org — find(1): https://man7.org/linux/man-pages/man1/find.1.html
- man7.org — xargs(1): https://man7.org/linux/man-pages/man1/xargs.1.html
- GNU findutils manual: https://www.gnu.org/software/findutils/manual/html_mono/find.html
Phần sau ta xem bộ ba xử lý văn bản theo dòng: sort, uniq, cut — vì sao uniq chỉ gộp dòng trùng liền kề (nên gần như luôn phải sort trước), và cách đếm tần suất bằng sort | uniq -c.