❤️ AZDIGI chính thức cập nhật hệ thống blog mới hoàn chỉnh. Tuy nhiên có thể một số bài viết bị sai lệch hình ảnh, hãy ấn nút Báo cáo bài viết ở cuối bài để AZDIGI cập nhật trong thời gian nhanh nhất. Chân thành cám ơn.

Ở các bài trước, bạn đã biết cách tạo file, xóa file, phân quyền, quản lý tiến trình. Nhưng sức mạnh thực sự của Linux nằm ở khả năng xử lý text. Hôm nay mình sẽ giới thiệu bộ công cụ mà dân sysadmin dùng hằng ngày: pipe, grep, redirect, awk, sed và một số lệnh xử lý dữ liệu khác.

linux b12 grep

Nắm được mấy thứ này, bạn có thể lọc log, phân tích traffic, tìm lỗi trong hàng triệu dòng text chỉ với một dòng lệnh.

Pipe (|), Nối lệnh lại với nhau

Pipe là ký tự |, dùng để lấy output của lệnh bên trái làm input cho lệnh bên phải. Đây là khái niệm nền tảng nhất khi làm việc với text trên Linux.

Cú pháp:

lệnh_1 | lệnh_2 | lệnh_3

Ví dụ, bạn muốn xem có bao nhiêu tiến trình nginx đang chạy:

ps aux | grep nginx

Lệnh ps aux liệt kê toàn bộ tiến trình, sau đó pipe sang grep nginx để chỉ lọc ra dòng nào có chữ “nginx”.

Một ví dụ khác, đếm số dòng trong file:

cat /etc/passwd | wc -l

Hoặc xem 20 file lớn nhất trong thư mục hiện tại:

du -sh * | sort -rh | head -20

Bạn có thể nối bao nhiêu pipe cũng được. Mỗi lệnh trong chuỗi nhận output từ lệnh trước và xử lý tiếp.

grep, Tìm text nhanh và mạnh

grep là lệnh dùng nhiều nhất khi làm việc với text trên Linux. Nó tìm các dòng chứa chuỗi ký tự bạn chỉ định, trong file hoặc trong output từ pipe.

Cú pháp cơ bản:

grep "chuỗi_cần_tìm" tên_file

Các option hay dùng

-i, Không phân biệt hoa thường (case insensitive):

grep -i "error" /var/log/syslog

Lệnh trên sẽ tìm được cả “Error”, “ERROR”, “error”.

-n, Hiện số dòng:

grep -n "failed" /var/log/auth.log

Output sẽ kèm số dòng ở đầu, giúp bạn biết chính xác lỗi nằm ở đâu trong file.

-r, Tìm đệ quy trong thư mục:

grep -r "listen 80" /etc/nginx/

Tìm trong tất cả file bên trong thư mục /etc/nginx/ và các thư mục con.

-v, Invert, hiện những dòng KHÔNG chứa chuỗi:

grep -v "^#" /etc/nginx/nginx.conf

