Linux cho DE 2 — Điều hướng & thao tác file
Vì sao DE phải thành thạo thao tác file trên terminal
Là data engineer, phần lớn thời gian bạn không "click chuột" mà gõ lệnh trên một server không có giao diện đồ hoạ: SSH vào edge node của cụm Spark, vào máy chứa Airflow worker, vào bastion host để kéo dataset về. Ở đó chỉ có shell. Một pipeline điển hình sinh ra hàng nghìn file: part-00000.parquet, application_2026-06-*.log, export_20260630.csv.gz. Bạn cần đếm dòng, kiểm tra dung lượng, tìm file cũ để dọn, nén dataset trước khi chuyển qua mạng. Toàn bộ đều làm bằng vài lệnh cơ bản — làm nhanh hay chậm quyết định bởi bạn nắm chắc chúng đến đâu.
Bài này đi từ điều hướng đến thao tác, tìm kiếm, kiểm tra và nén — kèm ví dụ với thư mục dữ liệu thật. Nếu bạn chưa đọc phần tổng quan, xem Linux cho DE 1.
Điều hướng: bạn đang ở đâu, có gì quanh đây
Ba lệnh nền tảng: pwd (in thư mục hiện tại — print working directory), cd (đổi thư mục — change directory), ls (liệt kê — list).
pwd
# /data/warehouse/raw/transactions
cd /data/warehouse/raw/transactions/2026/06
ls
ls trần trụi chỉ cho tên file. Sức mạnh nằm ở các flag, và chúng gộp được với nhau:
| Flag | Ý nghĩa | Dùng khi |
|---|---|---|
-l | dạng dài: quyền, chủ sở hữu, kích thước, thời gian | xem chi tiết |
-a | hiện cả file ẩn (bắt đầu bằng .) | tìm .env, .gitignore |
-h | kích thước dễ đọc (K/M/G) — đi kèm -l | xem file to nhỏ |
-t | sắp theo thời gian sửa, mới nhất trên | tìm file vừa sinh |
-r | đảo thứ tự | mới nhất xuống cuối |
-R | đệ quy, vào cả thư mục con | soi cả cây |
-S | sắp theo kích thước | tìm file nặng nhất |
# File parquet mới nhất nằm trên cùng, kích thước dễ đọc
ls -lht
# Toàn bộ, kể cả file ẩn, sắp theo kích thước giảm dần
ls -lahS
# 5 file mới nhất trong thư mục output của một job
ls -lt /data/spark/output | head -6
Đọc một dòng ls -l:
-rw-r--r-- 1 airflow airflow 2.3G Jun 30 02:14 transactions.parquet
Ký tự đầu - là file thường (nếu là d thì là thư mục, l là symlink). Tiếp theo là quyền, số link, chủ sở hữu (airflow), nhóm, kích thước (2.3G nhờ -h), thời gian sửa, tên. Chi tiết về cột quyền sẽ nói ở bài quyền & user.
Đường dẫn: tuyệt đối và tương đối
Đường dẫn tuyệt đối bắt đầu bằng / (thư mục gốc), luôn trỏ đúng một chỗ bất kể bạn đang đứng đâu: /data/warehouse/raw/transactions. Đường dẫn tương đối tính từ thư mục hiện tại, không bắt đầu bằng /.
Bốn ký hiệu tắt phải thuộc lòng:
| Ký hiệu | Nghĩa |
|---|---|
. | thư mục hiện tại |
.. | thư mục cha (lùi một cấp) |
~ | home của bạn (/home/airflow) |
- | thư mục trước đó (cd - để nhảy qua lại) |
cd /data/warehouse/raw/transactions/2026/06
cd .. # lên /data/warehouse/raw/transactions/2026
cd ../../curated # lùi 2 cấp rồi vào curated → /data/warehouse/raw/curated
cd ~/scripts # về ~/scripts bất kể đang ở đâu
cd - # nhảy lại thư mục ngay trước đó
Mẹo: cd không tham số sẽ về thẳng home. Dùng cd - để "toggle" giữa hai thư mục khi bạn vừa copy file bên A vừa kiểm tra bên B.
Cây thư mục dữ liệu điển hình và các đường đi:
Nếu đang ở 06, đi sang curated bằng tương đối: cd ../../../../curated/daily_balance — nhưng nói thật, đường tuyệt đối cd /data/warehouse/curated/daily_balance dễ đọc hơn nhiều. Quy tắc thực chiến: trong script dùng đường tuyệt đối cho chắc chắn; gõ tay thì tương đối cho nhanh.
Thao tác file: tạo, sao chép, di chuyển, xoá
mkdir staging # tạo 1 thư mục
mkdir -p data/2026/06/day30 # -p: tạo cả chuỗi cha, không báo lỗi nếu đã có
touch manifest.txt # tạo file rỗng, hoặc cập nhật timestamp file có sẵn
cp report.csv report_bak.csv # sao chép 1 file
cp -r raw/ raw_backup/ # -r: sao chép đệ quy cả thư mục
cp -a raw/ raw_backup/ # -a: giữ nguyên quyền, thời gian, symlink (archive)
mv old_name.csv new_name.csv # đổi tên (mv = move)
mv *.parquet /data/curated/ # di chuyển nhiều file
mkdir -p cực hữu ích trong script: tạo đường dẫn phân vùng theo ngày mà không cần kiểm tra thư mục cha đã tồn tại chưa. touch ngoài việc tạo file rỗng còn dùng để tạo file cờ (marker) như _SUCCESS — chuẩn Spark/Hadoop báo job xong.
rm -rf — lệnh nguy hiểm nhất bạn sẽ gõ
rm file.csv # xoá 1 file
rm -r old_dir/ # xoá thư mục và mọi thứ bên trong
rm -f locked.tmp # ép xoá, không hỏi
rm -rf /data/tmp/* # xoá tất cả trong /data/tmp
Trên Linux không có thùng rác — rm xoá vĩnh viễn, không undo. rm -rf (recursive + force) là công cụ quét sạch, và cũng là công cụ xoá sạch sự nghiệp nếu gõ sai. Các nguyên tắc sống còn:
- Không bao giờ để dấu cách lạc giữa đường dẫn.
rm -rf /data /tmp(thừa dấu cách) sẽ xoá cả/data. - Cảnh giác biến rỗng:
rm -rf "$DIR/"*— nếu$DIRchưa được set, lệnh biến thànhrm -rf /*. Trong script luônset -uđể lỗi ngay khi biến chưa định nghĩa. - Xem trước bằng
ls: gõls /data/tmp/*xác nhận đúng danh sách rồi mới đổilsthànhrm. - Trên production, cân nhắc
-i(hỏi từng file) hoặc chuyển file vào thư mục.trash/rồi cron dọn sau, thay vì xoá thẳng.
Wildcard & globbing: nói với shell "tất cả các file kiểu này"
Shell tự động khai triển các ký tự đặc biệt thành danh sách tên file trước khi chạy lệnh. Đây là globbing, khác regex.
| Mẫu | Khớp | Ví dụ |
|---|---|---|
* | 0 hoặc nhiều ký tự bất kỳ | *.parquet → mọi file parquet |
? | đúng 1 ký tự | log_?.txt → log_1.txt, log_a.txt |
[...] | 1 ký tự trong tập | data_[0-9].csv |
[!...] | 1 ký tự KHÔNG trong tập | [!_]* → tên không bắt đầu bằng _ |
{a,b} | luân phiên (brace expansion) | part-{00,01,02}.parquet |
ls *.csv # mọi file CSV trong thư mục hiện tại
ls part-000[0-9][0-9].parquet # part-00000 đến part-00099
cp export_{2026,2025}.csv /bak/ # copy đúng 2 file
rm application_2026-06-*.log # xoá mọi log tháng 6/2026
ls **/**.parquet # (nếu bật globstar) parquet ở mọi cấp con
Lưu ý quan trọng: nếu *.csv không khớp file nào, shell mặc định để nguyên chuỗi *.csv truyền vào lệnh — dễ gây lỗi khó hiểu. Và {...} là brace expansion — sinh chuỗi kể cả khi không có file tương ứng (khác *). Với dữ liệu, hãy nhớ globbing chỉ nhìn tên file, không nhìn nội dung.
Tìm file: find và locate
find là con dao đa năng — duyệt cây thư mục theo điều kiện. Cú pháp: find <nơi bắt đầu> <điều kiện> <hành động>.
Theo tên:
find /data/warehouse -name "*.parquet" # phân biệt hoa thường
find /data/warehouse -iname "*.CSV" # -i: không phân biệt hoa thường
find . -type d -name "day*" # -type d: chỉ thư mục
find . -type f -name "part-*" # -type f: chỉ file
Theo kích thước:
find /data -size +1G # lớn hơn 1 GB
find /data -size +100M -size -1G # từ 100MB đến 1GB
find /tmp -size 0 # file rỗng (0 byte)
Theo thời gian (-mtime theo ngày, -mmin theo phút; +n = cũ hơn, -n = mới hơn):
find /data/logs -name "*.log" -mtime +7 # sửa cách đây hơn 7 ngày
find /data/output -mmin -60 # thay đổi trong 60 phút qua
Kết hợp hành động với -exec ({} là file tìm thấy, \; kết thúc lệnh):
# Đếm dòng từng CSV lớn tìm được
find /data -name "*.csv" -size +10M -exec wc -l {} \;
# Xoá log cũ hơn 30 ngày (dọn ổ đĩa định kỳ)
find /data/logs -name "*.log" -mtime +30 -delete
# Nén mọi CSV cũ để tiết kiệm chỗ
find /archive -name "*.csv" -mtime +90 -exec gzip {} \;
Dùng + thay \; để gom nhiều file vào một lần gọi lệnh (nhanh hơn nhiều với hàng nghìn file): find . -name "*.log" -exec rm {} +.
locate khác find: nó tra một database index (cập nhật bởi updatedb, thường chạy hàng ngày) nên trả kết quả tức thì nhưng có thể lỗi thời:
locate transactions.parquet # nhanh, nhưng file vừa tạo có thể chưa có trong index
sudo updatedb # cập nhật index thủ công
Quy tắc: find khi cần chính xác thời gian thực và điều kiện phức tạp; locate khi chỉ muốn "file này nằm đâu" và cần nhanh.
Kiểm tra file: nó là gì, to bao nhiêu, còn bao nhiêu chỗ
file export.dat # đoán loại file thật (không tin đuôi tên)
# export.dat: gzip compressed data
file đọc magic bytes để nhận diện — rất hữu ích khi nhận file không rõ định dạng (một .txt thực chất là gzip, một .csv thực ra là UTF-16).
stat transactions.parquet
# Size, quyền, thời gian Access/Modify/Change, số inode
Dung lượng — cặp lệnh DE dùng hàng ngày:
du -sh /data/warehouse/raw/transactions # -s tổng, -h dễ đọc → "142G"
du -sh */ # dung lượng từng thư mục con
du -h --max-depth=1 /data | sort -rh # xếp hạng thư mục nặng nhất
df -h # dung lượng còn trống theo phân vùng
df -h /data # riêng phân vùng chứa /data
du (disk usage) đo file/thư mục; df (disk free) đo phân vùng. Khi job Spark chết vì "No space left on device", phản xạ đầu tiên là df -h xem phân vùng nào đầy, rồi du -sh */ | sort -rh truy thư mục nào ngốn chỗ.
Đếm dòng dữ liệu:
wc -l transactions.csv # số dòng (gồm cả header)
wc -l *.csv # từng file + tổng
cat data/*.csv | wc -l # tổng dòng nhiều file
wc -l là cách nhanh nhất kiểm tra số bản ghi một file CSV/TSV. Nhớ trừ 1 dòng header khi so với số record thật. (Không dùng được trực tiếp cho parquet vì đó là định dạng nhị phân — cần công cụ như parquet-tools hay đọc bằng Python/DuckDB.)
Xem đầu/cuối file lớn: head và tail
Với file CSV/log hàng GB, đừng bao giờ cat cả file (treo terminal). Xem một phần:
head transactions.csv # 10 dòng đầu (mặc định)
head -5 transactions.csv # 5 dòng đầu — kiểm tra header + vài record
tail transactions.csv # 10 dòng cuối
tail -100 app.log # 100 dòng cuối của log
tail -f app.log # -f: theo dõi log ĐANG chạy, dòng mới hiện realtime
tail -f app.log | grep ERROR # lọc lỗi trực tiếp khi job chạy
tail -f (follow) là bạn thân khi debug: mở một terminal chạy job, terminal khác tail -f để xem log tuôn ra. Kết hợp head/tail để cắt lát giữa: head -1000 big.csv | tail -100 lấy dòng 901–1000. Xử lý text sâu hơn (grep, awk, cut) sẽ ở bài xử lý văn bản, còn ghép lệnh bằng pipe ở bài pipe & redirection.
Symlink: một cái tên trỏ tới nơi khác
Symbolic link (ln -s) là một "lối tắt" trỏ tới file/thư mục thật. Rất hay dùng để tạo con trỏ "latest" ổn định trong khi dữ liệu thật đổi theo ngày:
ln -s /data/warehouse/curated/2026/06/30 /data/warehouse/curated/latest
ls -l /data/warehouse/curated/latest
# lrwxrwxrwx ... latest -> /data/warehouse/curated/2026/06/30
Job downstream chỉ cần đọc .../curated/latest; mỗi ngày bạn trỏ lại symlink sang phân vùng mới là xong, không phải sửa cấu hình. Cập nhật symlink an toàn (nguyên tử): ln -sfn /data/.../07/01 latest (-f ghi đè, -n không đi vào thư mục đích cũ). Xoá symlink bằng rm latest chỉ xoá link, không đụng dữ liệu thật — nhưng cẩn thận rm -r latest/ (có dấu /) có thể xoá nội dung đích.
Nén & giải nén: sống còn khi chuyển dataset
Chuyển 50GB CSV qua mạng nội bộ mà không nén là phí băng thông và thời gian. Ba công cụ chính:
tar — gom nhiều file/thư mục thành một archive (thường kèm nén):
tar -czf backup.tar.gz /data/warehouse/curated/2026/06 # c=create z=gzip f=file
tar -xzf backup.tar.gz # x=extract
tar -tzf backup.tar.gz # t=list, xem nội dung
tar -xzf backup.tar.gz -C /restore/here # -C: giải vào thư mục đích
Mẹo nhớ: create, extract, table-of-contents; luôn thêm z cho gzip và f trước tên file. Muốn nén mạnh hơn dùng -j (bzip2) hoặc -J (xz) — chậm hơn nhưng file nhỏ hơn.
gzip — nén từng file riêng lẻ (thay thế file gốc):
gzip transactions.csv # → transactions.csv.gz, XOÁ bản gốc
gunzip transactions.csv.gz # giải nén lại
gzip -k transactions.csv # -k: giữ cả bản gốc
zcat transactions.csv.gz | head # xem nội dung mà không giải nén ra đĩa
zcat/zgrep cho phép đọc/grep file .gz trực tiếp — cực tiện với log nén: zgrep "ERROR" app_2026-06-30.log.gz.
zip — định dạng phổ biến khi trao đổi với Windows/người dùng nghiệp vụ:
zip -r report.zip report/ # -r: gồm cả thư mục con
unzip report.zip # giải nén
unzip -l report.zip # -l: liệt kê nội dung không giải
So sánh nhanh cho DE:
| Công cụ | Gom nhiều file? | Ghi đè bản gốc? | Khi nào dùng |
|---|---|---|---|
tar -czf | Có | Không (tạo archive mới) | đóng gói cả thư mục dataset |
gzip | Không (1 file/lần) | Có (trừ khi -k) | nén từng file lớn, log |
zip | Có | Không | gửi cho người dùng Windows |
Lưu ý: parquet đã nén sẵn bên trong (Snappy/GZIP), nên gzip lại một file parquet gần như vô ích — chỉ nên nén CSV/JSON/log là những định dạng text chưa nén.
Use case thực tế
Bối cảnh: Tổ Vận hành dữ liệu NCB nhận cảnh báo phân vùng /data còn 4% trống trên edge node của cụm Spark. Job ETL giao dịch thẻ nửa đêm bắt đầu fail với "No space left on device". Cần khắc phục trong ca trực.
Bước 1 — Xác định phân vùng đầy:
df -h /data
# /dev/sdb1 2.0T 1.92T 80G 96% /data
Bước 2 — Truy thư mục ngốn chỗ:
du -h --max-depth=1 /data | sort -rh | head
# 1.1T /data/warehouse/raw
# 640G /data/logs
# 180G /data/tmp
/data/logs phình bất thường tới 640G.
Bước 3 — Tìm log cũ và ước lượng:
find /data/logs -name "*.log" -mtime +30 -type f | wc -l
# 8214 → hơn 8000 file log cũ hơn 30 ngày
du -sh $(find /data/logs -name "*.log" -mtime +30) 2>/dev/null | tail -1
Bước 4 — Nén thay vì xoá (log còn cần cho audit AML — xem STR reporting — nên nén để giữ chứng cứ, giảm dung lượng ~85%):
find /data/logs -name "*.log" -mtime +30 -exec gzip {} +
Bước 5 — Dọn thư mục tạm an toàn (sau khi ls xác nhận):
ls /data/tmp/spark-* # xác nhận đúng thư mục tạm của Spark
find /data/tmp -maxdepth 1 -name "spark-*" -mtime +1 -exec rm -rf {} +
Bước 6 — Kiểm tra lại và trỏ symlink dataset đã archive:
df -h /data # còn trống trở lại ~28%
Kết quả: giải phóng ~560G trong 15 phút, không mất dữ liệu audit, job ETL chạy lại thành công. Toàn bộ quy trình sau đó được đưa vào một cron job dọn dẹp định kỳ (xem lập lịch & systemd).
Ghi nhớ
pwd/cd/lslà bộ ba nền tảng;ls -lht(chi tiết, dễ đọc, mới nhất trên) là combo dùng nhiều nhất khi soi output pipeline.- Đường dẫn tuyệt đối (
/...) cho script để chắc chắn; tương đối (...~-) cho gõ tay cho nhanh.cd -nhảy qua lại 2 thư mục. mkdir -ptạo cả chuỗi thư mục cha;touchtạo file rỗng/marker;cp -r/cp -asao chép thư mục.rm -rfxoá vĩnh viễn, không thùng rác: luônlsxem trước,set -utrong script, cảnh giác dấu cách lạc và biến rỗng.- Globbing (
*?[]{}) khai triển tên file trước khi chạy lệnh — khác regex, chỉ nhìn tên không nhìn nội dung. findcho tìm kiếm chính xác theo tên/kích thước/thời gian và hành động-exec;locatecho tra nhanh qua index (có thể lỗi thời).du -shđo file/thư mục,df -hđo phân vùng còn trống — bộ đôi xử lý sự cố hết ổ đĩa.wc -lđếm dòng CSV nhanh.- File lớn dùng
head/tail(đừngcat);tail -ftheo dõi log realtime. ln -stạo symlink "latest" ổn định cho downstream; cập nhật bằngln -sfn.- Nén khi chuyển dataset:
tar -czfgói cả thư mục,gzipnén từng file,zipkhi gửi Windows. Parquet đã nén sẵn — đừng gzip lại.
Bài viết liên quan
Bản chất DevOps: phá bỏ rào cản Dev–Ops, vòng lặp vô tận, CALMS, và vì sao tự động hoá.
Continuous Integration/Delivery/Deployment, cấu trúc pipeline, ví dụ GitHub Actions và chiến lược release.
Container vs máy ảo, image/layer, Dockerfile, volume, network, Docker Compose và best practices.
Ba trụ cột logging–metrics–tracing, Prometheus/Grafana, alerting, SLI/SLO/SLA và golden signals.