Các luồng tiêu chuẩn cho đầu vào, đầu ra và lỗi
Trong điện toán, **chuyển hướng** là một hình thức giao tiếp giữa các tiến trình và là một chức năng phổ biến đối với hầu hết các trình thông dịch dòng lệnh, bao gồm các shell Unix khác nhau có thể chuyển hướng các luồng tiêu chuẩn đến các vị trí do người dùng chỉ định.

Trong các hệ điều hành giống Unix, các chương trình thực hiện chuyển hướng với lệnh gọi hệ thống `dup2 (2)` hoặc kém linh hoạt hơn nhưng mức độ cao hơn tương tự stdio là, `freopen (3)` và `popen (3)`.

Chuyển hướng đầu vào tiêu chuẩn và đầu ra tiêu chuẩn
----------------------------------------------------

Chuyển hướng thường được thực hiện bằng cách đặt các ký tự nhất định giữa các lệnh.

### Căn bản

Thông thường, cú pháp như sau, sử dụng `<` để chuyển hướng đầu vào và `>` để chuyển hướng đầu ra. `command1 > file1` thực thi `command1`, đặt đầu ra trong `file1`. Điều này sẽ ghi đè bất kỳ dữ liệu hiện có trong `tệp1`.

Sử dụng `command1 < file1` thực thi `command1`, với `file1` là nguồn đầu vào.

`command1 < infile > outfile` kết hợp hai khả năng: `command1` đọc từ `infile` và ghi vào `outfile`

### Biến thể

Để thêm vào cuối của tập tin, chứ không phải là ghi đè nó,`>>` được sử dụng: `command1 >> file1`.

Để đọc từ một chuỗi các dòng (một tập tin nhiều dòng, truyền từng dòng tới các đầu vào tiêu chuẩn), người ta có thể sử dụng một here document, sử dụng`<<`:

```
1 tr a-z A-Z << END_TEXT
2 one two three
3 uno dos tres
4 END_TEXT
```

Để đọc từ một chuỗi, người ta có thể sử dụng một here string, sử dụng`<<<`: `tr a-z A-Z <<< "one two three"`, hoặc là:

```
NUMBERS="one two three"
tr a-z A-Z <<< "$NUMBERS"
```

Đường ống
---------

thumb| Một đường dẫn gồm ba chương trình chạy trên text terminal. Các chương trình có thể được chạy cùng nhau sao cho một chương trình đọc đầu ra từ một chương trình khác mà không cần tệp trung gian rõ ràng. `command1 | command2` thực thi `command1`, sử dụng đầu ra của nó làm đầu vào cho `command2` (thường được gọi là đường ống, với ký tự "|" được gọi là "pipe").

Hai chương trình thực hiện các lệnh có thể chạy song song với không gian lưu trữ duy nhất là bộ đệm làm việc (Linux cho phép tối đa 64K cho mỗi bộ đệm) cộng với bất kỳ không gian làm việc nào mà mỗi lệnh xử lý yêu cầu. Ví dụ, lệnh "sort" không thể tạo ra bất kỳ đầu ra nào cho đến khi tất cả các bản ghi đầu vào đã được đọc, vì bản ghi cuối cùng nhận được có thể trở thành đầu tiên theo thứ tự được sắp xếp. Hệ điều hành thử nghiệm của Tiến sĩ Alexia Massalin, Synthesis, sẽ điều chỉnh mức độ ưu tiên của từng tác vụ khi chúng chạy theo mức độ đầy đủ của bộ đệm đầu vào và đầu ra.

Điều này tạo ra kết quả cuối cùng giống như sử dụng hai chuyển hướng và một tệp tạm thời, như cặp lệnh dưới đây:

```
1 command1 > tempfile
2 command2 < tempfile
3 rm tempfile
```

Nhưng ở đây, `command2` không bắt đầu thực thi cho đến khi `command1` kết thúc và một tệp tạm thời đủ lớn được yêu cầu để giữ kết quả trung gian cũng như bất kỳ không gian làm việc nào mà mỗi tác vụ yêu cầu. Ví dụ, mặc dù DOS cho phép cú pháp "pipe", nhưng nó sử dụng cách tiếp cận thứ hai này. Do đó, giả sử một số chương trình chạy trong thời gian dài, "Worker" tạo ra các thông báo khác nhau khi nó hoạt động và chương trình thứ hai, TimeStamp sao chép từng bản ghi từ *stdin* sang *stdout*, thêm vào phía trước ngày và giờ của hệ thống khi nhận được bản ghi. Một chuỗi như `Worker | TimeStamp > LogFile.txt` sẽ chỉ điền thời gian khi Worker đã hoàn thành vào dòng đầu tiên, và ghi thời gian đọc và ghi tệp đầu ra của nó ở các dòng tiếp theo.

Một ví dụ điển hình cho đường ống lệnh là kết hợp `echo` với một lệnh khác để đạt được thứ gì đó tương tác trong một shell không tương tác, ví dụ `echo -e 'user\npass'| ftp localhost`. Điều này chạy ứng dụng khách ftp với `user` đầu vào, nhấn `return`, sau đó `pass`.

Trong sử dụng thông thường, bước đầu tiên của một đường ống thường là `cat` hoặc `echo`, đọc từ tệp hoặc chuỗi. Điều này thường có thể được thay thế bằng chỉ định đầu vào hoặc here string và sử dụng cat và đường ống thay vì chuyển hướng đầu vào được gọi là sử dụng cat vô dụng. Ví dụ: các lệnh sau:

```
1 cat infile | cmd
2 echo $string | cmd
3 echo -e 'user\npass' | ftp localhost
```