Lọc bỏ tất cả dòng comment (bắt đầu bằng #), chỉ hiện config thực sự.

-c, Đếm số dòng khớp:

grep -c "404" /var/log/nginx/access.log

Cho biết có bao nhiêu request trả về lỗi 404.

-E, Dùng regex mở rộng:

grep -E "error|warning|critical" /var/log/syslog

Tìm đồng thời nhiều từ khóa bằng regex.

Hiện thêm context xung quanh kết quả

Khi grep tìm thấy lỗi, bạn thường muốn xem thêm vài dòng trước/sau để hiểu ngữ cảnh:

# -A 3: hiện thêm 3 dòng SAU dòng khớp (After)
grep -A 3 "error" /var/log/syslog

# -B 2: hiện thêm 2 dòng TRƯỚC dòng khớp (Before) grep -B 2 "error" /var/log/syslog

# -C 2: hiện thêm 2 dòng cả trước và sau (Context) grep -C 2 "error" /var/log/syslog

Ví dụ thực tế: Tìm lỗi trong log

Giả sử website bạn bị lỗi, cần tìm xem chuyện gì xảy ra:

# Tìm tất cả lỗi PHP trong error log
grep -i "fatal\|error" /var/log/php-fpm/error.log

# Tìm lỗi trong 1 giờ gần nhất (giả sử log có timestamp dạng "Mar 15 16:") grep "Mar 15 16:" /var/log/syslog | grep -i error

# Đếm số lần xuất hiện lỗi 502 trong access log grep -c " 502 " /var/log/nginx/access.log

Redirect, Điều hướng input/output

Trên Linux, mỗi lệnh có 3 luồng dữ liệu:

  • stdin (0): dữ liệu đầu vào
  • stdout (1): kết quả bình thường
  • stderr (2): thông báo lỗi

Redirect cho phép bạn chuyển hướng các luồng này thay vì hiện ra terminal.

Ghi output ra file

>, Ghi đè file (tạo mới nếu chưa có, xóa nội dung cũ nếu đã có):

echo "Hello" > output.txt
ls -la /etc > danh-sach.txt

>>, Nối thêm vào cuối file (không xóa nội dung cũ):

echo "Dòng mới" >> output.txt
date >> log.txt

Cẩn thận với >! Nếu bạn gõ nhầm > thay vì >>, nội dung cũ sẽ bị xóa sạch không cứu được.

Redirect stderr

2>, Chuyển hướng chỉ phần lỗi:

# Lưu lỗi vào file riêng
find / -name "*.conf" 2> errors.txt
# Bỏ qua lỗi hoàn toàn
find / -name "*.conf" 2>/dev/null

&>, Chuyển hướng cả stdout và stderr vào cùng một file:

command &> all-output.txt

Redirect input

<, Đọc input từ file thay vì từ bàn phím:

mysql -u root -p database_name < backup.sql
wc -l < /etc/passwd

/dev/null, Hố đen của Linux

/dev/null là một file đặc biệt, mọi thứ ghi vào đây sẽ biến mất. Dùng khi bạn muốn chạy lệnh mà không cần thấy output:

# Chạy lệnh, bỏ qua mọi output
command > /dev/null 2>&1
# Viết ngắn hơn (bash 4+)
command &> /dev/null

Hay gặp trong crontab khi bạn không muốn nhận email thông báo mỗi lần cron chạy.

Kết hợp pipe và redirect

Sức mạnh thực sự đến khi bạn kết hợp pipe với redirect:

# Tìm 20 dòng error cuối cùng trong syslog, lưu ra file
grep -i error /var/log/syslog | tail -20 > errors.txt

# Liệt kê user đang login, sắp xếp, lưu file who | sort > users-online.txt

# Tìm tất cả file .log lớn hơn 100MB find /var/log -name "*.log" -size +100M 2>/dev/null | sort > large-logs.txt

awk, Xử lý dữ liệu theo cột

awk là công cụ xử lý text mạnh, đặc biệt hữu ích khi dữ liệu có cấu trúc theo cột (như file log, CSV). Mình sẽ giới thiệu những cách dùng cơ bản nhất.

In cột chỉ định

Trong awk, $1 là cột 1, $2 là cột 2, $0 là toàn bộ dòng. Mặc định các cột phân tách bằng khoảng trắng.

# In cột 1 và cột 4 từ access log (IP và thời gian)
awk '{print $1, $4}' /var/log/nginx/access.log

# In cột 1 (username) từ /etc/passwd, phân tách bằng dấu : awk -F: '{print $1}' /etc/passwd

# In dòng có cột 9 = 404 (HTTP status code) awk '$9 == 404 {print $0}' /var/log/nginx/access.log

Đếm và tính toán

# Đếm số request từ mỗi IP
awk '{print $1}' access.log | sort | uniq -c | sort -rn

# Tính tổng bytes (cột 10) trong access log awk '{sum += $10} END {print sum}' access.log

# Tính tổng và format ra MB awk '{sum += $10} END {printf "%.2f MB\n", sum/1024/1024}' access.log

sed, Tìm và thay thế text

sed (stream editor) dùng để thay đổi nội dung text. Phổ biến nhất là tìm và thay thế.

Thay thế text

# Thay thế lần đầu tiên trong mỗi dòng
sed 's/old/new/' file.txt

# Thay thế tất cả (global) sed 's/old/new/g' file.txt

# Thay thế và ghi trực tiếp vào file (-i) sed -i 's/old-domain.com/new-domain.com/g' config.conf

# Thay thế không phân biệt hoa thường sed 's/error/WARNING/gi' log.txt

Option -i sẽ sửa trực tiếp file gốc. Nếu muốn an toàn, dùng -i.bak để tạo bản backup trước khi sửa: sed -i.bak 's/old/new/g' file.txt

Xóa dòng và in theo range

# Xóa dòng 5
sed '5d' file.txt

# Xóa từ dòng 10 đến dòng 20 sed '10,20d' file.txt

# Xóa dòng trống sed '/^$/d' file.txt

# Chỉ in dòng 5 đến 10 (tương tự head/tail nhưng linh hoạt hơn) sed -n '5,10p' file.txt

# Xóa tất cả dòng comment sed '/^#/d' config.conf

Ví dụ thực tế

# Đổi port SSH trong config
sed -i 's/^#Port 22/Port 2222/' /etc/ssh/sshd_config

# Thêm dòng sau dòng chứa "server_name" sed -i '/server_name/a\ include /etc/nginx/extra.conf;' /etc/nginx/sites-available/default

# Xóa tất cả comment và dòng trống để xem config gọn sed '/^#/d; /^$/d' /etc/nginx/nginx.conf

sort, uniq, cut, tr, Bộ công cụ xử lý data

Mấy lệnh này tuy đơn giản nhưng khi kết hợp với pipe thì rất mạnh.

sort, Sắp xếp

# Sắp xếp theo alphabet
sort file.txt

# Sắp xếp theo số sort -n numbers.txt

# Sắp xếp ngược (lớn đến nhỏ) sort -rn numbers.txt

# Sắp xếp theo cột 3, phân tách bằng dấu phẩy sort -t',' -k3 -n data.csv

uniq, Loại bỏ dòng trùng

# Loại bỏ dòng trùng liên tiếp (phải sort trước)
sort file.txt | uniq

# Đếm số lần xuất hiện sort file.txt | uniq -c

# Chỉ hiện dòng bị trùng sort file.txt | uniq -d

uniq chỉ loại bỏ dòng trùng liên tiếp, nên bạn cần sort trước. Đây là combo kinh điển: sort | uniq -c | sort -rn

cut, Cắt cột

# Lấy cột 1 từ file CSV (phân tách bằng dấu phẩy)
cut -d',' -f1 data.csv

# Lấy cột 1 và 3 cut -d',' -f1,3 data.csv

# Lấy username từ /etc/passwd cut -d: -f1 /etc/passwd

# Lấy ký tự từ vị trí 1 đến 10 cut -c1-10 file.txt

tr, Chuyển đổi ký tự

# Chuyển chữ thường thành chữ hoa
echo "hello" | tr 'a-z' 'A-Z'

# Xóa ký tự xuống dòng thừa cat file.txt | tr -s '\n'

# Thay tab thành dấu phẩy cat file.txt | tr '\t' ','

# Xóa tất cả số echo "abc123def456" | tr -d '0-9'

Pipeline kinh điển: Top 10 IP truy cập

Đây là ví dụ mà sysadmin nào cũng dùng. Phân tích access log để tìm 10 IP truy cập nhiều nhất:

awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

Giải thích từng bước:

  1. awk '{print $1}', lấy cột đầu tiên (IP address)
  2. sort, sắp xếp để các IP giống nhau nằm cạnh nhau
  3. uniq -c, đếm số lần xuất hiện của mỗi IP
  4. sort -rn, sắp xếp theo số lượng, từ cao xuống thấp
  5. head -10, chỉ lấy 10 dòng đầu

Output trông kiểu này:

   4523 192.168.1.100
   3891 10.0.0.50
   2104 203.0.113.42
   1876 198.51.100.7
    ...

tee, Vừa xem vừa lưu

tee giống như một ngã ba: nó vừa hiện output ra terminal, vừa ghi vào file cùng lúc.

# Vừa xem trên terminal, vừa lưu vào file
ping google.com | tee ping-result.txt

# Nối thêm thay vì ghi đè df -h | tee -a disk-log.txt

# Kết hợp trong pipeline grep "error" /var/log/syslog | tee errors.txt | wc -l

Ví dụ cuối rất hay: nó lọc error, lưu vào file errors.txt, đồng thời đếm xem có bao nhiêu dòng error tất cả.

Một trường hợp hữu ích nữa là khi cần ghi file với quyền root:

# Không hoạt động vì redirect chạy với user hiện tại
echo "nameserver 8.8.8.8" > /etc/resolv.conf
# Hoạt động vì tee chạy với sudo
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf

xargs, Chuyển output thành arguments

Một số lệnh không đọc input từ pipe. Ví dụ rm không đọc tên file từ stdin. Lúc này xargs giúp chuyển output của lệnh trước thành tham số cho lệnh sau.

# Tìm và xóa tất cả file .tmp
find /tmp -name "*.tmp" | xargs rm -f

# Tìm file .log cũ hơn 30 ngày và xóa find /var/log -name "*.log" -mtime +30 | xargs rm -f

# An toàn hơn với tên file có khoảng trắng find /tmp -name "*.tmp" -print0 | xargs -0 rm -f

Option -print0-0 dùng null character thay vì xuống dòng để phân tách, đảm bảo tên file có khoảng trắng hoặc ký tự đặc biệt vẫn xử lý đúng.

Một số ví dụ khác:

# Nén tất cả file .log lại
find /var/log -name "*.log" | xargs gzip

# Kill tất cả tiến trình của user cụ thể ps aux | grep "^username" | awk '{print $2}' | xargs kill

# Download nhiều URL từ file cat urls.txt | xargs -n1 wget

Option -n1 nghĩa là mỗi lần chỉ truyền 1 argument, hữu ích khi lệnh chỉ nhận từng tham số một.

Checkpoint: Bài tập thực hành

Dưới đây là một số bài tập để bạn tự luyện. Tất cả đều dùng các lệnh đã học trong bài này.

Bài 1: Phân tích access log

Giả sử bạn có file /var/log/nginx/access.log, hãy thực hiện:

# 1. Tìm top 10 IP truy cập nhiều nhất
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

# 2. Đếm số request theo HTTP status code awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

# 3. Tìm các URL trả về lỗi 500 awk '$9 == 500 {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

# 4. Xem top 10 URL được truy cập nhiều nhất awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10

# 5. Tính tổng bandwidth (bytes) đã dùng awk '{sum += $10} END {printf "Total: %.2f MB\n", sum/1024/1024}' /var/log/nginx/access.log

Bài 2: Lọc error trong syslog

# 1. Tìm tất cả dòng có chứa "error" (không phân biệt hoa thường)
grep -i "error" /var/log/syslog

# 2. Đếm số lần xuất hiện error theo từng service grep -i "error" /var/log/syslog | awk '{print $5}' | sort | uniq -c | sort -rn

# 3. Lọc error trong 1 giờ gần nhất và lưu ra file grep "$(date '+%b %d %H')" /var/log/syslog | grep -i error > /tmp/recent-errors.txt

# 4. Tìm các lỗi SSH failed login grep "Failed password" /var/log/auth.log | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10

Bài 3: Kết hợp sed với pipeline

# 1. Xem Nginx config sạch (bỏ comment và dòng trống)
sed '/^[[:space:]]*#/d; /^$/d' /etc/nginx/nginx.conf

# 2. Export danh sách user (chỉ lấy username và shell) awk -F: '{print $1, $7}' /etc/passwd | sort

# 3. Thay đổi hàng loạt domain trong config find /etc/nginx/sites-available/ -type f | xargs sed -i 's/old-domain.com/new-domain.com/g'

Tổng kết

Trong bài này bạn đã học:

  • Pipe (|), nối output/input giữa các lệnh
  • grep, tìm kiếm text với nhiều option mạnh
  • Redirect, điều hướng stdout, stderr, stdin bằng >, >>, 2>, &>, <
  • awk, xử lý dữ liệu theo cột, đếm và tính toán
  • sed, tìm và thay thế text, xóa dòng
  • sort, uniq, cut, tr, bộ công cụ xử lý data trong pipeline
  • tee, vừa hiện terminal vừa ghi file
  • xargs, chuyển output thành arguments cho lệnh khác

Những lệnh này đơn lẻ thì bình thường, nhưng khi kết hợp qua pipe thì bạn có thể xử lý data phức tạp chỉ trong một dòng lệnh. Sysadmin hay gọi đây là "one-liner" và đây thực sự là kỹ năng khiến bạn làm việc nhanh gấp nhiều lần so với dùng GUI.

Bài tiếp theo mình sẽ đi vào shell scripting, nơi bạn sẽ kết hợp tất cả những gì đã học thành các script tự động hóa hoàn chỉnh.

Chia sẻ:
Bài viết đã được kiểm duyệt bởi AZDIGI Team

Về tác giả

Trần Thắng

Trần Thắng

Chuyên gia tại AZDIGI với nhiều năm kinh nghiệm trong lĩnh vực web hosting và quản trị hệ thống.

Hơn 10 năm phục vụ 80.000+ khách hàng

Bắt đầu dự án web của bạn với AZDIGI