Bagaimana cara mengetahui apakah output dari perintah atau skrip shell stdout atau stderr


32

Katakanlah saya menjalankan perintah atau skrip shell, dan itu memberi saya output. Tanpa mengetahui bagian dalam dari perintah ini atau skrip shell, bagaimana cara menentukan apakah output berasal stderratau stdout?

Untuk misalnya,

$ ls -ld /
drwxrwxr-t  35 root  admin  1258 Dec 11 19:16 /

vs.

ls -ld /test
ls: /test: No such file or directory

Bagaimana saya memastikan bahwa perintah pertama dicetak ke stdoutdan yang kedua untuk stderr(melakukannya?)


1
Masalah apa yang Anda coba selesaikan di sini?
Kenster

3
Takut seseorang akan bertanya itu; tidak ada yang benar-benar penasaran dan berharap dapat meningkatkan pemahaman saya tentang pengalihan.
KM.

7
Anda bisa memasukkan stderredlingkungan shell Anda LD_PRELOADuntuk mendapatkan stdoutdan stderrdalam warna yang berbeda. Berikut pertanyaan terkait dalam nada itu.
Anko

Jawaban:


18

Tidak ada cara untuk mengetahui setelah output sudah dicetak. Dalam hal ini, keduanya stdoutdan stderrterhubung ke terminal, sehingga informasi tentang aliran mana yang dituliskan telah hilang pada saat teks muncul di terminal Anda; mereka digabungkan oleh program sebelum berhasil ke terminal.

Apa yang dapat Anda lakukan, dalam kasus seperti di atas, akan menjalankan perintah dengan stdoutdan stderrdiarahkan ke tempat yang berbeda dan melihat apa yang terjadi. Atau jalankan dua kali, sekali dengan stdoutdialihkan ke /dev/nulldan sekali dengan stderrdialihkan ke /dev/null, dan melihat mana dari kasus-kasus yang menghasilkan teks muncul.

Anda bisa mengarahkan stdoutke /dev/nulldengan menempel >/dev/nulldi ujung baris perintah, dan Anda bisa mengarahkan stderrke /dev/nulldengan menambahkan 2>/dev/null.


9

Anda dapat mengarahkan ulang stdout menggunakan > file, dan mengarahkan stderr menggunakan 2> file. Banyak shell modern mendukung pengalihan ke perintah, sehingga Anda dapat menggunakan seduntuk menyorot output mana yang berasal dari aliran:

$ ls 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
1: unity_support_test.0
1: vmwareDnD

$ ls foo 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
2: ls: cannot access foo: No such file or directory

Sangat bagus! Akan lebih bagus jika seseorang bisa menyorot garis dalam warna daripada awalan.
dotancohen

3
@dotancohen: Satu bisa! Misalnya,(echo "this is stdout"; echo "this is stderr" >&2) > >(sed 's/.*/\x1b[32m&\x1b[0m/') 2> >(sed 's/.*/\x1b[31m&\x1b[0m/')
PM 2Ring

Perhatikan bahwa jika ada output campuran dari stdout dan stderr, stdout pertama akan dicetak, kemudian stderr.
nyuszika7h

5

The annotate-outputScript dari Debian devscriptsmemungkinkan Anda melakukan hal ini secara selektif:

$ annotate-output ls -ld /test
14:54:22 -: Started ls -ld /test
14:54:22 E: ls: cannot access /test: No such file or directory
14:54:22 -: Finished with exitcode 2

Kolom kedua menunjukkan stdout dan stderr dengan Odan Emasing - masing.

Ada beberapa peringatan, yang utama seperti yang dicatat dalam jawaban lain: Anda tidak dapat melakukan ini setelah fakta. Shell atau terminal tidak mengetahui bagaimana program arbitrer menggunakan deskriptor file, meskipun shell bertanggung jawab untuk mengaturnya pada awalnya.

