Memipihkan stdout dan stderr di bash?

156

Tampaknya versi bash yang lebih baru memiliki &>operator, yang (jika saya mengerti dengan benar), mengarahkan ulang stdout dan stderr ke sebuah file ( &>>sebagai gantinya ditambahkan ke file, seperti yang diklarifikasi Adrian).

Apa cara paling sederhana untuk mencapai hal yang sama, tetapi sebaliknya mengirim ke perintah lain?

Misalnya, di baris ini:

cmd-doesnt-respect-difference-between-stdout-and-stderr | grep -i SomeError

Saya ingin grep dicocokkan dengan konten, baik di stdout dan stderr (secara efektif, digabungkan menjadi satu aliran).

Catatan : pertanyaan ini menanyakan tentang pemipaan, bukan pengalihan - jadi itu bukan duplikat dari pertanyaan yang saat ini ditandai sebagai duplikat dari.

Andrew Ferrier
sumber
Lihat jawaban kedua ( stackoverflow.com/a/637834/1129642 ) pada pertanyaan terkait untuk cara yang benar untuk mem-pipe stdout dan stderr. Tidak perlu pertanyaan lain.
Marki555
4
@triplee Bukan duplikat yang tepat, bukan? Pipa vs. redirect ke file?
Benjamin W.
@ BenjaminW Ada setidaknya satu jawaban di sana yang memecahkan kedua skenario, meskipun itu bukan jawaban yang diterima. Ini adalah pertanyaan yang cukup umum sehingga kami mungkin dapat menemukan duplikat yang lebih baik, atau meminta moderator untuk menggabungkan ini - atau bahkan, dalam kasus terburuk, membuat kanonik yang sama sekali baru untuk topik ini. Jika Anda menemukan penipuan yang lebih baik, tentu saja usulkan saja. Terima kasih sebelumnya.
tripleee
12
@ tripleee Memecahkan, ya, tapi tidak ada jawaban yang menggunakan |&pintasan, yang menurut saya sejauh ini merupakan solusi paling mudah untuk "mengarahkan ulang stdout dan stderr ke sebuah pipa".
Benjamin W.
3
Ini bukan duplikat dari pertanyaan terkait, dan tidak jelas bahwa jawaban Marko melakukan apa yang saya inginkan. Juga, itu tidak menyebutkan | &. Voting untuk dibuka kembali.
Martin Bonner mendukung Monica

Jawaban:

163

(Perhatikan bahwa &>>file menambahkan file sementara &>akan mengarahkan ulang dan menimpa file yang sudah ada sebelumnya.)

Untuk menggabungkan stdoutdan stderrAnda akan mengarahkan yang terakhir ke yang sebelumnya menggunakan 2>&1. Ini mengarahkan ulang stderr (deskriptor file 2) ke stdout (deskriptor file 1), misalnya:

$ { echo "stdout"; echo "stderr" 1>&2; } | grep -v std
stderr
$

stdoutpergi ke stdout, stderrpergi ke stderr. grephanya melihat stdout, karenanya stderrmencetak ke terminal.

Di samping itu:

$ { echo "stdout"; echo "stderr" 1>&2; } 2>&1 | grep -v std
$

Setelah menulis ke stdout dan stderr, 2>&1pengalihan stderr kembali ke stdout dan grepmelihat kedua string pada stdin, sehingga menyaring keduanya.

Anda dapat membaca lebih lanjut tentang pengalihan di sini .

Mengenai contoh Anda (POSIX):

cmd-doesnt-respect-difference-between-stdout-and-stderr 2>&1 | grep -i SomeError

atau, menggunakan >=bash-4:

cmd-doesnt-respect-difference-between-stdout-and-stderr |& grep -i SomeError
Adrian Frühwirth
sumber
Terima kasih atas klarifikasi pada &>>. Saya telah memperbaiki pertanyaan saya.
Andrew Ferrier
18
Saya menambahkan contoh Anda ke jawaban saya, kalau-kalau itu tidak jelas berdasarkan contoh yang diberikan. Sebagai catatan tambahan, Anda juga dapat menggunakan bash-specific |&sebagai ganti 2>&1 |.
Adrian Frühwirth
13
Catatan tambahan tentang pintasan yang |&diusulkan oleh @ AdrianFrühwirth untuk pembaca di masa mendatang: fitur ini hanya didukung dengan bashversi 4+. Jika Anda menggunakan 3 atau lebih rendah, Anda harus menggunakannya 2>&1 |.
tomocafe
3
Pengalihan Bash dijelaskan dengan sangat baik di sini . @ AdrianFrühwirth telah melakukan pekerjaan dengan baik, tautan yang ditempelkan lebih jauh. Terkadang, saya berharap dokumentasi resmi Bash sebaik itu.
David Andreoletti
112

Bash memiliki singkatan untuk 2>&1 |, yaitu |&, yang pipa stdout dan stderr (lihat manual ):

cmd-doesnt-respect-difference-between-stdout-and-stderr |& grep -i SomeError

Ini diperkenalkan di Bash 4.0, lihat catatan rilis .

Benjamin W.
sumber
Terima kasih telah menambahkan ini untuk kelengkapan. Saya akan menjaga jawaban yang lain benar karena banyak orang masih menggunakan bash pre-4.0. Tapi ini bermanfaat.
Andrew Ferrier
9
Paling mungkin, Bash yang dikirim pada macOS terlalu tua untuk mendukung ini.
Flimm
@ Flimm tapi zsh bukan
Trenton
1
Karena ksh menggunakan | & untuk coproc, ini sepertinya pilihan yang buruk untuk tulisan cepat yang tidak perlu. Saya benci melihat garis dengan setumpuk dups dan redirect sebanyak orang berikutnya, tetapi ada sesuatu yang bisa dikatakan eksplisit .... dan saya minta maaf bahwa komentar ini tidak menambah banyak. Saya hanya ingin mengekspresikan kebencian pada steno tanpa menurunkan jawaban yang benar-benar bermanfaat, karena ada baiknya orang melihat ini. Saya tidak tahu ini, jadi terima kasih telah membuat saya sadar.
Paul Hodges
@PaulHodges Saya setuju bahwa ini tidak portabel - Saya terutama suka menggunakannya untuk sesi Bash interaktif untuk menghindari mengetik terlalu banyak.
Benjamin W.