Các báo cáo tiến độ / thông tin đăng nhập thuộc về stderr hoặc stdout?


75

Có một POSIX, GNU hoặc hướng dẫn chính thức nào về nơi báo cáo tiến trình và thông tin đăng nhập (những thứ như "Làm foo; foo xong") nên được in không? Cá nhân, tôi có xu hướng viết chúng vào thiết bị xuất chuẩn để tôi có thể chuyển hướng thiết bị xuất chuẩn và chỉ nhận đầu ra thực tế của chương trình. Gần đây tôi đã nói rằng đây không phải là thông lệ tốt vì các báo cáo tiến độ không thực sự có lỗi và chỉ nên in thông báo lỗi cho thiết bị lỗi chuẩn.

Cả hai vị trí đều có ý nghĩa, và tất nhiên bạn có thể chọn cái này hay cái kia tùy thuộc vào chi tiết của những gì bạn đang làm, nhưng tôi muốn biết liệu có một tiêu chuẩn thường được chấp nhận cho việc này không. Tôi chưa thể tìm thấy bất kỳ quy tắc cụ thể nào trong POSIX, các tiêu chuẩn mã hóa GNU hoặc bất kỳ danh sách thực tiễn tốt nhất nào được chấp nhận rộng rãi như vậy.

Chúng tôi có một vài câu hỏi tương tự, nhưng chúng không giải quyết được vấn đề chính xác này:

Vì vậy, có bất kỳ quy tắc chính thức nào về nơi báo cáo tiến độ và thông báo thông tin khác (không phải là một phần của đầu ra thực tế của chương trình) nên được in không?


26
In spinners và muốn stdoutcùng với kết quả là một cách an toàn để làm cho kết quả vô dụng. Nếu bạn cần chuyển kết quả sang một số chương trình khác, chương trình cho biết sẽ cần tách kết quả khỏi các spinners. Ngoài ra, nếu bạn chuyển hướng đầu ra sang một tệp, bạn sẽ không thể thấy các spinners. IMHO.
Satō Katsura

2
@SatoKatsura yeah, đó cũng là ý kiến ​​của tôi và đó là lý do tại sao tôi in như vậy cho stderr. CTO của công ty tôi làm việc, tuy nhiên, cảm thấy rằng in ra stderr là một dấu hiệu cho thấy có gì đó không ổn. Tôi đã đưa ra, khá táo bạo, tuyên bố rằng POSIX Way® đang in ra stderr và anh ấy đã gọi tôi ra. Cho rằng anh ta có 20 năm kinh nghiệm đối với tôi, tôi muốn xem liệu tôi có thể tìm thấy một số hướng dẫn "chính thức" không.
terdon

giống như Sato Katsura đã nói, stdoutthực sự là một cách an toàn và đúng đắn để pringing spinners và các thông điệp thông tin khác, nhưng như nhiều lập trình viên nói 'Im lặng là vàng. Đầu ra không có gì nếu mọi thứ đều ổn. ' Vì vậy, trên thực tế, stderr luôn được sử dụng để làm điều đó vì định nghĩa mơ hồ và cũng là thiết bị xuất chuẩn có thể phá vỡ chuỗi ống. Đối với hướng dẫn chính thức
Se ven

6
@Seven Tôi nghĩ bạn hiểu lầm; Sato đang nói rằng sử dụng thiết bị xuất chuẩn là không an toàn ("cách an toàn để làm cho kết quả trở nên vô dụng").
Stephen Kitt

1
Một giải pháp phù hợp với một kích thước có thể sẽ chỉ được sử dụng stderrđể báo cáo các thông báo lỗi, ngoại trừ khi --verbosesử dụng cờ, tại đó cũng bao gồm các báo cáo tiến trình.
Gaurav

Câu trả lời:


27

Posix định nghĩa các luồng tiêu chuẩn, do đó :

