Khả năng chuyển hướng I/O trong Linux giúp bạn tối ưu hóa nhiều quy trình làm việc. “Triết lý Unix” trong phát triển phần mềm nhấn mạnh việc tạo ra các công cụ mà mỗi công cụ chỉ làm một việc duy nhất và làm tốt việc đó.
Triết lý này đã được kế thừa đến các công cụ dòng lệnh hiện đại. Chúng vốn dĩ đã mạnh mẽ riêng lẻ, và càng mạnh mẽ hơn gấp bội khi được kết hợp với nhau.
Dù bạn đang viết phần mềm phức tạp hay chỉ làm việc trên dòng lệnh, việc biết cách thao tác các luồng I/O (I/O streams) khác nhau trong môi trường của bạn sẽ giúp tăng năng suất đáng kể.
Điều kiện tiên quyết
Để làm theo hướng dẫn này, bạn cần có quyền truy cập vào một máy chủ Linux (Linux server).
Streams
Trong môi trường Linux, đầu vào và đầu ra được phân phối qua ba luồng (streams) chính dưới đây:
- Standard input – stdin (Đầu vào chuẩn)
- Standard output – stdout (Đầu ra chuẩn)
- Standard error – stderr (Lỗi chuẩn)
Các luồng này cũng được gán số hiệu:
- stdin (0)
- stdout (1)
- stderr (2)
Trong các tương tác thông thường giữa người dùng và terminal (thiết bị đầu cuối), standard input đến từ bàn phím của người dùng. Standard output và standard error được hiển thị dưới dạng văn bản trên terminal của người dùng. Tập hợp ba luồng này được gọi chung là standard stream (luồng chuẩn).
Standard Input
Luồng Standard input thường mang dữ liệu từ người dùng đến một chương trình. Các chương trình mong đợi standard input thường nhận đầu vào từ một thiết bị, chẳng hạn như bàn phím. Sau này trong hướng dẫn này, bạn sẽ thấy các ví dụ về việc sử dụng đầu ra của một chương trình làm standard Input cho một chương trình khác.
Standard Output
Standard output là đầu ra được tạo ra bởi một chương trình. Khi luồng đầu ra chuẩn không được chuyển hướng, nó sẽ xuất văn bản trực tiếp ra terminal. Hãy thử xuất một số văn bản tùy ý, sử dụng lệnh echo
:
echo Sent to the terminal
Output
Sent to the terminal
Khi được sử dụng mà không có bất kỳ tùy chọn bổ sung nào, lệnh echo
sẽ xuất bất kỳ đối số (argument) nào được truyền cho nó trên dòng lệnh.
Hãy chạy echo
mà không có bất kỳ đối số nào:
echo
Nó sẽ trả về một dòng trống. Một số chương trình không thực hiện bất kỳ hành động nào nếu không có đối số được cung cấp.
Standard Error
Standard error chứa các lỗi được tạo ra bởi một chương trình bị thất bại theo một cách nào đó. Giống như standard output, đích mặc định cho luồng này là màn hình của terminal .
Hãy xem một ví dụ cơ bản về standard error sử dụng lệnh ls
. Lệnh ls
liệt kê nội dung của một thư mục.
Khi chạy mà không có đối số, ls
liệt kê nội dung trong thư mục hiện tại. Nếu ls
được chạy với một thư mục làm đối số, nó sẽ liệt kê nội dung của thư mục được cung cấp.
ls %
Vì %
không phải là một thư mục hiện có, lệnh này sẽ gửi văn bản sau đến standard error:
Output
ls: cannot access %: No such file or directory
Một chương trình không nhất thiết phải sập hoặc kết thúc chạy để tạo ra standard error. Việc một số đầu ra được gửi đến standard output hay standard error hoàn toàn phụ thuộc vào hành vi của chương trình. Về mặt kỹ thuật, chúng không khác gì nhau. Chỉ là một luồng đầu ra được dùng để chứa các thông báo lỗi, và một số công cụ sẽ mặc định rằng standard error trống có nghĩa là chương trình đã chạy thành công. Một số chương trình thậm chí sẽ xuất các lỗi nhỏ ra standard error mà không bị sập hoặc không thất bại trong việc tạo ra đầu ra dự kiến. Nó chỉ được sử dụng như một quy ước để phân tách đầu ra dự kiến khỏi đầu ra không mong muốn.
Chuyển hướng I/O, Pipe và Redirection trong Linux
Chuyển hướng luồng
Linux bao gồm các lệnh chuyển hướng cho từng luồng. Chúng có thể được dùng để ghi standard output hoặc standard error vào một file. Nếu bạn ghi vào một file không tồn tại, một file mới với tên đó sẽ được tạo trước khi ghi.
Các lệnh với một dấu ngoặc đơn sẽ ghi đè nội dung hiện có của đích.
Ghi đè (Overwrite)
>
– standard output<
– standard input2>
– standard error
Các lệnh với dấu ngoặc kép sẽ không ghi đè nội dung hiện có của đích.
Nối thêm (Append)
>>
– standard output<<
– standard input2>>
– standard error
Pipes
Pipes được sử dụng để chuyển hướng một luồng từ chương trình này sang chương trình khác. Khi standard output của một chương trình được gửi đến chương trình khác thông qua một pipe, đầu ra của chương trình đầu tiên sẽ được sử dụng làm đầu vào cho chương trình thứ hai, thay vì được in ra terminal. Chỉ dữ liệu được trả về bởi chương trình thứ hai mới được hiển thị.
Pipe trong Linux được biểu thị bằng một dấu gạch thẳng đứng: |
Đây là một ví dụ về lệnh sử dụng một pipe:
ls | less
Lệnh này lấy đầu ra của ls
, hiển thị nội dung của thư mục hiện tại của bạn, và pipes (chuyển qua ống dẫn) nó đến chương trình less
. less
hiển thị dữ liệu được gửi đến nó từng dòng một.
ls
thông thường hiển thị nội dung thư mục trên nhiều hàng. Khi bạn chạy nó thông qua less
, mỗi mục được đặt trên một dòng mới.
Mặc dù chức năng của pipe có vẻ tương tự với >
và >>
, điểm khác biệt là pipes chuyển hướng dữ liệu từ lệnh này sang lệnh khác, trong khi >
và >>
được sử dụng để chuyển hướng độc quyền đến các file.
Filters
Filters (bộ lọc) là một nhóm các chương trình thường được sử dụng với đầu ra được pipe từ một chương trình khác. Nhiều filter cũng hữu ích khi dùng riêng lẻ, nhưng chúng minh họa hành vi piping (truyền qua ống dẫn) đặc biệt hiệu quả.
find
– trả về các file có tên file khớp với đối số được truyền chofind
.grep
– trả về văn bản khớp với string pattern được truyền chogrep
.tee
– chuyển hướng standard input đến cả standard output và một hoặc nhiều file.tr
– tìm và thay thế một chuỗi bằng một chuỗi khác.wc
– đếm ký tự, dòng và từ.
Ví dụ
Bây giờ bạn đã được giới thiệu về redirection, piping và các filter cơ bản, hãy cùng xem xét một số mẫu và ví dụ redirection phổ biến.
Mẫu command > file
sẽ chuyển hướng standard output của một lệnh đến một file.
ls ~ > root_dir_contents.txt
Lệnh trên chuyển nội dung thư mục home của bạn (~
) làm standard output và ghi đầu ra đó vào một file có tên root_dir_contents.txt
. Nó sẽ xóa mọi nội dung trước đó trong file vì đây là lệnh sử dụng một dấu ngoặc đơn.
Mẫu command > /dev/null
sẽ chuyển hướng standard output đến “không nơi nào”. /dev/null
là một file đặc biệt được dùng để loại bỏ mọi dữ liệu được chuyển hướngđến đó. Nó được sử dụng để loại bỏ standard output không cần thiết, thứ có thể gây cản trở đến chức năng của một lệnh hoặc một script. Mọi đầu ra được gửi đến /dev/null
đều bị loại bỏ.
ls > /dev/null
Lệnh này loại bỏ standard output stream trả về từ lệnh ls
bằng cách chuyển nó đến /dev/null
.
Mẫu command 2> file
sẽ chuyển hướng standard error stream của một lệnh đến một file, ghi đè nội dung hiện có.
mkdir '' 2> mkdir_log.txt
Lệnh này có lỗi phát sinh do tên thư mục không hợp lệ ''
, và ghi nó vào log.txt
. Lưu ý rằng lỗi vẫn được gửi đến terminal (thiết bị đầu cuối) và hiển thị dưới dạng văn bản.
Mẫu command >> file
sẽ redirect (chuyển hướng) standard output của một lệnh đến một file mà không ghi đè nội dung hiện có của file.
echo Written to a new file > data.txt
echo Appended content to an existing file >> data.txt
Cặp lệnh này đầu tiên redirect văn bản được người dùng nhập thông qua echo
vào một file mới. Sau đó, nó append (nối thêm) văn bản nhận được bởi lệnh echo
thứ hai vào file hiện có, mà không ghi đè nội dung của nó.
Mẫu command 2>> file
ở trên sẽ redirect standard error stream của một lệnh đến một file mà không ghi đè nội dung hiện có của file. Mẫu này hữu ích để tạo các error log (nhật ký lỗi) cho một chương trình hoặc dịch vụ, vì file log sẽ không bị xóa nội dung trước đó mỗi khi file được ghi vào.
find '' 2> stderr_log.txt
wc '' 2>> stderr_log.txt
Lệnh trên redirect thông báo lỗi gây ra bởi một đối số find
không hợp lệ đến một file tên stderr_log.txt
. Sau đó, nó append thông báo lỗi gây ra bởi một đối số wc
không hợp lệ vào cùng file đó.
Mẫu command | command
sẽ redirect standard output từ lệnh đầu tiên đến standard input của lệnh thứ hai.
find /var lib | grep deb
Lệnh này tìm kiếm trong /var
và các thư mục con của nó các tên file và phần mở rộng khớp với string deb
, và trả về các file paths (đường dẫn tệp) cho các file, với phần khớp trong mỗi đường dẫn được tô sáng màu đỏ.
Mẫu command | tee file
(bao gồm lệnh tee
) sẽ redirect standard output của lệnh đến một file và ghi đè nội dung của nó. Sau đó, nó hiển thị đầu ra đã được redirect trong terminal. Nó sẽ tạo một file mới nếu file đó chưa tồn tại.
Trong ngữ cảnh của mẫu này, tee
thường được sử dụng để xem đầu ra của một chương trình đồng thời lưu nó vào một file.
wc /etc/magic | tee magic_count.txt
Câu lệnh này sẽ pipe kết quả đếm số ký tự, dòng và từ trong file /etc/magic
(được Linux shell sử dụng để xác định loại file) đến lệnh tee
. Lệnh tee
sau đó chia đầu ra của wc
thành hai hướng, và gửi nó đến màn hình terminal và file magic_count.txt
. Đối với lệnh tee
, hãy hình dung chữ T. Phần dưới của chữ cái là dữ liệu ban đầu, và phần trên là dữ liệu được chia thành hai hướng khác nhau (standard output và terminal).
Bạn cũng có thể dùng nhiều pipe để redirect đầu ra qua nhiều lệnh và/hoặc filters.
Kết luận
Học cách sử dụng các khả năng redirection trong Linux là một kỹ năng thiết yếu. Giờ đây sau khi đã nắm được những điều cơ bản về cách hoạt động của redirection và pipe, bạn có thể bắt đầu hành trình của mình vào thế giới shell scripting, nơi thường xuyên sử dụng các chương trình và mẫu được nêu bật trong hướng dẫn này.
Việc tìm kiếm các lệnh cụ thể, hoặc những gì bạn muốn làm trong command line (ví dụ: “xóa tất cả các file trong một thư mục bắt đầu bằng chữ cái viết hoa”) cũng có thể rất hữu ích khi bạn cần hoàn thành một tác vụ cụ thể bằng cách sử dụng command line.