Lệnh tee trong Linux — Ghi dữ liệu vào file và màn hình

Bạn đã bao giờ rơi vào tình huống đang thực hiện một script quan trọng trên VPS, nhưng lại lỡ tay chạy lệnh mà không thấy kết quả hiển thị ra màn hình để theo dõi trực tiếp chưa nhỉ? Điều này thực sự rất khó chịu, nhất là khi bạn cần vừa ghi log vào file, vừa muốn quan sát tiến trình đang diễn ra ngay lúc đó đúng không? Vậy tee là gì và làm thế nào để giải quyết vấn đề này một cách mượt mà nhất?

Tee là một công cụ cực kỳ mạnh mẽ trong thế giới Linux, cho phép bạn đọc dữ liệu từ đầu vào tiêu chuẩn và ghi đồng thời vào cả đầu ra tiêu chuẩn lẫn một hoặc nhiều file. Với kinh nghiệm của một Senior System Admin, mình thường xuyên sử dụng cách dùng tee để ghi lại log quá trình cài đặt các package phức tạp trên server, giúp mình có thể vừa kiểm soát lỗi trực tiếp, vừa lưu trữ dữ liệu để kiểm tra lại sau này. Hãy cùng mình khám phá cách dùng tee Linux để tối ưu hóa công việc quản trị hệ thống của bạn nhé!

Cần chuẩn bị gì trước khi dùng lệnh tee?

  • Quyền user: Người dùng cần có quyền đọc file nguồn và quyền ghi vào file đích. Trong trường hợp ghi vào các thư mục hệ thống, bạn cần sử dụng quyền sudo.
  • Hệ điều hành hỗ trợ: Lệnh tee là một phần của gói coreutils, được hỗ trợ mặc định trên hầu hết các bản phân phối Linux (Ubuntu, Debian, CentOS, Fedora, Arch Linux) và macOS.
  • Package dependencies: Không yêu cầu cài đặt thêm gói bổ trợ vì lệnh này luôn đi kèm sẵn trong các hệ thống Unix-like.

Cú pháp lệnh tee là gì?

Lệnh tee hỗ trợ các dạng cú pháp cơ bản trên hầu hết các hệ thống Linux/Unix.

tee [OPTION]... [FILE]...

Các tùy chọn của lệnh tee là gì?

Lệnh tee cung cấp các tùy chọn cho phép kiểm soát cách xử lý dữ liệu đầu vào, ghi file và quản lý luồng dữ liệu đầu ra.

Tùy chọn ngắn Tùy chọn dài Mô tả
-a --append tee -a ghi dữ liệu vào cuối file thay vì ghi đè toàn bộ nội dung file.
-i --ignore-interrupts tee -i bỏ qua tín hiệu ngắt (SIGINT) từ bàn phím, cho phép lệnh tiếp tục xử lý dữ liệu.
-p --output-error tee -p không dừng khi gặp lỗi ghi file, tiếp tục ghi dữ liệu còn lại.
--output-error=warn tee --output-error=warn hiển thị cảnh báo khi gặp lỗi ghi file nhưng không dừng xử lý.
--output-error=exit tee --output-error=exit dừng lệnh ngay khi gặp lỗi ghi file.
--output-error=exit-nopipe tee --output-error=exit-nopipe dừng lệnh khi gặp lỗi ghi file, ngoại trừ lỗi broken pipe.
-h --help tee -h hiển thị thông tin trợ giúp về cách sử dụng lệnh tee.
-V --version tee -V hiển thị phiên bản của lệnh tee.

xem thêm: Basic File and Directory Operations

Lệnh tee được sử dụng trong các trường hợp thực tế nào?

Phần này trình bày các kịch bản ứng dụng lệnh tee từ việc ghi log cơ bản đến xử lý luồng dữ liệu phức tạp trong quản trị hệ thống.

tee là gì? [Ghi dữ liệu ra file và màn hình]

echo "Hello Linux" | tee message.txt
Hello Linux

Nội dung được in ra terminal đồng thời lưu vào file message.txt. Trong thực tế, cách này giúp người dùng vừa theo dõi được tiến độ chạy lệnh, vừa lưu lại kết quả để kiểm tra sau này.

tee -a là gì? [Ghi nối tiếp vào file hiện có]

echo "New log entry" | tee -a log.txt
New log entry

