Apakah laporan kemajuan / informasi logging milik stderr atau stdout?

75

Apakah ada POSIX, GNU resmi, atau pedoman lain di mana laporan kemajuan dan informasi logging (hal-hal seperti "Melakukan foo; foo dilakukan") harus dicetak? Secara pribadi, saya cenderung menulisnya ke stderr sehingga saya bisa mengarahkan ulang stdout dan hanya mendapatkan output aktual program. Saya baru-baru ini diberitahu bahwa ini bukan praktik yang baik karena laporan kemajuan sebenarnya bukan kesalahan dan hanya pesan kesalahan yang harus dicetak ke stderr.

Kedua posisi tersebut masuk akal, dan tentu saja Anda dapat memilih satu atau yang lain tergantung pada rincian apa yang Anda lakukan, tetapi saya ingin tahu apakah ada standar yang berlaku umum untuk ini. Saya belum dapat menemukan aturan khusus dalam POSIX, standar pengkodean GNU, atau daftar praktik terbaik lainnya yang diterima secara luas.

Kami memiliki beberapa pertanyaan serupa, tetapi mereka tidak membahas masalah yang tepat ini:

Jadi, apakah ada aturan resmi tentang di mana laporan kemajuan dan pesan informatif lainnya (yang bukan bagian dari hasil aktual program) harus dicetak?

terdon
sumber
26
Mencetak pemintal dan sejenisnya untuk stdoutbersama-sama dengan hasilnya adalah cara yang aman untuk membuat hasil tidak berguna. Jika Anda perlu menyalurkan hasilnya ke beberapa program lain, program tersebut perlu memisahkan hasil dari pemintal. Juga, jika Anda mengarahkan output ke file Anda tidak akan dapat melihat pemintal. MENURUT OPINI SAYA.
Satō Katsura
2
@SatoKatsura ya, itu pendapat saya juga dan itulah mengapa saya mencetak stderr. CTO perusahaan tempat saya bekerja, bagaimanapun, merasa bahwa mencetak ke stderr merupakan indikasi bahwa ada yang tidak beres. Saya membuat klaim yang agak berani, bahwa POSIX Way® mencetak ke stderr dan dia memanggil saya untuk menggunakannya. Mengingat dia memiliki 20 tahun pengalaman aneh pada saya, saya ingin melihat apakah saya dapat menemukan semacam pedoman "resmi".
terdon
sama seperti yang dikatakan Sato Katsura, stdoutsebenarnya adalah cara yang aman dan benar untuk melakukan pringting pemintal dan pesan informatif lainnya, tetapi seperti yang dikatakan banyak programmer, 'Diam adalah emas. Tidak menghasilkan apa-apa jika semuanya baik-baik saja. ' jadi pada kenyataannya, stderr selalu digunakan untuk melakukan itu karena definisi yang kabur dan juga stdout dapat memutus urutan pipa. untuk panduan resmi
Se ven
6
@ Bahkan saya pikir Anda salah paham; Sato mengatakan bahwa menggunakan stdout tidak aman ("cara aman untuk membuat hasil tidak berguna").
Stephen Kitt
1
Salah satu solusi satu-ukuran-cocok-untuk-semua hanya akan digunakan stderruntuk melaporkan pesan kesalahan, kecuali ketika --verbosebendera digunakan, di mana titik laporan kemajuan disertakan juga.
Gaurav

Jawaban:

27

Posix mendefinisikan stream standar sebagai berikut :

Pada awal program, tiga aliran harus ditentukan sebelumnya dan tidak perlu dibuka secara eksplisit: input standar (untuk membaca input konvensional), output standar (untuk penulisan output konvensional), dan standard error (untuk penulisan output diagnostik). Ketika dibuka, aliran kesalahan standar tidak sepenuhnya buffer; input standar dan output stream standar sepenuhnya buffered jika dan hanya jika aliran dapat ditentukan untuk tidak merujuk ke perangkat interaktif.

The GNU C Library menggambarkan aliran standar yang sama:

Variabel: FILE * stdout
Aliran keluaran standar, yang digunakan untuk keluaran normal dari program.

Variabel: FILE * stderr
Aliran kesalahan standar, yang digunakan untuk pesan kesalahan dan diagnostik yang dikeluarkan oleh program.

