Bạn đã có một vài câu trả lời rất tốt rồi. Hãy để tôi nhấn mạnh mặc dù có hai khái niệm khác nhau liên quan ở đây, sự hiểu biết về nó giúp ích rất nhiều:
Bối cảnh: Mô tả tệp so với bảng tệp
Bộ mô tả tệp của bạn chỉ là số 0 ... n, là chỉ mục trong bảng mô tả tệp trong quy trình của bạn. Theo quy ước, STDIN = 0, STDOUT = 1, STDERR = 2 (lưu ý rằng các thuật ngữ, STDIN
v.v ... ở đây chỉ là các ký hiệu / macro được sử dụng bởi quy ước trong một số ngôn ngữ lập trình và trang man, không có một "đối tượng" thực tế nào được gọi là STDIN; mục đích của cuộc thảo luận này, STDIN là 0, v.v.).
Bản thân bảng mô tả tệp đó không chứa bất kỳ thông tin nào về tệp thực sự là gì. Thay vào đó, nó chứa một con trỏ tới một bảng tệp khác; cái sau chứa thông tin về một tệp vật lý thực tế (hoặc thiết bị chặn hoặc đường ống hoặc bất kỳ thứ gì khác mà Linux có thể xử lý thông qua cơ chế tệp) và nhiều thông tin hơn (ví dụ, cho dù đó là để đọc hay viết).
Vì vậy, khi bạn sử dụng >
hoặc <
trong trình bao của mình, bạn chỉ cần thay thế con trỏ của bộ mô tả tệp tương ứng để trỏ đến một cái gì đó khác. Cú pháp 2>&1
chỉ đơn giản là điểm mô tả 2 đến bất cứ nơi nào 1 điểm. > file.txt
chỉ cần mở file.txt
để viết và để STDOUT (tệp decsriptor 1) trỏ đến đó.
Có một số tính năng khác, ví dụ: 2>(xxx)
(ví dụ: tạo một quy trình mới đang chạy xxx
, tạo một đường ống, kết nối bộ mô tả tệp 0 của quy trình mới với đầu đọc của ống và kết nối bộ mô tả tệp 2 của quy trình ban đầu với đầu ghi của ống).
Đây cũng là cơ sở cho "tệp xử lý ma thuật" trong phần mềm khác ngoài vỏ của bạn. Ví dụ: trong tập lệnh Perl của bạn, dup
hãy mô tả bộ mô tả tệp STDOUT thành một bộ mô tả (tạm thời) khác, sau đó mở lại STDOUT thành một tệp tạm thời mới được tạo. Từ thời điểm này, tất cả đầu ra STDOUT từ tập lệnh Perl của riêng bạn và tất cả các system()
cuộc gọi của tập lệnh đó sẽ kết thúc trong tệp tạm thời đó. Khi hoàn tất, bạn có thể gửi lại dup
STDOUT của mình cho bộ mô tả tạm thời mà bạn đã lưu nó và trước đó, tất cả vẫn như trước. Bạn thậm chí có thể ghi vào bộ mô tả tạm thời trong khi đó, vì vậy trong khi đầu ra STDOUT thực tế của bạn chuyển đến tệp tạm thời, bạn vẫn có thể thực sự xuất nội dung sang STDOUT thực (thông thường, người dùng).
Câu trả lời
Để áp dụng thông tin cơ bản được đưa ra ở trên cho câu hỏi của bạn:
Theo thứ tự nào shell thực hiện các lệnh và chuyển hướng luồng?
Trái sang phải.
<command> > file.txt 2>&1
fork
tắt một quy trình mới.
- Mở
file.txt
và lưu trữ con trỏ của nó trong bộ mô tả tệp 1 (STDOUT).
- Điểm STDERR (mô tả tệp 2) cho bất cứ điều gì fd 1 điểm đến ngay bây giờ (một lần nữa là
file.txt
khóa học đã được mở ).
exec
các <command>
Điều này rõ ràng chuyển hướng thiết bị xuất chuẩn thành thiết bị xuất chuẩn trước, và sau đó thiết bị xuất chuẩn kết quả được chuyển hướng đến file.txt.
Điều này sẽ có ý nghĩa nếu chỉ có một bảng, nhưng như đã giải thích ở trên có hai bảng. Các bộ mô tả tệp không được trỏ vào nhau theo cách đệ quy, sẽ không có ý nghĩa gì khi nghĩ "chuyển hướng STDERR sang STDOUT". Suy nghĩ đúng là "điểm STDERR đến bất cứ nơi nào STDOUT điểm". Nếu bạn thay đổi STDOUT sau đó, STDERR sẽ giữ nguyên vị trí của nó, điều đó không kỳ diệu đi cùng với những thay đổi tiếp theo đối với STDOUT.