Học bằng cách đọc theo thứ tự

Đầu ra và báo cáo — Ghi bằng printf và here-doc

Bài viết này là một phần của Khóa học Linux, giúp bạn thành thạo từ đầu những kỹ năng Linux thực tiễn, từ các lệnh cơ bản đến lập trình shell script.
Canh cột bằng printf '%s\t%s\n', nối thêm kết quả bằng > và >>, tách lỗi sang tệp khác bằng 2>, rồi nhúng $(wc -l) vào mẫu here-doc để dựng một báo cáo tổng hợp — minh họa và thực hành trên terminal.

In có định dạng — printf và điều hướng nơi đầu ra đi tới

Để in kết quả của script cho dễ đọc, bạn dùng echo khi cần in một chuỗi nguyên văn, và printf khi cần chỉ định định dạng để canh đều độ rộng và dấu phân cách.

Nếu bạn chỉ cần in giá trị của một biến trên một dòng thì echo "$v" là đủ.

Viết printf '%s\t%s\n' name age thì các tham số lần lượt đi vào các chỗ %s, \t thành tab còn \n thành xuống dòng.

Khác với echo, printf không tự xuống dòng, nên hãy luôn viết \n ở cuối dòng.

Đầu ra của một lệnh đi theo hai luồng: đầu ra chuẩn và lỗi chuẩn.

> file ghi đè tệp bằng đầu ra chuẩn, >> file nối thêm vào cuối, còn 2> file chỉ đưa lỗi chuẩn sang một tệp riêng.

Đưa kết quả bình thường vào báo cáo và lỗi sang tệp riêng thì sau này bạn truy ra nguyên nhân dễ hơn hẳn.

vi fmt.sh   # mở bằng trình soạn thảo, viết nội dung sau rồi lưu bằng :wq
#   #!/bin/sh
#   printf '%s\t%s\n' name age      # tiêu đề phân tách bằng tab
#   printf '%s\t%s\n' alice 30      # dòng dữ liệu, đã canh cột
#   echo "done" >> fmt.log           # nối thêm vào log
chmod +x fmt.sh
./fmt.sh
Điều hướng nơi đầu ra đi tới
kết quả thườngđầu ra chuẩn> ghi đè>> nối thêmlỗilỗi chuẩn2> err.logvào báo cáolỗi sang tệp riêng
Kết quả thường đi vào báo cáo bằng > (ghi đè) hoặc >> (nối thêm), còn lỗi được tách sang một tệp khác bằng 2>.
Cú phápÝ nghĩaVí dụ
echo "$v"In một biến hay chuỗi nguyên vănecho "$name"
printf "%s\t%s\n" a bIn có định dạng (phân tách bằng tab, xuống dòng ghi rõ)printf '%s\t%s\n' name age
> fGhi đè tệp bằng đầu ra chuẩnecho line > report.txt
>> fNối thêm đầu ra chuẩn vào một tệpecho more >> report.txt
2> errChỉ tách lỗi chuẩn sang một tệp kháccat missing 2> err.log

Viết và chạy một script in đầu ra có định dạng rồi ghi nó ra tệp.

① Mở format.sh bằng vi format.sh rồi nhấn i để vào insert mode. Viết phần in có định dạng và ghi báo cáo, rồi lưu bằng Esc:wq (có thể sao chép nội dung trong bảng đáp án rồi dán vào).

② Thêm quyền thực thi bằng chmod +x format.sh.

③ Chạy bằng ./format.sh và xem đầu ra đã định dạng trên màn hình.

④ Xem nội dung báo cáo vừa ghi ra bằng cat table.txt. (Chạy đúng thì phần giải thích sẽ hiện ra.)

Linux console
0 / 4 đã hoàn thành
Loading Linux Terminal...

Gom báo cáo tổng hợp vào một tệp — here-doc và thay thế lệnh

Với báo cáo có bố cục cố định, hãy viết khuôn mẫu bằng here-doc và nhúng kết quả của lệnh vào bên trong nó.

Các dòng bạn viết giữa cat > report.txt <<EOF … EOF trở thành nội dung tệp nguyên văn, còn chỗ bạn viết $(...) thì kết quả chạy sẽ được mở rộng ngay tại đó.

<<EOF không có nháy sẽ mở rộng biến và thay thế lệnh, còn <<'EOF' (có nháy đơn) không mở rộng gì cả và in nguyên văn.

Các giá trị tổng hợp như số đếm hay tổng thì lấy vào biến bằng thay thế lệnh $(wc -l …) hay $(grep -c …).

Viết xong báo cáo, hãy dùng mã thoát exit để báo cho phía gọi script có chạy thành công hay không.

exit 0 nghĩa là thành công còn exit 1 nghĩa là có gì đó không ổn, và một && phía sau hay một job CI đều dựa vào đó mà quyết định.