Tham số -a (append) cho phép ghi thêm nội dung vào cuối file mà không làm mất dữ liệu cũ. Trên môi trường production, đây là cách phổ biến để ghi nhật ký (logging) liên tục vào một file log duy nhất.

tee với sudo là gì? [Ghi file hệ thống bằng quyền root]

echo "127.0.0.1 mysite.local" | sudo tee -a /etc/hosts
127.0.0.1 mysite.local

Sử dụng sudo kết hợp với tee cho phép ghi dữ liệu vào các file hệ thống bị giới hạn quyền. Trong thực tế, việc dùng lệnh "sudo echo ... > /etc/hosts" thường thất bại do lỗi phân quyền shell, nên tee là giải pháp thay thế tiêu chuẩn để sửa đổi cấu hình hệ thống.

tee kết hợp pipe là gì? [Lưu log và chuyển tiếp dữ liệu]

ls -l | tee file_list.txt | grep ".txt"
-rw-r--r-- 1 user user 10 May 20 file_list.txt
-rw-r--r-- 1 user user 5 May 20 test.txt

Lệnh tee đóng vai trò là điểm trung gian, vừa lưu danh sách file vào file_list.txt, vừa đẩy dữ liệu qua lệnh grep để lọc. Trong các kịch bản automation, kỹ thuật này cho phép vừa thực hiện xử lý dữ liệu, vừa tạo ra file backup dữ liệu thô để phục vụ debug.

Tại sao lệnh tee không ghi được dữ liệu vào file hoặc bị lỗi Permission denied?

Trong quá trình quản trị hệ thống, người dùng thường gặp phải các lỗi liên quan đến quyền truy cập và luồng dữ liệu khi sử dụng lệnh tee.

Lỗi không thể ghi vào file hệ thống dù đã dùng sudo với lệnh trước đó

echo "nameserver 8.8.8.8" | sudo echo > /etc/resolv.conf
bash: /etc/resolv.conf: Permission denied

Lỗi xảy ra do toán tử điều hướng (>) được thực thi bởi shell của người dùng hiện tại thay vì shell của root, dẫn đến việc không có quyền ghi vào file hệ thống.

Lỗi không thể ghi vào file yêu cầu quyền quản trị khi dùng pipe

echo "127.0.0.1 mysite.local" > /etc/hosts
bash: /etc/hosts: Permission denied

Lệnh thất bại vì luồng đầu ra được điều hướng trực tiếp vào file hệ thống mà không thông qua quyền sudo, ngay cả khi người dùng có quyền sudo cho các lệnh khác.

Lỗi mất dữ liệu khi ghi đè file mà không sử dụng tùy chọn phù hợp

echo "new content" | tee -a config.txt

Nếu người dùng muốn nối thêm nội dung vào cuối file nhưng quên tùy chọn -a, lệnh tee sẽ mặc định ghi đè và làm mất toàn bộ dữ liệu cũ trong file.

Lỗi không nhận được output khi kết hợp với các lệnh không in ra stdout

find /etc -type f | tee log.txt | grep "pattern"

Nếu lệnh find không tìm thấy kết quả nào, file log.txt sẽ được tạo ra nhưng trống rỗng, dẫn đến việc các lệnh xử lý phía sau không có dữ liệu để thực hiện.

Quy trình thực tế dùng lệnh tee trong quản trị hệ thống Linux?

Trong kịch bản cấu hình dịch vụ web server, lệnh tee thường được sử dụng kết hợp với quyền sudo để ghi đè file cấu hình và lưu trữ log quá trình thực hiện cùng một lúc.

Bước 1: Kiểm tra nội dung file cấu hình hiện tại

cat /etc/nginx/nginx.conf

Cho phép bạn xem nội dung cấu hình hiện tại của Nginx trước khi thực hiện thay đổi.

Bước 2: Ghi cấu hình mới vào file hệ thống bằng quyền root

echo "worker_processes 4;" | sudo tee /etc/nginx/nginx.conf
worker_processes 4;

Cho phép bạn ghi dữ liệu từ lệnh echo vào file cấu hình hệ thống mà không gặp lỗi quyền truy cập (permission denied) nhờ kết hợp với sudo.

Bước 3: Ghi đè cấu hình và lưu log vào file riêng biệt

echo "server { listen 80; }" | tee /etc/nginx/conf.d/default.conf > deploy_log.txt
server { listen 80; }

Cho phép bạn vừa hiển thị cấu hình mới ra màn hình, vừa lưu nội dung đó vào file deploy_log.txt để phục vụ việc kiểm tra sau này.