Dengan demikian, definisi standar memiliki sedikit panduan untuk penggunaan aliran di luar "keluaran konvensional / normal" dan "keluaran diagnostik / kesalahan." Dalam praktiknya, biasanya mengarahkan ulang salah satu atau kedua aliran ini ke file dan saluran pipa, di mana indikator kemajuan akan menjadi masalah . Beberapa sistem bahkan memantau stderr output dan menganggapnya sebagai tanda masalah. Oleh karena itu, informasi kemajuan yang bersifat tambahan murni bermasalah di kedua aliran.

Alih-alih mengirim indikator kemajuan tanpa syarat kepada salah aliran standar, penting untuk mengenali bahwa kemajuan output hanya sesuai untuk interaktif sungai. Dengan mengingat hal itu, saya merekomendasikan penulisan penghitung kemajuan hanya setelah memeriksa apakah aliran itu interaktif (misalnya, dengan isatty()) atau ketika diaktifkan secara eksplisit oleh opsi baris perintah. Itu sangat penting untuk pengukur kemajuan yang mengandalkan perilaku pembaruan terminal agar masuk akal, seperti% -complete bar.

Untuk pesan kemajuan tertentu yang sangat sederhana ("Memulai X" ... "Selesai dengan X") lebih masuk akal untuk memasukkan output bahkan untuk stream non-interaktif. Dalam hal itu, pertimbangkan bagaimana pengguna dapat berinteraksi dengan stream, seperti mencari dengan grepatau paging dengan lessatau memantau tail -f. Jika masuk akal untuk melihat pesan kemajuan dalam konteks itu, mereka akan lebih mudah untuk dikonsumsi stdout.

Bradd Szonye
sumber
Terima kasih, pedoman GNU adalah hal yang saya cari. Namun, saya menyadari pertanyaan saya agak menyesatkan. Ketika saya menyebutkan "laporan kemajuan", saya memikirkan hal-hal seperti N% donedan hal-hal seperti doing foodan foo done. Yang terakhir harus selalu disimpan karena digunakan untuk debugging ketika diarahkan ke file. Jadi saran Anda untuk memeriksa apakah aliran itu interaktif tidak berlaku (meskipun umumnya ide yang sangat bagus).
terdon
Ah terima kasih atas klarifikasi, itu sedikit berbeda dari hal-hal seperti "% complete" dan bilah kemajuan tanda-hash yang Anda lihat pada perangkat lunak seperti curldan yum. Dalam hal ini, saya akan berpikir tentang apakah dan bagaimana pengguna ingin berinteraksi dengan output melalui grepatau lessatau alat serupa.
Bradd Szonye
Jawaban yang diperbarui untuk memasukkan klarifikasi di atas.
Bradd Szonye
71

POSIX mendefinisikan kesalahan standar sebagai

untuk menulis keluaran diagnostik

Ini tidak membatasi penggunaannya untuk pesan kesalahan saja. Saya akan mempertimbangkan informasi kemajuan sebagai hasil diagnostik, jadi itu milik kesalahan standar.

Stephen Kitt
sumber
8
FWIW, dalam Python, stdoutadalah buffer-line secara default sedangkan stderrunbuffered, jadi stderradalah pilihan alami untuk menulis teks / bar / pemintal kemajuan yang tidak mengandung baris baru. (Jika Anda menulis teks seperti itu pada stdoutAnda perlu mengacaukan panggilan output kemajuan Anda dengan stdout.flush()membuatnya terlihat).
PM 2Ring
12
@ PM2Ring yang tidak khusus untuk Python, POSIX mendefinisikan aliran seperti itu.
Stephen Kitt
4
@ PM2Ring: Saat menulis stdout, Anda perlu menyiram bahkan jika teks Anda mengandung baris baru jika Anda ingin laporan kemajuan Anda benar-benar muncul secara real time saat diarahkan.
@Hurkyl Ah, poin bagus. Saya tidak mempertimbangkan pengalihan.
PM 2Ring
1
@ Power, ya? Tidak. Anonim menelan teks stderr jika status keluar adalah 0. Klaim itu salah.
Charles Duffy
10

POSIX sedikit lebih konkret tentang "informasi diagnostik" di Shell dan Utilities , 1.4: Default Deskripsi Utilitas (penekanan tambang):

STDERR

Bagian STDERR menjelaskan output kesalahan standar dari utilitas. Hanya pesan-pesan yang sengaja dikirim oleh utilitas yang dijelaskan. Penggunaan terminal untuk kesalahan standar dapat menyebabkan utilitas standar yang menulis output kesalahan standar berhenti saat digunakan di latar belakang. Untuk alasan ini, aplikasi tidak boleh menggunakan fitur interaktif dalam skrip untuk ditempatkan di latar belakang.