vi summary.sh   # mở bằng trình soạn thảo, viết nội dung sau rồi lưu bằng :wq
#   #!/bin/sh
#   log=access.log
#   lines=$(wc -l < "$log")          # đếm số dòng
#   cat > summary.txt <<REPORT       # nhúng giá trị vào mẫu
#   --- access summary ---
#   total lines: $lines
#   REPORT
#   echo "summary.txt created"
#   exit 0
chmod +x summary.sh
Nhúng kết quả tổng hợp vào here-doc
access.logđếm bằng $(wc -l)total = 5<<EOF … EOFnhúng $totalreport.txt hoàn tấttổng hợpnhúng vào mẫu
Giá trị mà $(wc -l) đếm được sẽ được nhúng vào đúng chỗ $(...) trong mẫu here-doc, gom cả báo cáo vào một tệp.
Cú phápÝ nghĩaVí dụ
<<EOF … EOFhere-doc có mở rộng biến và thay thế lệnhcat <<EOF > t.txt
<<'EOF' … EOFhere-doc không mở rộng gì cả, in nguyên văncat <<'EOF' > t.txt
$(wc -l < f)Lấy một giá trị tổng hợp vào biến bằng thay thế lệnhn=$(wc -l < access.log)
exit 0 / exit 1Trả về mã thoát thành công hay thất bạiexit 0

Tổng hợp số đếm từ một log, nhúng chúng vào mẫu here-doc, rồi gom báo cáo vào một tệp duy nhất.

① Tạo tệp log dữ liệu mẫu bằng printf 'GET /a 200\nGET /b 404\nGET /c 200\nGET /d 500\nGET /e 200\n' > access.log.

② Mở report.sh bằng vi report.sh rồi nhấn i để vào insert mode. Viết phần tổng hợp số đếm bằng thay thế lệnh rồi nhúng chúng vào mẫu here-doc, sau đó lưu bằng Esc:wq (có thể sao chép nội dung trong bảng đáp án rồi dán vào).

③ Thêm quyền thực thi bằng chmod +x report.sh.

④ Chạy bằng ./report.sh, rồi xem các giá trị tổng hợp và mẫu trong report.txt vừa sinh ra bằng cat report.txt.

Linux console
0 / 3 đã hoàn thành
Loading Linux Terminal...

Tách đầu ra chuẩn và lỗi sang hai tệp riêng

Khi một lệnh duy nhất vừa cho kết quả bình thường vừa cho lỗi cùng lúc, viết > ok.txt 2> err.txt thì đầu ra chuẩn được lưu vào ok.txt còn lỗi chuẩn vào err.txt.

Vì sau đó bạn xem được "kết quả" và "vấn đề" tách bạch, dạng này rất hay dùng khi thiết kế log cho script vận hành.

ls /etc /no_such_dir > ok.txt 2> err.txt   # danh sách vào ok.txt, lỗi vào err.txt
cat ok.txt                                  # danh sách /etc (đầu ra chuẩn)
cat err.txt                                 # lỗi /no_such_dir (lỗi chuẩn)
Tách hai luồng của một lệnh duy nhất
ls /etc /no_suchok.txt(kết quả)err.txt(vấn đề)> đầu ra chuẩn2> lỗi chuẩn
Đầu ra chuẩn của một lệnh duy nhất đi được vào > ok.txt còn lỗi chuẩn vào 2> err.txt, lưu riêng cùng lúc.
Cú phápÝ nghĩaVí dụ
cmd > ok 2> errĐưa đầu ra chuẩn và lỗi chuẩn sang hai tệp riêng cùng lúcls /etc > ok.txt 2> err.txt
echo "…" 1>&2Đưa một thông báo sang phía lỗi chuẩnecho failed 1>&2

Viết và chạy một script điều hướng đầu ra chuẩn và lỗi của một lệnh duy nhất sang hai tệp riêng.

① Mở split.sh bằng vi split.sh rồi nhấn i để vào insert mode. Viết phần đưa đầu ra chuẩn và lỗi sang hai tệp riêng, rồi lưu bằng Esc:wq (có thể sao chép nội dung trong bảng đáp án rồi dán vào).

② Thêm quyền thực thi bằng chmod +x split.sh.

③ Chạy bằng ./split.sh và xem số dòng của ok.txterr.txt hiện trên màn hình.

④ Xem nội dung đầu ra chuẩn bằng cat ok.txt và nội dung lỗi bằng cat err.txt.

Linux console
0 / 5 đã hoàn thành
Loading Linux Terminal...
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Trong printf '%s\t%s\n' a b, \t\n đại diện cho cái gì?

Câu 2Cách viết nào chỉ điều hướng lỗi chuẩn của một lệnh sang một tệp riêng?

Câu 3Khi muốn nhúng kết quả chạy của $(...) bên trong mẫu here-doc, bạn chọn thẻ mở nào?