Metode ini menggunakan fifos, menulis ke fifo dapat berperilaku berbeda dari menulis ke fty, dan menulis ke dua fifos berbeda pasti berbeda (potensi waktu / masalah interleaving). Juga, itu tidak cocok untuk penggunaan interaktif, misalnya annotate-output bashbukan rencana yang bagus, tetapi berguna untuk banyak tujuan lain. Ada banyak, banyak contoh skrip dan fungsi shell dalam menjawab pertanyaan terkait tentang pewarnaan stdin / stdout / stderr, yang paling kuat adalah stderrd yang menggunakan modifikasi runtime dari (sebagian besar) program untuk memodifikasi data yang ditulis ke stderr.

Pertanyaan yang dihubungkan Anko ini memiliki jawaban yang bagus tentang tema terkait: mewarnai stdout / stderr output: Dapatkah saya mengonfigurasi shell saya untuk mencetak STDERR dan STDOUT dalam berbagai warna?


1
Perhatikan bahwa ini adalah bashskrip yang menggunakan while readloop dan menjalankan satu dateperintah untuk setiap baris stdout atau stderr, jadi itu akan jauh lebih efisien daripada yang cmd > >(ts '%T O:') 2> >(ts '%T E:')setara.
Stéphane Chazelas

1

Terlepas dari jawaban yang lain, itu adalah interessant untuk menunjuk /proc/$PID/fd(meskipun tidak menjawab pertanyaan):

$ cat > /dev/null 2> /tmp/blablah &
[1] 3073

[1]+  Stopped                 cat > /dev/null 2> /tmp/blablah
$ ls -l /proc/3073/fd
total 0
lrwx------ 1 kampde kampde 64 Feb 24 11:43 0 -> /dev/pts/33
l-wx------ 1 kampde kampde 64 Feb 24 11:43 1 -> /dev/null
l-wx------ 1 kampde kampde 64 Feb 24 11:43 2 -> /tmp/blablah

Seperti yang Anda lihat, di sini Anda dapat melihat deskriptor file dibuka untuk suatu proses. 0adalah STDIN, 1adalah STDOUTdan 2adalah STDERR. Jika Anda tidak memiliki STDOUT atau STDERR dialihkan, Anda akan melihat /dev/pts/33(dalam contoh ini setidaknya) karena mereka akan menunjuk ke terminal.

catatan : /proc/$PIDhanya ada untuk menjalankan proses. Dalam hal ini saya telah menggunakan cattanpa argumen sehingga tidak berakhir sampai saya menutup STDIN. Saya juga telah menjalankannya di latar belakang sehingga saya memiliki PID segera untuk contoh ini.


0

Tidak jelas apa yang Anda minta tetapi ini mungkin bisa membantu

ls -ld /
echo $?    # Exit status 0 returned because command executed successfully.

ls -ld /test
echo $?    # Non-zero exit status returned -- command failed to execute

Sumber

Jika kode keluar 0 berarti perintah dijalankan dengan benar (stdout), di sini Anda dapat menemukan artinya jika kode keluar berbeda dari 0 (stderr)


Sangat menarik! Saya tidak akan pernah menghubungkan status keluar dengan pengalihan. Apakah nol menyiratkan stdoutdan bukan-nol menyiratkan stderr?
KM.

7
@ KM., Tidak. Saya akan mengatakan itu sangat berkorelasi, tetapi tidak ada yang menghentikan program dari menulis ke stderrdan mengembalikan kode kesalahan yang baik, atau menulis ke stdoutdan mengembalikan kode kesalahan buruk. Bahkan, coba find /root- dengan asumsi Anda tidak berjalan sebagai root, Anda harus mencetak 2 baris - "/ root" dicetak stdout, dan "temukan: / root: Izin ditolak" akan dicetak stderr. Dan temukan pengembalian kode pengembalian yang buruk.
godlygeek

Masalah op jelas bahwa bagaimana cara mengetahui yang stdout atau stderr.
it_is_a_literature

0

Biasanya STDERR akan memiliki nama program yang diawali dengan pesan dengan titik dua.

Contoh:

rpm -zq some_utils 
rpm: -zq: unknown option

Vs

rpm -ql some_utils 
package some_utils is not installed

-1

Untuk menangkap dan menguji output kesalahan:

ls -l test 2>errors
if [ -s errors ]; then echo "There were errors:" && cat errors; fi
rm errors
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.