Khi khởi động chương trình, ba luồng phải được xác định trước và không cần phải mở một cách rõ ràng: đầu vào tiêu chuẩn (để đọc đầu vào thông thường), đầu ra tiêu chuẩn (để ghi đầu ra thông thường) và lỗi tiêu chuẩn (để ghi đầu ra chẩn đoán). Khi mở, luồng lỗi tiêu chuẩn không được đệm hoàn toàn; các luồng đầu vào tiêu chuẩn và đầu ra tiêu chuẩn được đệm hoàn toàn khi và chỉ khi luồng có thể được xác định không tham chiếu đến một thiết bị tương tác.

Các thư viện GNU C mô tả các dòng tiêu chuẩn tương tự:

Biến: FILE * stdout
Luồng đầu ra tiêu chuẩn, được sử dụng cho đầu ra bình thường từ chương trình.

Biến: FILE * stderr
Luồng lỗi tiêu chuẩn, được sử dụng cho các thông báo lỗi và chẩn đoán do chương trình ban hành.

Do đó, các định nghĩa tiêu chuẩn có rất ít hướng dẫn cho việc sử dụng luồng ngoài đầu ra thông thường / đầu ra bình thường và đầu ra chẩn đoán / lỗi thông thường. Và trong thực tế, thông thường để chuyển hướng một hoặc cả hai luồng này sang tệp và đường ống, trong đó các chỉ số tiến trình sẽ là một vấn đề . Một số hệ thống thậm chí giám sát stderr đầu ra và coi đó là dấu hiệu của sự cố. Do đó, thông tin hoàn toàn phụ trợ là vấn đề trên cả hai luồng.

Thay vì gửi các chỉ báo tiến trình vô điều kiện đến một luồng tiêu chuẩn, điều quan trọng là phải nhận ra rằng đầu ra tiến độ chỉ phù hợp với các luồng tương tác . Với ý nghĩ đó, tôi khuyên bạn chỉ nên viết bộ đếm tiến trình sau khi kiểm tra xem luồng có tương tác (ví dụ: với isatty()) hoặc khi được bật rõ ràng bằng tùy chọn dòng lệnh. Điều đó đặc biệt quan trọng đối với các máy đo tiến độ dựa trên hành vi cập nhật thiết bị đầu cuối để có ý nghĩa, như các thanh% -complete.

Đối với một số thông báo tiến trình rất đơn giản (Bắt đầu từ X X ... ... Xong với X,) hợp lý hơn là bao gồm đầu ra ngay cả đối với các luồng không tương tác. Trong trường hợp đó, hãy xem xét cách người dùng có thể tương tác với các luồng, như tìm kiếm grephoặc phân trang với lesshoặc theo dõi tail -f. Nếu có ý nghĩa để xem các thông điệp tiến bộ trong các bối cảnh đó, chúng sẽ dễ tiêu thụ hơn nhiều stdout.


Cảm ơn, hướng dẫn GNU là thứ tôi đang theo đuổi. Tuy nhiên, tôi nhận ra câu hỏi của tôi có một chút sai lệch. Khi tôi đề cập đến "báo cáo tiến độ", tôi đã nghĩ về cả những thứ như N% donevà những thứ như doing foofoo done. Cái sau phải luôn được giữ vì chúng được sử dụng để gỡ lỗi khi được chuyển hướng đến một tệp. Vì vậy, đề xuất của bạn về việc kiểm tra xem luồng có tương tác không được áp dụng (mặc dù nói chung là một ý tưởng rất tốt).
terdon

À cảm ơn vì đã làm rõ, điều đó hơi khác một chút so với những thứ như thanh %% hoàn thành và các thanh tiến trình đánh dấu băm mà bạn thấy trong phần mềm như curlyum. Trong trường hợp đó, tôi sẽ suy nghĩ về việc và cách người dùng muốn tương tác với đầu ra thông qua grephoặc lesshoặc các công cụ tương tự.
Bradd Szonye

Cập nhật câu trả lời để kết hợp làm rõ ở trên.
Bradd Szonye

71

POSIX định nghĩa lỗi tiêu chuẩn là

để viết đầu ra chẩn đoán

Điều này không giới hạn việc sử dụng nó chỉ thông báo lỗi. Tôi sẽ coi thông tin tiến trình là đầu ra chẩn đoán, vì vậy nó thuộc về lỗi tiêu chuẩn.


