Pertanyaan Bagaimana cara men-pipe stderr, dan tidak stdout?


Saya memiliki program yang menulis informasi stdout dan stderr, dan saya perlu grep melalui apa yang akan terjadi stderr, tanpa mempedulikan stdout.

Saya tentu saja dapat melakukannya dalam 2 langkah:

command > /dev/null 2> temp.file
grep 'something' temp.file

tetapi saya lebih memilih untuk dapat melakukan ini tanpa file temp. Apakah ada trik pemipaan yang cerdas?


760
2018-02-26 15:53


asal


Jawaban:


Pengalihan pertama stderr ke stdout - pipa; kemudian redirect stdout ke /dev/null (tanpa mengubah ke mana stderr pergi):

command 2>&1 >/dev/null | grep 'something'

Untuk rincian I / O redirection di semua ragamnya, lihat bab tentang Pengalihan dalam manual referensi Bash.

Perhatikan bahwa urutan pengalihan I / O ditafsirkan dari kiri ke kanan, tetapi pipa disiapkan sebelum pengalihan I / O ditafsirkan. File deskriptor seperti 1 dan 2 adalah referensi untuk membuka deskripsi file. Operasi 2>&1 membuat file descriptor 2 alias stderr mengacu pada deskripsi file terbuka yang sama seperti file descriptor 1 alias stdout saat ini mengacu pada (lihat dup2() dan open()). Operasi >/dev/null kemudian mengubah deskripsi file 1 sehingga mengacu pada deskripsi file terbuka untuk /dev/null, tapi itu tidak mengubah fakta bahwa file descriptor 2 mengacu pada deskripsi file yang terbuka yang deskriptor file 1 awalnya menunjuk ke - yaitu, pipa.


902
2018-02-26 15:55



Atau untuk menukar output dari stderr dan stdout over use: -

command 3>&1 1>&2 2>&3

Ini menciptakan deskriptor file baru (3) dan menugaskannya ke tempat yang sama dengan 1 (stdout), kemudian menetapkan fd 1 (stdout) ke tempat yang sama seperti fd 2 (stderr) dan akhirnya menetapkan fd 2 (stderr) ke yang sama tempatkan sebagai fd 3 (stdout). Stderr sekarang tersedia sebagai stdout dan stdout lama yang diawetkan di stderr. Ini mungkin berlebihan tetapi mudah-mudahan memberikan rincian lebih lanjut tentang deskriptor file bash (ada 9 tersedia untuk setiap proses).


311
2018-03-04 18:18



Di Bash, Anda juga dapat mengalihkan ke subkulit menggunakan substitusi proses:

command > >(stdlog pipe)  2> >(stderr pipe)

Untuk kasus di tangan:

command 2> >(grep 'something') >/dev/null

172
2018-02-09 19:14



Menggabungkan yang terbaik dari jawaban ini, jika Anda:

command 2> >(grep -v something 1>&2)

... maka semua stdout dipertahankan sebagai stdout dan semua stderr dipertahankan sebagai stderr, tetapi Anda tidak akan melihat baris apa pun di stderr yang diawali dengan string "sesuatu".

Ini memiliki keuntungan unik yaitu tidak membalikkan atau membuang stoutr dan stderr, atau menghujani mereka bersama-sama, atau menggunakan file sementara.


138
2018-04-10 21:05



Jauh lebih mudah untuk memvisualisasikan berbagai hal jika Anda memikirkan apa yang sebenarnya terjadi dengan "pengalihan" dan "pipa." Pengalihan dan pipa di bash melakukan satu hal: memodifikasi tempat deskriptor file proses 0, 1, dan 2 titik ke (lihat / proc / [pid] / fd / *).

Ketika sebuah pipa atau "|" Operator hadir pada baris perintah, hal pertama yang terjadi adalah bash yang menciptakan fifo dan mengarahkan perintah sisi kiri FD 1 ke fifo ini, dan menunjukkan perintah sisi kanan FD 0 ke fifo yang sama.

Selanjutnya, operator redirect untuk setiap sisi dievaluasi dari kiri ke kanan, dan pengaturan saat ini digunakan setiap kali duplikasi deskriptor terjadi. Ini penting karena sejak pipa pertama kali dipasang, FD1 (sisi kiri) dan FD0 (sisi kanan) sudah berubah dari apa yang biasanya mereka lakukan, dan setiap duplikasi ini akan mencerminkan fakta itu.

Oleh karena itu, ketika Anda mengetik sesuatu seperti berikut:

command 2>&1 >/dev/null | grep 'something'

Inilah yang terjadi, dalam urutan:

  1. pipa (fifo) dibuat. "perintah FD1" diarahkan ke pipa ini. "grep FD0" juga menunjuk ke pipa ini
  2. "perintah FD2" menunjuk ke tempat "perintah FD1" saat ini menunjuk (pipa)
  3. "perintah FD1" menunjuk ke / dev / null

Jadi, semua output yang "perintah" tulis ke FD 2-nya (stderr) membuat jalan ke pipa dan dibaca oleh "grep" di sisi lain. Semua output yang "perintah" tulis ke FD 1 (stdout) membuat jalannya ke / dev / null.

Jika sebaliknya, Anda menjalankan yang berikut:

command >/dev/null 2>&1 | grep 'something'

Inilah yang terjadi:

  1. pipa dibuat dan "perintah FD 1" dan "grep FD 0" menunjuk ke sana
  2. "perintah FD 1" menunjuk ke / dev / null
  3. "perintah FD 2" menunjuk ke tempat FD 1 saat ini menunjuk (/ dev / null)

Jadi, semua stdout dan stderr dari "command" pergi ke / dev / null. Tidak ada yang pergi ke pipa, dan dengan demikian "grep" akan menutup tanpa menampilkan apa pun di layar.

Perhatikan juga bahwa pengalihan (deskriptor file) dapat bersifat hanya-baca (<), hanya-menulis (>), atau baca-tulis (<>).

Catatan terakhir. Apakah suatu program menulis sesuatu ke FD1 atau FD2, sepenuhnya tergantung pada pemrogram. Praktik pemrograman yang baik menyatakan bahwa pesan kesalahan harus pergi ke FD 2 dan output normal ke FD 1, tetapi Anda akan sering menemukan pemrograman ceroboh yang mencampur dua atau mengabaikan konvensi.


82
2017-08-20 18:09



Apakah kamu menggunakan bash? Jika begitu:

command >/dev/null |& grep "something"

http://www.gnu.org/software/bash/manual/bashref.html#Pipelines


28
2018-04-18 21:56



Bagi mereka yang ingin mengarahkan ulang stdout dan stderr secara permanen ke file, grep di stderr, tetapi tetap stdout untuk menulis pesan ke tty:

# save tty-stdout to fd 3
exec 3>&1
# switch stdout and stderr, grep (-v) stderr for nasty messages and append to files
exec 2> >(grep -v "nasty_msg" >> std.err) >> std.out
# goes to the std.out
echo "my first message" >&1
# goes to the std.err
echo "a error message" >&2
# goes nowhere
echo "this nasty_msg won't appear anywhere" >&2
# goes to the tty
echo "a message on the terminal" >&3

9
2017-11-14 08:59



Ini akan mengalihkan command1 stderr ke command2 stdin, sementara meninggalkan command1 stdout sebagaimana adanya.

exec 3>&1
command1 2>&1 >&3 3>&- | command2 3>&-
exec 3>&-

Diambil dari LDP


5
2017-10-07 07:39



Saya coba ikuti, temukan itu berfungsi juga,

command 1> /dev/null | grep 'something'

0
2018-04-11 03:27