có thể được thay thế bởi:

```
1 cmd < infile
2 cmd <<< $string
3 ftp localhost <<< $'user\npass'
```

Vì `echo` thường là một lệnh shell nội bộ, nên việc sử dụng nó không bị chỉ trích như cat, là một lệnh bên ngoài.

Chuyển hướng đến và đi từ xử lí tệp tiêu chuẩn
----------------------------------------------

Trong các shell Unix có nguồn gốc từ shell Bourne ban đầu, hai hành động đầu tiên có thể được sửa đổi thêm bằng cách đặt một số (bộ mô tả tệp) ngay trước ký tự; điều này sẽ ảnh hưởng đến luồng nào được sử dụng để chuyển hướng. Các luồng I / O tiêu chuẩn Unix là:

| Xử lý | Tên | Sự miêu tả |
| --- | --- | --- |
| 0 | stdin | Đầu vào tiêu chuẩn |
| 1 | stdout | Đầu ra tiêu chuẩn |
| 2 | stderr | Lỗi tiêu chuẩn |

Ví dụ: `command1 2> file1` thực thi `command1`, hướng luồng lỗi tiêu chuẩn đến `file1`.

Trong các shell có nguồn gốc từ csh (shell C), cú pháp thay vào đó sẽ thêm ký tự `&` (ampersand) vào các ký tự chuyển hướng, do đó đạt được kết quả tương tự. Lý do cho điều này là để phân biệt giữa một tệp có tên '1' và stdout, tức là 'cat file 2> 1' so với 'cat file 2> &1'. Trong trường hợp đầu tiên, stderr được chuyển hướng đến một tệp có tên '1' và trong trường hợp thứ hai, stderr được chuyển hướng đến stdout.

Một khả năng hữu ích khác là chuyển hướng một xử lý tệp tiêu chuẩn sang một tệp khác. Biến thể phổ biến nhất là hợp nhất lỗi tiêu chuẩn thành đầu ra tiêu chuẩn để thông báo lỗi có thể được xử lý cùng với (hoặc thay thế cho) đầu ra thông thường. Ví dụ: `find / -name.profile > results 2>&1` sẽ cố gắng tìm tất cả các tệp có tên `.profile`. Nếu thực hiện mà không chuyển hướng, nó sẽ xuất các lần tìm được vào stdout và lỗi (ví dụ như thiếu đặc quyền đối với các thư mục được bảo vệ) vào stderr. Nếu đầu ra tiêu chuẩn được hướng đến tập tin `results`, thông báo lỗi xuất hiện trên console. Để xem cả lượt truy cập và thông báo lỗi trong tệp `results`, cần hợp nhất stderr (xử lý 2) vào stdout (xử lý 1) bằng cách sử dụng **`2> & 1`**.

Nếu đầu ra được hợp nhất vào đường ống để chuyển sang chương trình khác, chuỗi hợp nhất tệp **`2> & 1`** phải đặt trước ký hiệu ống, do đó, `find / -name.profile2>&1 | less`

Một hình thức tuân thủ đơn giản nhưng không phải POSIX của lệnh, `command > file 2>&1` là (không có sẵn trong Bourne Shell trước phiên bản 4, bản phát hành cuối cùng hoặc trong vỏ shell Debian Almquist tiêu chuẩn được sử dụng trong Debian / Ubuntu): `command &>file` hoặc `command >&file`.

Có thể sử dụng `2>&1` trước "`>` "nhưng kết quả thường bị hiểu sai. Quy tắc là bất kỳ chuyển hướng nào đều đặt tay cầm vào luồng đầu ra một cách độc lập. Vì vậy, "`2>&1` "đặt xử lý `2` thành bất cứ điều gì xử lý điểm`1`, mà tại thời điểm đó thường là *stdout*. Sau đó, "`>` "chuyển hướng xử lý `1` sang một thứ khác, ví dụ như một tệp, nhưng nó **không** thay đổi xử lý `2`, mà vẫn trỏ đến *stdout*.

Trong ví dụ sau, đầu ra tiêu chuẩn được ghi vào *file*, nhưng lỗi được chuyển hướng từ stderr sang stdout, tức là được gửi đến màn hình: `command 2>&1 > file`.

Để ghi cả lỗi và đầu ra tiêu chuẩn vào *tập file*, thứ tự phải được đảo ngược. Đầu ra tiêu chuẩn trước tiên sẽ được chuyển hướng đến tệp, sau đó stderr cũng sẽ được chuyển hướng đến stdout đã được thay đổi để trỏ đến tệp: `command > file 2>&1`. Windows PowerShell 5 định nghĩa sáu luồng khác nhau.

Chuỗi đường ống
---------------

Các mã thông báo chuyển hướng và đường ống có thể được nối lại với nhau để tạo ra các lệnh phức tạp. Ví dụ: `sort infile | uniq -c | sort -n > outfile` sắp xếp các dòng của `infile` theo thứ tự từ điển, viết các dòng duy nhất với tiền tố là số lần xuất hiện, sắp xếp các dòng theo số lần xuất hiện và ghi vào `outfile`. Kiểu xây dựng này được sử dụng rất phổ biến trong các tập lệnh shell và tập tin bó.

Chuyển hướng đến nhiều đầu ra
-----------------------------

Lệnh chuẩn `tee` có thể chuyển hướng đầu ra từ một lệnh đến một số địa điểm: `ls -lrt | tee xyz`. Điều này chỉ đạo đầu ra danh sách tập tin cho cả đầu ra tiêu chuẩn và tập tin `xyz`.

Tham khảo
---------