jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

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:

StreamSốDùng cho
stdin0input
stdout1output bình thường
stderr2lỗ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:

  1. tạo danh sách;
  2. lọc;
  3. biến đổi;
  4. đế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

  1. Dùng rg tìm draft: false, pipe qua wc -l.
  2. Lưu output npm run build vào build.log bằng tee.
  3. Dùng rg --filesxargs wc -l để đếm dòng các file .astro.
  4. 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.