Sự khác biệt giữa 2> & 1> output.log và 2> & 1 | đầu ra tee.log


35

Tôi muốn biết sự khác biệt giữa hai lệnh sau

2>&1 > output.log 

2>&1 | tee output.log

Tôi thấy một trong những đồng nghiệp của tôi sử dụng tùy chọn thứ hai để chuyển hướng. Tôi biết 2> & 1 làm gì, câu hỏi duy nhất của tôi là mục đích của việc sử dụng tee nơi toán tử chuyển hướng đơn giản ">" có thể được sử dụng là gì?

Câu trả lời:


11

Nhìn vào hai lệnh riêng biệt:

utility 2>&1 >output.log 

Ở đây, do các chuyển hướng được xử lý theo cách từ trái sang phải, luồng lỗi tiêu chuẩn trước tiên sẽ được chuyển hướng đến bất cứ nơi nào luồng đầu ra tiêu chuẩn đi (có thể đến bàn điều khiển), và sau đó luồng đầu ra tiêu chuẩn sẽ được chuyển hướng đến một tệp. Luồng lỗi tiêu chuẩn sẽ không được chuyển hướng đến tập tin đó.

Hiệu quả có thể nhìn thấy của điều này sẽ là bạn có được những gì được tạo ra do lỗi tiêu chuẩn trên màn hình và những gì được tạo ra trên đầu ra tiêu chuẩn trong tệp.

utility 2>&1 | tee output.log

Tại đây, bạn chuyển hướng lỗi tiêu chuẩn đến cùng một nơi với luồng đầu ra tiêu chuẩn. Điều này có nghĩa là cả hai luồng sẽ được dẫn đến teetiện ích dưới dạng một luồng đầu ra xen kẽ duy nhất và dữ liệu đầu ra tiêu chuẩn này sẽ được lưu vào tệp đã cho tee. Dữ liệu cũng sẽ được sao chép lại teetrong bảng điều khiển (đây là những gì teenó làm, nó sao chép các luồng dữ liệu).

Cái nào được sử dụng tùy thuộc vào những gì bạn muốn đạt được.

Lưu ý rằng bạn sẽ không thể tái tạo hiệu ứng của đường ống thứ hai chỉ bằng >(như trong utility >output.log 2>&1, sẽ lưu cả đầu ra tiêu chuẩn và lỗi trong tệp). Bạn sẽ cần sử dụng teeđể lấy dữ liệu trong bàn điều khiển cũng như trong tệp đầu ra.


Ghi chú bổ sung:

Các thể nhìn thấy ảnh hưởng của lệnh đầu tiên,

utility 2>&1 >output.log 

sẽ giống như

utility >output.log

Tức là, đầu ra tiêu chuẩn đi đến tập tin và lỗi tiêu chuẩn đi đến bàn điều khiển.

Nếu một bước xử lý tiếp theo được thêm vào cuối mỗi lệnh trên, thì sẽ có một sự khác biệt lớn:

utility 2>&1 >output.log | more_stuff

utility >output.log      | more_stuff

Trong đường ống đầu tiên, more_stuffsẽ nhận được luồng lỗi ban đầu từ utilitydữ liệu đầu vào tiêu chuẩn của nó, trong khi ở đường ống thứ hai, vì đó chỉ là luồng đầu ra tiêu chuẩn được gửi qua một đường ống, more_stuffmột phần của đường ống sẽ không nhận được gì để đọc trên đầu vào tiêu chuẩn của nó.


Với lệnh " utility 2>&1 | tee output.log, bạn có nghĩa là nói rằng vì 1 đang được chuyển hướng đến tee, 2 cũng vậy. Vì tee sao chép luồng, đầu ra được hiển thị trên bảng điều khiển cũng như được ghi vào tệp? Do đó, sự khác biệt giữa utility 2>&1 > output.logutility 2>&1 | tee output.logteeở chỗ nó sao chép luồng. Điều đó có đúng không?
động lực

