Đường ống là | danh sách giới hạn lệnh. Bất kỳ chuyển hướng nào bạn chỉ định áp dụng cho các lệnh cấu thành (đơn giản hoặc hợp chất), nhưng không áp dụng cho toàn bộ đường dẫn. Mỗi chuỗi ống một lệnh của stdout để stdin của tiếp theo bằng cách ngầm áp dụng một chuyển hướng cho mỗi subshell trước khi bất kỳ chuyển hướng nào liên kết với một lệnh được đánh giá.
cmd 2>&1 | less
Giá trị đầu tiên của phân đoạn đầu tiên được chuyển hướng đến đường ống mà từ đó less
đang đọc. Tiếp theo, chuyển hướng 2>&1
được áp dụng cho lệnh đầu tiên. Việc chuyển hướng stderr sang stdout hoạt động vì stdout đã trỏ vào đường ống.
cmd | less 2>&1
Ở đây, chuyển hướng áp dụng cho less
. Stdout và stderr ít hơn cả hai có lẽ bắt đầu ra chỉ vào thiết bị đầu cuối, do đó, 2>&1
trong trường hợp này không có hiệu lực.
Nếu bạn muốn có một chuyển hướng để áp dụng cho toàn bộ đường ống, để nhóm nhiều lệnh như một phần của đường ống, hoặc ống dẫn tổ, sau đó sử dụng một nhóm lệnh (hoặc bất kỳ khác hợp chất lệnh):
{ { cmd1 >&3; cmd2; } 2>&1 | cmd3; } 3>&2
Có thể là một ví dụ điển hình. Kết quả cuối cùng là: cmd1
và cmd2
's stderr ->cmd3
; cmd2
's stdout ->cmd3
; và mã thông báo của cmd1
và cmd3
và một số thiết bị đầu cuối -> thiết bị đầu cuối.
Nếu bạn sử dụng ống |&
đặc trưng của Bash, mọi thứ trở nên lạ lẫm hơn, vì mỗi chuyển hướng stdout của đường ống vẫn xảy ra trước, nhưng chuyển hướng stderr thực sự đến cuối cùng. Ví dụ:
f() { echo out; echo err >&2; }; f >/dev/null |& cat
Hiện tại, tất cả đầu ra đều bị ẩn. Đường ra đầu tiên của f
đi tới đường ống, đường ra tiếp theo của f
được chuyển hướng đến /dev/null
và cuối cùng, stderr được chuyển hướng tới thiết bị xuất chuẩn (vẫn còn /dev/null
).
Tôi khuyên bạn không bao giờ sử dụng |&
trong Bash - nó được sử dụng ở đây để trình diễn.
+1 cũng được giải thích – jordanm
+1. Điều duy nhất tôi muốn thêm là một đường ống là một dấu tách lệnh, giống như dấu chấm phẩy. –
+1 Wow, câu trả lời tuyệt vời @ormaaj! Chính xác những gì tôi đang tìm kiếm - cảm ơn bạn! –