Bước 4: Ghi thêm nội dung vào cuối file mà không làm mất dữ liệu cũ

echo "user nginx;" | tee -a /etc/nginx/nginx.conf
user nginx;

Sử dụng tham số -a cho phép bạn chèn thêm dòng cấu hình vào cuối file hiện có thay vì ghi đè toàn bộ file.

Lệnh tee thực hiện ghi dữ liệu đồng thời vào tệp tin và tiêu chuẩn đầu ra (stdout). Trong các kịch bản quản trị VPS, người dùng thường gặp lỗi Permission denied khi sử dụng lệnh redirect thông thường như > để ghi vào tệp hệ thống. Việc kết hợp sudo với redirect trực tiếp (ví dụ: sudo echo "data" > /etc/config) không có tác dụng vì quyền sudo chỉ áp dụng cho lệnh echo, không áp dụng cho trình điều hướng shell. Để xử lý trường hợp này trên VPS, cấu trúc sudo tee phải được sử dụng: sudo echo "data" | tee /etc/config. Ngoài ra, khi thực hiện các tác vụ ghi log trong cron job, cần lưu ý tham số -a để tránh việc lệnh tee ghi đè (overwrite) dữ liệu cũ của tệp tin hiện có. Việc sử dụng tee cho phép theo dõi luồng dữ liệu trực tiếp ngay khi quá trình ghi vào tệp đang diễn ra.

Những câu hỏi thường gặp về lệnh tee?

Dưới đây là các tình huống thực tế và thắc mắc phổ biến khi người dùng bắt đầu sử dụng lệnh tee trong quản trị hệ thống Linux.

Làm thế nào để vừa hiển thị kết quả ra màn hình vừa ghi vào file?

Lệnh tee mặc định thực hiện song song hai nhiệm vụ là xuất dữ liệu ra chuẩn đầu ra (stdout) và ghi dữ liệu đó vào tệp tin được chỉ định.

echo "Hello Linux" | tee output.txt
Hello Linux

Làm thế nào để ghi đè lên nội dung cũ của file thay vì ghi nối tiếp?

Theo mặc định, lệnh tee sẽ ghi đè toàn bộ nội dung cũ của tệp tin bằng nội dung mới được truyền vào.

echo "New Content" | tee file.txt
New Content

Làm thế nào để ghi thêm dữ liệu vào cuối file mà không xóa nội dung cũ?

Sử dụng tùy chọn -a (append) để cho phép lệnh tee thêm dữ liệu vào cuối tệp tin hiện có.

echo "Append this line" | tee -a file.txt
Append this line

Làm thế nào để ghi dữ liệu vào các file hệ thống yêu cầu quyền root?

echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf
nameserver 8.8.8.8

Khi sử dụng dấu redirect thông thường (>) với sudo, quyền root chỉ áp dụng cho lệnh echo chứ không áp dụng cho việc ghi file. Lệnh tee kết hợp với sudo cho phép ghi trực tiếp vào tệp tin có bảo mật cao.

Làm thế nào để ghi kết quả vào nhiều file cùng một lúc?

Lệnh tee cho phép bạn truyền vào nhiều tên tệp tin khác nhau làm đối số để đồng thời ghi dữ liệu vào tất cả các tệp đó.

echo "Data for all" | tee file1.txt file2.txt file3.txt
Data for all

Làm thế nào để loại bỏ việc hiển thị kết quả ra màn hình khi dùng tee?

Để chỉ ghi dữ liệu vào file mà không xuất ra terminal, bạn có thể điều hướng đầu ra của tee vào thiết bị null.

echo "Silent write" | tee file.txt > /dev/null

Lệnh tee là một công cụ vô cùng mạnh mẽ giúp bạn vừa ghi dữ liệu vào tệp tin, vừa hiển thị nội dung đó ra màn hình cùng một lúc. Bạn có thể dễ dàng kết hợp tham số -a để ghi nối tiếp vào tệp hiện có mà không làm mất dữ liệu cũ, hoặc sử dụng tham số -i để bỏ qua các cảnh báo khi gặp lỗi, đúng không nhỉ? Việc kiểm soát luồng dữ liệu thông qua lệnh này chắc chắn sẽ giúp quy trình làm việc của bạn trở nên linh hoạt và trực quan hơn rất nhiều. Chúc bạn thành công!