This programming guide is only available in Vietnamese. Switch to Vietnamese to read the full article.
Sức mạnh thực sự của Bash nằm ở khả năng xử lý text. Với hệ thống redirection,
pipeline và bộ ba công cụ grep, sed, awk, bạn có thể biến đổi,
lọc và phân tích dữ liệu text một cách cực kỳ hiệu quả ngay từ dòng lệnh. Bài học này sẽ hướng dẫn bạn
từng công cụ một cách chi tiết.
1. Redirection: stdin, stdout, stderr
Mỗi tiến trình trong Linux/Unix có 3 file descriptor mặc định:
0— stdin (standard input): dữ liệu đầu vào1— stdout (standard output): kết quả bình thường2— stderr (standard error): thông báo lỗi
Redirection cho phép bạn chuyển hướng các luồng dữ liệu này sang file hoặc sang nhau.
#!/bin/bash
# Ghi đè file (overwrite) với >
echo "Dòng đầu tiên" > output.txt
# Nối thêm vào file (append) với >>
echo "Dòng thứ hai" >> output.txt
# Đọc input từ file với <
wc -l < output.txt # Đếm số dòng trong file
# Redirect stderr (fd 2) sang file
ls /thu_muc_khong_ton_tai 2> error.log
# Redirect cả stdout và stderr sang cùng file
ls /home /xxx 2>&1 > all_output.log
# Hoặc cú pháp ngắn gọn hơn (Bash 4+):
ls /home /xxx &> all_output.log
# Bỏ qua output hoàn toàn với /dev/null
ping -c 1 google.com > /dev/null 2>&1
echo "Ping xong, exit code: $?"
# Redirect stdout sang file, stderr sang file khác
command_nao_do > success.log 2> error.log
Here Document và Here String
Here Document (<<EOF) cho phép bạn truyền nhiều dòng text vào
stdin của một lệnh. Here String (<<<) truyền một chuỗi đơn.
#!/bin/bash
# Here Document — tạo file config nhanh
cat <<EOF > config.ini
[database]
host=localhost
port=5432
name=myapp_db
EOF
# Here Document với tab indentation (dùng <<- để bỏ tab đầu dòng)
if true; then
cat <<-EOF
Dòng này có tab ở đầu sẽ bị loại bỏ
Tiện lợi khi viết trong block indent
EOF
fi
# Here String — truyền chuỗi vào stdin
grep "hello" <<< "hello world, xin chào"
# Đếm từ trong một chuỗi
wc -w <<< "Bash là ngôn ngữ shell scripting"
# Tách chuỗi bằng read với here string
IFS=',' read -r name age city <<< "Quang,25,HCM"
echo "Tên: $name, Tuổi: $age, TP: $city"
2. Pipeline |
Pipeline (|) là cốt lõi của triết lý Unix:
"Mỗi chương trình làm một việc tốt, và kết nối chúng lại với nhau." Pipe lấy
stdout của lệnh bên trái làm stdin của lệnh bên phải.
#!/bin/bash
# Đếm số lỗi 404 trong access log
cat access.log | grep "404" | wc -l
# Top 10 IP truy cập nhiều nhất
cat access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -10
# Liệt kê tất cả user đang chạy process
ps aux | awk '{print $1}' | sort -u | tail -n +2
# Tìm 5 file lớn nhất trong thư mục hiện tại
du -sh * 2>/dev/null | sort -rh | head -5
# Pipeline kết hợp nhiều bước xử lý
echo "hello world foo bar baz" | tr ' ' '\n' | sort | uniq | wc -l
Lệnh tee — ghi ra file đồng thời hiển thị
tee cho phép bạn "rẽ nhánh" dữ liệu: vừa ghi vào file, vừa tiếp tục pipeline.
#!/bin/bash
# Vừa hiển thị ra màn hình, vừa lưu vào file
ls -la | tee listing.txt
# Append thay vì overwrite
date | tee -a log.txt
# Ghi vào nhiều file cùng lúc
echo "Thông báo quan trọng" | tee file1.txt file2.txt file3.txt
# Kết hợp trong pipeline dài
cat data.csv | tee raw_backup.csv | grep "active" | tee filtered.csv | wc -l
3. grep — Tìm kiếm Pattern
grep (Global Regular Expression Print) là công cụ tìm kiếm text mạnh nhất trong Unix. Nó
tìm các dòng khớp với pattern và in ra kết quả.
#!/bin/bash
# Tìm kiếm cơ bản
grep "error" /var/log/syslog
# -i: không phân biệt hoa thường
grep -i "warning" app.log
# -n: hiển thị số dòng
grep -n "TODO" *.py
# -r: tìm đệ quy trong thư mục
grep -r "import React" src/
# -c: đếm số dòng khớp
grep -c "404" access.log
# -v: đảo ngược — hiển thị dòng KHÔNG khớp
grep -v "^#" config.ini # Bỏ dòng comment
# -l: chỉ hiển thị tên file chứa pattern
grep -rl "deprecated" --include="*.js" src/
# -w: khớp nguyên từ (word boundary)
grep -w "log" script.sh # Khớp "log" nhưng không khớp "logging"
# -A, -B, -C: hiển thị dòng xung quanh kết quả
grep -A 3 "ERROR" app.log # 3 dòng sau
grep -B 2 "ERROR" app.log # 2 dòng trước
grep -C 2 "ERROR" app.log # 2 dòng trước và sau
Extended Regex với grep -E
#!/bin/bash
# -E: Extended Regular Expression (hoặc dùng egrep)
# Tìm email
grep -E '[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' contacts.txt
# Tìm IP address
grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log
# Tìm nhiều pattern với |
grep -E "error|warning|critical" app.log
# Tìm dòng bắt đầu bằng số
grep -E "^[0-9]" data.txt
# Tìm dòng trống
grep -E "^$" file.txt
# Tìm URL
grep -Eo 'https?://[^ ]+' page.html
# -o: chỉ in phần khớp (không in cả dòng)
echo "Giá: 150000 VND" | grep -oE '[0-9]+'
# Output: 150000
# -P: Perl-compatible regex (hỗ trợ lookahead/lookbehind)
echo "version=3.14.1" | grep -oP '(?<=version=)\S+'
# Output: 3.14.1
4. sed — Stream Editor
sed (Stream Editor) là công cụ chỉnh sửa text theo luồng. Nó đọc từng dòng, áp dụng lệnh
biến đổi, và in ra kết quả — không thay đổi file gốc (trừ khi dùng -i).
#!/bin/bash
# Thay thế cơ bản: s/old/new/
echo "Hello World" | sed 's/World/Vietnam/'
# Output: Hello Vietnam
# g flag: thay thế TẤT CẢ occurrences trên dòng
echo "aaa bbb aaa" | sed 's/aaa/xxx/g'
# Output: xxx bbb xxx
# Không có g chỉ thay thế lần đầu tiên
echo "aaa bbb aaa" | sed 's/aaa/xxx/'
# Output: xxx bbb aaa
# -i: chỉnh sửa file trực tiếp (in-place)
sed -i 's/old_value/new_value/g' config.txt
# Trên macOS cần backup extension:
sed -i '.bak' 's/old/new/g' config.txt
# Xóa dòng chứa pattern
sed '/^#/d' config.ini # Xóa dòng comment
sed '/^$/d' file.txt # Xóa dòng trống
# Xóa theo số dòng
sed '5d' file.txt # Xóa dòng 5
sed '3,7d' file.txt # Xóa dòng 3 đến 7
# In dòng cụ thể (kết hợp -n)
sed -n '10p' file.txt # In dòng 10
sed -n '5,10p' file.txt # In dòng 5 đến 10
sed -n '/pattern/p' file.txt # In dòng khớp pattern
sed nâng cao
#!/bin/bash
# Address ranges — chỉ thay thế trong phạm vi dòng
sed '2,5s/foo/bar/g' file.txt # Chỉ thay ở dòng 2-5
sed '/START/,/END/s/old/new/g' file.txt # Từ dòng chứa START đến END
# Capture groups với \( \) và back-reference \1
echo "2026-06-24" | sed 's/\([0-9]*\)-\([0-9]*\)-\([0-9]*\)/\3\/\2\/\1/'
# Output: 24/06/2026
# Chèn dòng trước/sau
sed '3i\Dòng mới chèn trước dòng 3' file.txt
sed '3a\Dòng mới chèn sau dòng 3' file.txt
# Nhiều lệnh sed cùng lúc
sed -e 's/foo/bar/g' -e 's/baz/qux/g' -e '/^$/d' file.txt
# Thay đổi delimiter (hữu ích khi pattern chứa /)
sed 's|/usr/local/bin|/opt/bin|g' paths.txt
sed 's#http://#https://#g' urls.txt
# Thêm prefix/suffix cho mỗi dòng
sed 's/^/PREFIX: /' file.txt # Thêm prefix
sed 's/$/ :SUFFIX/' file.txt # Thêm suffix
5. awk — Field Processing
awk là ngôn ngữ xử lý text mạnh mẽ nhất trong bộ ba. Nó tự động chia mỗi dòng thành các
field ($1, $2, ...) và cho phép bạn thực hiện tính toán,
điều kiện, vòng lặp.
#!/bin/bash
# In field cụ thể (mặc định tách bằng khoảng trắng)
echo "Alice 90 85 92" | awk '{print $1, $3}'
# Output: Alice 85
# $0 = toàn bộ dòng, NR = số dòng, NF = số field
echo -e "a b c\nd e f g" | awk '{print "Dòng", NR, "có", NF, "field:", $0}'
# -F: thay đổi field separator
echo "name,age,city" | awk -F',' '{print $2}'
# Output: age
# Xử lý file CSV
awk -F',' '{print $1, $3}' employees.csv
# Pattern matching — chỉ xử lý dòng khớp
awk '/error/ {print NR, $0}' app.log
# So sánh field
awk -F',' '$3 > 50000 {print $1, $3}' salaries.csv
# BEGIN và END blocks
awk 'BEGIN {print "=== BÁO CÁO ==="}
{print NR". "$0}
END {print "Tổng:", NR, "dòng"}' data.txt
awk nâng cao — Tính toán và thống kê
#!/bin/bash
# Tính tổng cột
awk -F',' '{sum += $2} END {print "Tổng:", sum}' sales.csv
# Tính trung bình
awk -F',' '{sum += $2; count++} END {print "TB:", sum/count}' scores.csv
# Tìm giá trị lớn nhất
awk -F',' 'BEGIN {max=0} $2 > max {max=$2; name=$1} END {print name, max}' data.csv
# Format output với printf
awk -F',' '{printf "%-20s %10.2f VND\n", $1, $2}' prices.csv
# Associative array — đếm theo nhóm
awk -F',' '{count[$1]++} END {for (k in count) print k, count[k]}' log.csv
# Điều kiện if-else
awk -F',' '{
if ($3 >= 90) grade="A"
else if ($3 >= 80) grade="B"
else if ($3 >= 70) grade="C"
else grade="F"
print $1, grade
}' students.csv
Các công cụ bổ sung: cut, sort, uniq, tr, wc, xargs
#!/bin/bash
# cut — cắt field/ký tự từ mỗi dòng
cut -d',' -f1,3 data.csv # Lấy field 1 và 3 (delimiter = ,)
cut -c1-10 file.txt # Lấy 10 ký tự đầu mỗi dòng
# sort — sắp xếp
sort file.txt # Sắp xếp theo alphabet
sort -n numbers.txt # Sắp xếp theo số
sort -r file.txt # Đảo ngược
sort -t',' -k2 -n data.csv # Sắp xếp theo cột 2 (số)
sort -u file.txt # Sắp xếp + loại bỏ trùng
# uniq — loại bỏ dòng trùng liên tiếp (thường dùng sau sort)
sort names.txt | uniq # Loại trùng
sort names.txt | uniq -c # Đếm số lần xuất hiện
sort names.txt | uniq -d # Chỉ hiện dòng trùng
# tr — translate/delete ký tự
echo "hello" | tr 'a-z' 'A-Z' # Chuyển thành HOA
echo "hello world" | tr -s ' ' # Squeeze khoảng trắng
echo "abc123def" | tr -d '0-9' # Xóa số → abcdef
cat file.txt | tr '\n' ' ' # Nối tất cả dòng thành 1
# wc — word count
wc -l file.txt # Đếm dòng
wc -w file.txt # Đếm từ
wc -c file.txt # Đếm byte
# xargs — chuyển stdin thành arguments
find . -name "*.tmp" | xargs rm # Xóa file .tmp
grep -rl "old_func" src/ | xargs sed -i 's/old_func/new_func/g'
echo "1 2 3 4 5" | xargs -n 2 echo # Chia thành nhóm 2
6. Câu hỏi trắc nghiệm ôn tập
Trắc nghiệm: Pipeline & grep
Lệnh nào đếm số dòng chứa từ "error" (không phân biệt hoa thường) trong file app.log?
Trắc nghiệm: sed & awk
Trong awk, biến NF đại diện cho gì?
Tải file code thực hành minh họa bài học
File script tổng hợp tất cả ví dụ về redirection, pipeline, grep, sed, awk và các công cụ xử lý text khác.
Tải về text_processing.sh
Comments
Bình luận