Format pesan diagnostik untuk sebagian besar utilitas tidak ditentukan, tetapi konvensi bahasa dan budaya pesan diagnostik dan informatif yang formatnya tidak ditentukan oleh volume POSIX.1-2008 ini harus dipengaruhi oleh pengaturan LC_MESSAGES dan [XSI] [Opsi Mulai ] NLSPATH. [Opsi Berakhir]

Keluaran kesalahan standar yang ditentukan dari utilitas standar tidak akan bergantung pada keberadaan atau nilai variabel lingkungan yang didefinisikan dalam volume POSIX.1-2008 ini, kecuali sebagaimana ditentukan oleh volume POSIX.1-2008 ini.

Perilaku Default : Ketika bagian ini terdaftar sebagai "Kesalahan standar hanya akan digunakan untuk pesan diagnostik.", Itu berarti bahwa, kecuali dinyatakan lain, pesan diagnostik harus dikirim ke kesalahan standar hanya ketika status keluar menunjukkan bahwa kesalahan terjadi dan utilitas digunakan seperti yang dijelaskan oleh volume POSIX.1-2008 ini.

Ketika bagian ini terdaftar sebagai "Tidak digunakan.", Itu berarti bahwa kesalahan standar tidak akan digunakan ketika utilitas digunakan seperti yang dijelaskan dalam volume POSIX.1-2008 ini.

IANASL, tetapi saya menafsirkan bahwa itu berarti stderr akan memiliki output hanya jika utilitas akan mengembalikan kode keluar kesalahan. Karena ini seharusnya bukan jalannya peristiwa yang normal untuk eksekusi yang sukses, tidak ada informasi kemajuan yang harus dicetak oleh utilitas POSIX kecuali ada kesalahan (kecuali, tentu saja, ditentukan lain, dll.).

muru
sumber
Saya mengerti ini sebagai menggambarkan arti dari bagian "STDERR" yang diberikan dalam spesifikasi setiap utilitas POSIX, bukan sebagai definisi umum untuk penggunaan kesalahan standar. Saya tidak berpikir terdon menulis utilitas POSIX standar di sini ;-).
Stephen Kitt
1
@StephenKitt juga tidak. Tapi dia berdebat dengan CTO-nya, yang mengatakan bahwa output stderr merupakan indikasi sesuatu yang salah, dan standar mendukung klaimnya sebagai perilaku default.
muru
1
Ini hanya mendukung klaim sebagai perilaku default untuk utilitas POSIX , dan itupun hanya dalam kasus tertentu (utilitas yang menggunakan frasa yang disebutkan). Bagian dari POSIX ini tidak normatif (AIUI), ini adalah templat: memberi tahu Anda cara membaca spesifikasi utilitas, ini tidak menentukan perilaku utilitas. Secara khusus, ini mendefinisikan arti dari frasa "Kesalahan standar hanya akan digunakan untuk pesan diagnostik." dan "Tidak digunakan." di bagian "STDERR" dari spesifikasi utilitas. Setiap utilitas menentukan perilakunya, dan dapat menggunakan frasa tersebut sebagai singkatan.
Stephen Kitt
@StephenKitt yang tidak mengubah poin saya. Utilitas POSIX baik a) jangan output ke stderr, b) menggunakannya hanya untuk pesan diagnostik jika ada masalah, c) menggunakannya hanya untuk pesan diagnostik bahkan jika tidak ada yang salah dan d) menggunakannya untuk sesuatu yang lain. Saya mengatakan bahwa mereka hanya menggunakannya untuk pesan diagnostik jika terjadi kesalahan (a, b), kecuali dinyatakan sebaliknya (c, d). Sekarang, klaim saya adalah bahwa ini adalah default, yang jelas, karena itulah templatnya.
muru
2
Yah, saya akan mengatakan "kecuali ditentukan lain" adalah peringatan yang agak signifikan: utilitas POSIX sangat bisa menentukan bahwa itu menghasilkan informasi kemajuan pada kesalahan standar, dan itu akan memenuhi standar. Anda benar, menarik bahwa "perilaku default" (yang masih memerlukan penyebutan khusus di bagian yang relevan) adalah hanya menggunakan kesalahan standar jika kode keluar juga menunjukkan kesalahan; tapi itu tidak membatasi.
Stephen Kitt
7

Dengan prinsip pengecualian, itu hanya bisa pergi ke stderr. Ya, saya tahu Anda bertanya tentang spesifikasi resmi, yang tidak dapat saya tampilkan di luar tautan ke spesifikasi POSIX, yang diberikan oleh Stephen Kitt, yang menyatakan bahwa stderr adalah untuk tujuan diagnostik.

