Command Line cho Developer · Part 4 - Pipes, Redirection & xargs
Ghép command thành workflow: stdin/stdout/stderr, pipe, >, >>, 2>, tee, command substitution, xargs, while read và pattern xử lý file hàng loạt an toàn.
Đây là Phần 4. Từ đây terminal bắt đầu mạnh hơn GUI: bạn không chỉ chạy từng lệnh, mà ghép output của lệnh này thành input của lệnh khác.
Một command line giỏi thường là một pipeline nhỏ, dễ đọc:
rg -l "TODO" src | sort | head
Ba stream: stdin, stdout, stderr
Mỗi process có ba stream chuẩn:
| Stream | Số | Dùng cho |
|---|---|---|
| stdin | 0 | input |
| stdout | 1 | output bình thường |
| stderr | 2 | lỗi, cảnh báo, log |
Ví dụ:
echo "hello" # stdout
ls /no-such-path # stderr
Pipe chỉ nối stdout mặc định:
command1 | command2
Nếu lỗi nằm trên stderr, pipe sau không thấy nó trừ khi bạn redirect.
Redirection cơ bản
Ghi stdout vào file:
npm run build > build.out
Ghi nối tiếp:
npm run test >> test.out
Ghi stderr:
npm run build 2> build.err
Ghi stdout và stderr chung:
npm run build > build.log 2>&1
Trong bash/zsh, dạng ngắn:
npm run build &> build.log
Khi viết script portable hơn, dùng > file 2>&1 vì rõ ràng và quen thuộc.
Pipe: ghép command thành câu hỏi
Đếm TODO:
rg "TODO|FIXME" src | wc -l
Top file có nhiều match:
rg -n "TODO|FIXME" src | cut -d: -f1 | sort | uniq -c | sort -nr | head
Liệt kê file bài viết theo series:
rg --files src/content/posts | rg '^src/content/posts/bash-' | sort
Pipeline nên đọc từ trái sang phải như một câu:
- tạo danh sách;
- lọc;
- biến đổi;
- đếm/sắp xếp/in phần đầu.
Nếu pipeline dài hơn 4-5 bước và bạn cần dùng lại, đó là ứng viên để viết script.
tee: vừa lưu vừa nhìn
npm run build 2>&1 | tee build.log
tee hợp khi bạn muốn giữ log nhưng vẫn nhìn tiến trình.
Ghi thêm:
npm run test 2>&1 | tee -a test.log
Trong CI, nhiều team dùng pattern này để upload log artifact khi job fail.
Command substitution: lấy output làm biến
branch=$(git rev-parse --abbrev-ref HEAD)
today=$(date +%Y-%m-%d)
echo "Building $branch on $today"
Luôn quote biến khi dùng lại:
latest_file=$(ls -t logs/*.log | head -1)
less "$latest_file"
Nếu output có newline hoặc nhiều file, đừng nhét vào một biến string tùy tiện. Dùng array hoặc pipeline null-separated ở các phần sâu hơn.
xargs: biến danh sách thành arguments
xargs đọc stdin, gom thành argument cho command khác.
Đếm dòng của mọi file MDX:
rg --files src/content/posts | rg '\\.mdx$' | xargs wc -l
Chạy formatter trên file match:
rg -l "oldFunction" src | xargs prettier --write
Xem 5 dòng đầu của từng file match:
rg -l "series: dev-cli" src/content/posts | xargs -I {} sh -c 'echo "== {} =="; head -5 "{}"'
Trong ví dụ cuối, {} là placeholder do xargs -I thay bằng từng path.
An toàn với tên file có space
Sai khi file có space:
find . -name '*.mdx' | xargs wc -l
Đúng hơn:
find . -name '*.mdx' -print0 | xargs -0 wc -l
Với rg:
rg -l --null "TODO" src | xargs -0 sed -n '1,20p'
Quy tắc thực tế:
- Nếu pipeline xử lý text lines, newline là ổn.
- Nếu pipeline xử lý file paths, dùng null separator khi có thể.
while read: khi mỗi item cần logic
Khi command quá phức tạp cho xargs, dùng loop:
rg -l --null "TODO" src |
while IFS= read -r -d '' file; do
echo "Checking $file"
head -5 "$file"
done
Pattern này giữ path an toàn, kể cả có space.
Nếu shell của bạn không hỗ trợ read -d '' như mong muốn, chuyển sang script bash rõ ràng với shebang:
#!/usr/bin/env bash
set -euo pipefail
Recipe developer hay dùng
Lưu output build đầy đủ:
npm run build > build.log 2>&1
Tìm file chứa secret nghi ngờ và in tên file:
rg -l "api_key|secret|token" --hidden --glob '!.git/**'
Chạy lệnh trên mọi package trong monorepo:
find packages -maxdepth 2 -name package.json -print0 |
xargs -0 -I {} dirname "{}" |
xargs -I {} sh -c 'cd "{}" && npm test'
Đếm extension trong repo:
rg --files | sed 's/.*\\.//' | sort | uniq -c | sort -nr | head
Bài tập
- Dùng
rgtìmdraft: false, pipe quawc -l. - Lưu output
npm run buildvàobuild.logbằngtee. - Dùng
rg --filesvàxargs wc -lđể đếm dòng các file.astro. - Viết pipeline tìm 10 extension xuất hiện nhiều nhất trong repo.
Lời giải tham khảo
rg "draft: false" src/content/posts | wc -l
npm run build 2>&1 | tee build.log
rg --files | rg '\\.astro$' | xargs wc -l
rg --files | sed 's/.*\\.//' | sort | uniq -c | sort -nr | head -10Điều cốt lõi
Pipe và redirection biến terminal thành bộ lego nhỏ: command tạo output, command sau lọc hoặc biến đổi output đó. xargs là cầu nối từ danh sách sang thao tác hàng loạt. Khi pipeline bắt đầu khó đọc, hãy viết script.