8
FWIW, trong Python, stdoutđược đệm theo mặc định trong khi không stderrcó bộ đệm , do đó, stderrlà lựa chọn tự nhiên để viết văn bản / thanh / spinners tiến trình không chứa dòng mới. (Nếu bạn viết văn bản như vậy vào, stdoutbạn cần làm lộn xộn các cuộc gọi đầu ra tiến trình của mình stdout.flush()để làm cho nó hiển thị).
PM 2Ring

12
@ PM2Ring không dành riêng cho Python, POSIX định nghĩa các luồng theo cách đó.
Stephen Kitt

4
@ PM2Ring: Khi viết thư stdout, bạn cần xóa ngay cả khi văn bản của bạn chứa một dòng mới nếu bạn muốn báo cáo tiến độ của bạn thực sự hiển thị trong thời gian thực khi được chuyển hướng.

@Hurkyl Ah, điểm tốt. Tôi đã không xem xét chuyển hướng.
PM 2Ring

1
@Wtower, hả? Không. Ansible nuốt văn bản stderr nếu trạng thái thoát là 0. Yêu cầu đó đơn giản là sai.
Charles Duffy

10

POSIX cụ thể hơn một chút về "thông tin chẩn đoán" trong Shell và Tiện ích , 1.4: Mặc định Mô tả Tiện ích (nhấn mạnh của tôi):

ĐẶT HÀNG

Phần STDERR mô tả đầu ra lỗi tiêu chuẩn của tiện ích. Chỉ những tin nhắn được gửi có chủ ý bởi tiện ích được mô tả. Việc sử dụng thiết bị đầu cuối cho lỗi tiêu chuẩn có thể khiến bất kỳ tiện ích tiêu chuẩn nào ghi đầu ra lỗi tiêu chuẩn dừng lại khi được sử dụng trong nền. Vì lý do này, các ứng dụng không nên sử dụng các tính năng tương tác trong các tập lệnh được đặt trong nền.

Định dạng của thông báo chẩn đoán cho hầu hết các tiện ích là không xác định, nhưng các quy ước về ngôn ngữ và văn hóa của thông báo chẩn đoán và thông tin có định dạng không được xác định bởi tập POSIX.1-2008 này sẽ bị ảnh hưởng bởi cài đặt LC_MESSAGES và [XSI] [Tùy chọn Bắt đầu ] NỀN TẢNG. [Kết thúc tùy chọn]

Đầu ra lỗi tiêu chuẩn được chỉ định của các tiện ích tiêu chuẩn sẽ không phụ thuộc vào sự tồn tại hoặc giá trị của các biến môi trường được xác định trong tập POSIX.1-2008 này, trừ khi được cung cấp bởi tập POSIX.1-2008 này.

Hành vi mặc định : Khi phần này được liệt kê là "Lỗi tiêu chuẩn chỉ được sử dụng cho các thông báo chẩn đoán.", Điều đó có nghĩa là, trừ khi có quy định khác, các thông báo chẩn đoán chỉ được gửi đến lỗi tiêu chuẩn khi trạng thái thoát cho biết có lỗi đã xảy ra và tiện ích được sử dụng như được mô tả bởi tập POSIX.1-2008 này.

Khi phần này được liệt kê là "Không được sử dụng.", Điều đó có nghĩa là lỗi tiêu chuẩn sẽ không được sử dụng khi tiện ích được sử dụng như được mô tả trong tập POSIX.1-2008 này.

IANASL, nhưng tôi giải thích điều đó có nghĩa là stderr sẽ chỉ có đầu ra nếu tiện ích sẽ trả về mã thoát lỗi. Vì đây không phải là tiến trình thông thường để thực hiện thành công, nên không có thông tin tiến trình nào được in bởi tiện ích POSIX trừ khi xảy ra lỗi (tất nhiên trừ khi có quy định khác, v.v.).


Tôi hiểu điều này khi mô tả ý nghĩa của phần "STDERR" được nêu trong thông số kỹ thuật của từng tiện ích POSIX, không phải là định nghĩa chung cho việc sử dụng lỗi tiêu chuẩn. Tôi không nghĩ terdon đang viết một tiện ích POSIX tiêu chuẩn ở đây ;-).
Stephen Kitt