Với các ví dụ về utility 2>&1 > output.log | more_stuffutility >ouput.log| more_ ware more_ , is the difference that ware` có đầu ra lỗi tiêu chuẩn cho bàn điều khiển làm đầu vào more_stuffkhông? Vì trong ví dụ thứ hai, không có đầu ra cho bàn điều khiển, về cơ bản không có đầu vào more_stuff? Nếu có, điều đó không rõ ràng vì đoạn trước bạn lưu ý rằng đầu ra tiêu chuẩn đi đến tệp và lỗi tiêu chuẩn sẽ đến bảng điều khiển.
động lực

@Motivated Nhận xét đầu tiên của bạn có vẻ đúng với tôi, vâng. Đối với nhận xét thứ hai: Trong lệnh đầu tiên, more_stuffsẽ nhận được những gì utilityban đầu được gửi đến luồng lỗi của nó (nhưng được chuyển hướng đến đầu ra tiêu chuẩn). Không phải vì nó sẽ kết thúc trên bàn điều khiển nếu more_stuffkhông có ở đó, mà bởi vì nó sẽ đi đến luồng đầu ra tiêu chuẩn . Trong lệnh thứ hai, khôngmore_stuff nhận được vì không có đầu ra tiêu chuẩn từ phía bên trái của đường ống. Luồng lỗi từ utilityvẫn sẽ kết thúc trên bàn điều khiển trong lệnh thứ 2.
Kusalananda

Cảm ơn. Bạn có nghĩa là bởi vì lệnh utility > output.log | more_stuffkhông dẫn đến một đầu ra trong luồng đầu ra tiêu chuẩn theo quan điểm lỗi tiêu chuẩn?
động lực

@Motivated Vì phía bên trái không tạo ra bất cứ thứ gì trên đầu ra tiêu chuẩn (nó được chuyển hướng), nên sẽ không có dữ liệu nào được gửi qua đường ống.
Kusalananda

24

Biên tập

Hãy chắc chắn để đọc các ý kiến ​​về câu trả lời này - derobert .


Câu trả lời gốc

2>&1 >output.logcó nghĩa là trước tiên bắt đầu gửi tất cả xử lý tệp 2 thứ (lỗi tiêu chuẩn) đến xử lý tệp 1 (đầu ra tiêu chuẩn) sau đó gửi tệp đó đến tệp output.log. Nói cách khác, gửi lỗi tiêu chuẩn và đầu ra tiêu chuẩn đến tệp nhật ký.

2>&1 | tee output.loglà giống nhau với 2>&1bit, nó kết hợp đầu ra tiêu chuẩn và lỗi tiêu chuẩn trên luồng đầu ra tiêu chuẩn. Sau đó, nó dẫn thông qua teechương trình sẽ gửi đầu vào tiêu chuẩn của nó đến đầu ra tiêu chuẩn của nó (như cat) và cả vào tệp. Vì vậy, nó kết hợp hai luồng (lỗi và đầu ra), sau đó xuất nó đến thiết bị đầu cuối và tệp.

Điểm mấu chốt là cái đầu tiên gửi stderr/ stdoutđến tệp, trong khi cái thứ hai gửi nó cho cả tệp và đầu ra tiêu chuẩn ( có lẽ là thiết bị đầu cuối trừ khi bạn ở trong một cấu trúc khác đã chuyển hướng đầu ra tiêu chuẩn).

Tôi đề cập đến khả năng cuối cùng bởi vì bạn có thể có những thứ như:

(echo hello | tee xyzzy.txt) >plugh.txt

nơi không có gì kết thúc trên thiết bị đầu cuối.


13
-1 Bạn có cú pháp đúng, nhưng không phải là ngữ nghĩa. Chạy cat /doesnotexist 2>&1 >output.txt- bạn sẽ thấy cat: /doesnotexist: No such file or directoryhiển thị cho thiết bị đầu cuối và output.txt là một tệp trống. Thứ tự ưu tiên và đóng cửa đang diễn ra: 2>&1(dup fd2 từ fd1 hiện tại ), sau đó >output.txt(chuyển hướng fd1 sang output.txt, không thay đổi bất cứ điều gì khác). Lý do 2>&1 |khác nhau là vì thứ tự ưu tiên: |trước >.
Arcege

5
Câu trả lời này về cơ bản là sai về mọi khía cạnh . Nhiều câu trả lời dưới đây là tốt hơn, nhưng tôi nghĩ câu trả lời này của Kusalananda là rõ ràng nhất.
Michael Homer

2
@ user14408: Nếu bạn đã từng tạo một tài khoản trên Unix & Linux và yêu cầu câu trả lời này, xin vui lòng xóa ghi chú biên tập của tôi sau khi bạn đã giải quyết các bình luận.
derobert

8

Lệnh đầu tiên sẽ thực hiện một nhiệm vụ khác:

Sau

2>&1 > output.log 

STDOUT cũ sẽ được lưu (sao chép) trong STDERR và sau đó STDOUT sẽ được chuyển hướng đến tệp.

Vì vậy, stdout sẽ đi đến tập tin và stderr sẽ vào giao diện điều khiển.

Và trong

 2>&1 | tee output.log

cả hai luồng sẽ được chuyển hướng đến tee. Tee sẽ nhân đôi bất kỳ đầu vào nào cho thiết bị xuất chuẩn của nó (bảng điều khiển trong trường hợp của bạn) và thành tệp ( output.log).

Và có một hình thức khác đầu tiên:

    > output.log  2>&1

điều này sẽ chuyển hướng cả STDOUT và STDERR vào tệp.


4

Các đầu ra trước đây chỉ vào tập tin. Cái thứ hai xuất ra cả tệp màn hình.


4

Lý do 2>&1 | teelà để có thể chụp cả thiết bị xuất chuẩn và thiết bị xuất chuẩn vào một tệp nhật ký và để xem nó trên màn hình cùng một lúc. Điều này cũng có thể được thực hiện >output.txt 2>&1 & tail -f, nhưng bạn sẽ không biết khi nào lệnh nền được kết thúc - là chương trình bị chấm dứt hay nó đang chạy mà không có đầu ra. Đây 2>&1 | teelà một thành ngữ phổ biến cho các lập trình viên.


Bạn có nghĩa là nói rằng 2> & 1> file.txt chẳng hạn sẽ không bắt được cả thiết bị xuất chuẩn và thiết bị xuất chuẩn thành file.txt?
Động lực

0

Trước tiên hãy xem một số mã mẫu:

#include <stdio.h>
main() 
{
// message 1, on stdout (using  printf)
printf("%s",          "message 1, on stdout (using  printf)\n");

// message 2, on stdout (using fprintf)
fprintf(stdout, "%s", "message 2, on stdout (using fprintf)\n");

// message 3, on stderr (using fprintf)
fprintf(stderr, "%s", "message 3, on stderr (using fprintf)\n");
}

Cho phép so sánh kết quả:
./helloerror
+ tệp: không có tin nhắn; bảng điều khiển: tin nhắn 1,2,3;

./helloerror >error.txt
+ tập tin: tin nhắn 1,2; bảng điều khiển: tin nhắn 3;

./helloerror 2>&1 >error.txt
+ tập tin: tin nhắn 1,2; bảng điều khiển: tin nhắn 3;
+ giống như ./helloerror> error.txt

./helloerror >error.txt 2>&1
+ tệp: tin nhắn 3,1,2; bàn điều khiển: không có tin nhắn;
+ lưu ý thứ tự 3 là đầu tiên, sau đó 1, sau đó 2

./helloerror | tee error.txt 2>&1
+ tập tin: tin nhắn 1,2; bảng điều khiển: tin nhắn 3,1,2;
+ lưu ý thứ tự 3 là đầu tiên, sau đó 1, sau đó 2

./helloerror 2>&1 | tee error.txt
+ tệp: tin nhắn 3,1,2; bảng điều khiển: tin nhắn 3,1,2;

Để sử dụng:
./helloerror >error.txt 2>&1
-> nếu ai đó muốn tất cả các thông báo (stdout + stderr) trong tệp, nhưng không bị xóa trên bảng điều khiển

./helloerror 2>&1 | tee error.txt
-> nếu ai đó muốn tất cả các thông báo (stdout + stderr) trong tệp và được in trên bảng điều khiển


-1

Dưới đây là một bài viết tóm tắt các luồng đầu ra Unix: http://www.devcodenote.com/2015/04/unix-output-streams.html

Một đoạn trích từ bài viết:

Có 3 luồng đầu ra tiêu chuẩn:

STDIN - Standard Input - Writes from an input device to the program
STDOUT - Standard Output - Writes program output to screen unless specified otherwise.
STDERR - Standard Error Output - Writes error messages. Also printed to the screen unless specified otherwise.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.