Poin yang lebih penting adalah stdin dan stdout memiliki fungsi yang melarang pencetakan laporan kemajuan menjadi stdout - mereka tentu saja membentuk urutan pipa yang dalam perintah shell Unix bukan hanya efek samping, tetapi inti dari pendekatan perpipaan yang kuat .

Begitu. Tidak ada yang lain kecuali "payload" nyata dari program Anda yang dimiliki stdout. Jika program Anda tidak memiliki output, maka tidak ada yang harus dilakukan untuk stdout. Ini menyisakan stderr untuk yang lainnya , termasuk laporan kemajuan.

Memang, ini meninggalkan lubang - mungkin akan menyenangkan untuk memiliki "stdfluff" atau sesuatu seperti itu yang bukan untuk output atau kesalahan tetapi laporan kemajuan, debugging dan semacamnya. Bahkan, tidak ada yang menghalangi Anda untuk melakukan itu, yaitu, Anda bisa mencetak kemajuan Anda ke file descriptor 3. Contoh:

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

Ini tidak menghasilkan keluaran. (*)

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

Ini mencetak ke fd-3, yang diarahkan ke stdout.

(*) Contoh pertama tidak menghasilkan output tetapi masih agak dibuat-buat; yang opengagal dan $!akan mengandung no such file or directory; ambil saja ini sebagai contoh, tentu saja tidak boleh digunakan seperti ini dengan sungguh-sungguh. Dalam program yang sebenarnya, jika Anda ingin menempuh rute ini, Anda dapat menguji apakah /dev/fd/3dapat digunakan dan menganggap ini sebagai petunjuk apakah akan mengaktifkan laporan kemajuan Anda; Anda harus melakukannya cukup awal sehingga Anda tidak bingung dengan openfile Anda yang asli dan semacamnya ...

AnoE
sumber
Apa fd-3? Floppy disk ketiga?
Peter Mortensen
file descriptor 3, @PeterMortensen
AnoE
-1

Pesan penggunaan harus pergi ke stdout jika pengguna telah memanggilnya dengan --helpdan ke stderr jika mereka telah melakukan kesalahan. Mencetaknya ke stderr tanpa syarat adalah menjengkelkan karena membuatnya lebih sulit untuk melihatnya dengan pager / grep / etc.

Juga, izinkan saya menyarankan cara ketiga: buka / dev / tty untuk laporan kemajuan / pemintal / dll.

Random832
sumber
6
Maaf, tetapi ini tidak menjawab pertanyaan. Saya secara khusus meminta pedoman resmi , bukan pendapat. Bagaimanapun, bahkan jika saya telah meminta pendapat, Anda menjawab pertanyaan yang berbeda. Saya tidak berbicara tentang --helpatau membantu pesan sama sekali. Harap baca kembali pertanyaannya.
terdon
Anda menyebut "pesan penggunaan", saya pikir itu adalah bagian dari pertanyaan Anda, bukan hanya judul pertanyaan lain yang Anda tautkan. Saya tidak mengerti mengapa Anda berpikir "pedoman resmi" ada untuk ini. Siapa yang akan memiliki wewenang untuk membuatnya?
Random832
3
Saya tidak tahu mereka melakukannya, itu sebabnya saya bertanya. Dan untuk resmi, standar POSIX memiliki spesifikasi untuk berbagai detail menit tentang bagaimana suatu program harus berperilaku. Termasuk, seperti yang ditunjukkan Stephen dalam jawabannya, saran samar-samar untuk apa yang harus dilakukan ke stderr. Standar pengkodean GNU juga bisa memiliki sesuatu yang serupa. Pada dasarnya, setiap grup yang aktif dan menghasilkan kode untuk ekosistem * nix mungkin memiliki standar yang akan saya minati.
terdon
@terdon apakah Anda akan baik-baik saja dengan contoh program apa yang ada? curl, wget, dan pv semua menggunakan stderr, dengan wget dan pv membuatnya bersyarat menjadi tty dan curl menjadikannya bersyarat pada stdout bukan tty.
Acak832
4
Juga, sepertinya CTO Anda berpikir bahwa program panggilan harus bereaksi terhadap keberadaan data pada stderr sebagai makna bahwa telah terjadi kesalahan, daripada melihat status keluar. Ini jelas merupakan praktik yang buruk (dan juga lebih sulit untuk menulis daripada memeriksa status keluar) dan mungkin sudut yang lebih baik untuk meyakinkannya.
Acak832