1
@StephenKitt cũng không làm tôi. Nhưng anh ấy đang tranh luận với CTO của mình, anh ấy nói rằng đầu ra stderr là một dấu hiệu cho thấy có gì đó không ổn và tiêu chuẩn không hỗ trợ cho yêu cầu của anh ấy như là hành vi mặc định.
muru

1
Nó chỉ hỗ trợ khiếu nại như hành vi mặc định cho các tiện ích POSIX và thậm chí sau đó chỉ trong các trường hợp cụ thể (các tiện ích sử dụng cụm từ được đề cập). Phần này của POSIX không phải là quy tắc (AIUI), nó là một mẫu: nó cho bạn biết cách đọc các thông số kỹ thuật của tiện ích, nó không chỉ định hành vi của các tiện ích. Cụ thể, nó xác định ý nghĩa của cụm từ "Lỗi tiêu chuẩn chỉ được sử dụng cho các thông báo chẩn đoán." và "Không được sử dụng." trong phần "STDERR" của thông số kỹ thuật tiện ích. Mỗi tiện ích chỉ định hành vi của nó và nó có thể sử dụng các cụm từ đó làm tốc ký.
Stephen Kitt

@StephenKitt không thay đổi quan điểm của tôi. Các tiện ích POSIX hoặc a) không xuất ra stderr, b) chỉ sử dụng nó cho các thông báo chẩn đoán nếu có sự cố, c) chỉ sử dụng nó cho các thông báo chẩn đoán ngay cả khi không có gì sai và d) sử dụng nó cho mục đích khác. Tôi đã nói rằng họ chỉ sử dụng nó cho các thông báo chẩn đoán nếu có sự cố xảy ra (a, b), trừ khi có quy định khác (c, d). Bây giờ, yêu cầu của tôi là đây là mặc định, rõ ràng là như vậy, vì đó là lý do tại sao nó là mẫu.
muru

2
Chà, tôi muốn nói rằng "trừ khi có quy định khác" là một cảnh báo khá quan trọng: tiện ích POSIX rất có thể chỉ định rằng nó đưa ra thông tin tiến trình về lỗi tiêu chuẩn của nó và nó sẽ tuân thủ các tiêu chuẩn. Bạn nói đúng, điều thú vị là "hành vi mặc định" (vẫn yêu cầu một đề cập cụ thể trong phần có liên quan) là chỉ sử dụng lỗi tiêu chuẩn nếu mã thoát cũng chỉ ra lỗi; nhưng nó không giới hạn.
Stephen Kitt

7

Theo nguyên tắc loại trừ, nó chỉ có thể đi đến stderr. Vâng, tôi biết bạn đã hỏi về một đặc điểm kỹ thuật chính thức, mà tôi không thể đưa ra cho bạn ngoài liên kết đến đặc tả POSIX, được đưa ra bởi Stephen Kitt, trong đó tuyên bố rằng stderr là dành cho mục đích chẩn đoán.

Điểm quan trọng hơn là stdin và stdout có chức năng không cho phép báo cáo tiến trình in ra thiết bị xuất chuẩn - tất nhiên chúng tạo thành chuỗi các đường ống mà trong các lệnh shell Unix không chỉ là tác dụng phụ, mà là cốt lõi của cách tiếp cận đường ống mạnh mẽ .

Vì thế. Không có gì ngoại trừ "tải trọng" thực sự của chương trình của bạn thuộc về thiết bị xuất chuẩn. Nếu chương trình của bạn không có đầu ra, thì không có gì nên vào stdout. Điều này để lại stderr cho mọi thứ khác , bao gồm các báo cáo tiến độ.

Cấp, điều này để lại một lỗ hổng - có lẽ sẽ rất tốt nếu có một "stdfluff" hoặc một cái gì đó tương tự không phải là đầu ra cũng không phải lỗi mà là báo cáo tiến trình, gỡ lỗi và somesuch. Trong thực tế, không có gì ngăn bạn làm điều đó, tức là, bạn có thể in tiến trình của mình để mô tả tệp 3. Ví dụ:

$ perl -e 'open($fd, ">", "/dev/fd/3"); print $fd "hello\n"'

Điều này tạo ra không có đầu ra. (*)

$ perl -e 'open($fd, ">", "/dev/fd/3"); print $fd "hello\n"'  3>&1
hello

Điều này in ra fd-3, được chuyển hướng đến thiết bị xuất chuẩn.

(*) Ví dụ đầu tiên không tạo ra đầu ra nhưng vẫn hơi xa; sự openthất bại và $!sẽ chứa đựng no such file or directory; chỉ cần lấy điều này làm ví dụ, tất nhiên không nên sử dụng như thế này một cách nghiêm túc. Trong một chương trình thực tế, nếu bạn muốn đi theo lộ trình này, bạn có thể kiểm tra xem /dev/fd/3có thể sử dụng được không và lấy đây làm gợi ý về việc có nên kích hoạt báo cáo tiến độ của bạn hay không; bạn phải làm điều đó khá sớm để bạn không bị nhầm lẫn bởi chính bạn openđối với các tệp thực và ...


fd-3gì Đĩa mềm thứ ba?
Peter Mortensen

mô tả tệp 3, @PeterMortensen
AnoE

-1

Thông báo sử dụng sẽ đi đến thiết bị xuất chuẩn nếu người dùng đã gọi nó --helpvà gửi thông báo nếu họ mắc lỗi. In nó ra stderr vô điều kiện là đáng ghét vì nó làm cho việc xem nó với máy nhắn tin / grep / vv trở nên khó khăn hơn.

Ngoài ra, tôi có thể đề xuất một cách thứ ba: open / dev / tty cho các báo cáo tiến độ / spinners / vv.


6
Xin lỗi, nhưng điều này không trả lời câu hỏi. Tôi đặc biệt yêu cầu hướng dẫn chính thức , không ý kiến. Trong mọi trường hợp, ngay cả khi tôi đã hỏi ý kiến, bạn đang trả lời một câu hỏi khác. Tôi không nói về --helphoặc giúp đỡ tin nhắn nào cả. Xin vui lòng đọc lại câu hỏi.
terdon

Bạn đã đề cập đến "thông điệp sử dụng", tôi nghĩ đó là một phần câu hỏi của bạn chứ không chỉ là tiêu đề của câu hỏi khác mà bạn liên kết. Tôi không hiểu tại sao bạn nghĩ rằng "hướng dẫn chính thức" tồn tại cho việc này. Ai sẽ có thẩm quyền để làm cho họ?
Random832

3
Tôi không biết rằng họ làm, đó là lý do tại sao tôi hỏi. Và như chính thức, tiêu chuẩn POSIX có thông số kỹ thuật cho các chi tiết khác nhau về cách thức hoạt động của một chương trình. Bao gồm, như Stephen đã chỉ ra trong câu trả lời của mình, một gợi ý mơ hồ cho những gì nên đến stderr. Tiêu chuẩn mã hóa GNU cũng có thể có một cái gì đó tương tự. Về cơ bản, bất kỳ nhóm nào đang hoạt động và tạo mã cho hệ sinh thái * nix đều có thể có một tiêu chuẩn mà tôi quan tâm.
terdon

@terdon bạn có ổn không với các ví dụ về những chương trình hiện có làm gì? curl, wget, và pv đều sử dụng stderr, với wget và pv làm cho nó có điều kiện trên đó là một tty và curl làm cho nó có điều kiện trên stdout không phải là tty.
Random832

4
Ngoài ra, có vẻ như CTO của bạn nghĩ rằng một chương trình gọi sẽ phản ứng với sự hiện diện của dữ liệu trên thiết bị lỗi như có nghĩa là đã xảy ra lỗi, thay vì nhìn vào trạng thái thoát. Đây chắc chắn là một thực hành tồi (và cũng khó viết hơn là kiểm tra trạng thái thoát) và có thể là một góc độ tốt hơn để thuyết phục anh ta từ đó.
Random832
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.