Saya memiliki program yang menulis informasi untuk stdout
dan stderr
, dan saya harus grep
melalui apa yang akan terjadi pada stderr , sambil mengabaikan stdout .
Tentu saja saya bisa melakukannya dalam 2 langkah:
command > /dev/null 2> temp.file
grep 'something' temp.file
tapi saya lebih suka bisa melakukan ini tanpa file temp. Apakah ada trik perpipaan yang cerdas?
command 2| othercommand
. Bash sangat sempurna sehingga pengembangan berakhir pada 1982, jadi kami tidak akan pernah melihatnya di bash, aku khawatir.Jawaban:
Redirect stderr pertama ke stdout - pipa; lalu arahkan stdout ke
/dev/null
(tanpa mengubah arah tujuan stderr):Untuk detail pengalihan I / O dalam semua varietasnya, lihat bab Pengalihan di manual referensi Bash.
Perhatikan bahwa urutan pengalihan I / O ditafsirkan dari kiri ke kanan, tetapi pipa disiapkan sebelum pengalihan I / O ditafsirkan. Deskriptor file seperti 1 dan 2 adalah referensi untuk membuka deskripsi file. Operasi ini
2>&1
membuat file descriptor 2 alias stderr merujuk ke deskripsi file terbuka yang sama dengan file descriptor 1 alias stdout saat ini merujuk ke (lihatdup2()
danopen()
). Operasi>/dev/null
kemudian mengubah file descriptor 1 sehingga mengacu pada deskripsi file terbuka/dev/null
, tetapi itu tidak mengubah fakta bahwa file deskriptor 2 mengacu pada deskripsi file terbuka yang file deskriptor 1 awalnya tunjuk - yaitu, pipa.sumber
command 2> /dev/stdout 1> /dev/null | grep 'something'
/dev/stdout
et al, atau menggunakan/dev/fd/N
. Mereka akan sedikit kurang efisien kecuali jika shell memperlakukan mereka sebagai kasus khusus; notasi angka murni tidak melibatkan mengakses file dengan nama, tetapi menggunakan perangkat berarti pencarian nama file. Apakah Anda bisa mengukurnya masih bisa diperdebatkan. Saya suka ringkasnya notasi angka - tetapi saya sudah menggunakannya begitu lama (lebih dari seperempat abad; aduh!) Sehingga saya tidak memenuhi syarat untuk menilai manfaatnya di dunia modern.2>&1
, yang berarti 'hubungkan stderr ke deskriptor file yang saat ini akan stdout '. Operasi kedua adalah 'ubah stdout jadi begini/dev/null
', meninggalkan stderr pergi ke stdout asli, pipa. Shell membagi sesuatu pada simbol pipa terlebih dahulu, jadi, pengalihan pipa terjadi sebelum2>&1
atau>/dev/null
redirection, tapi itu saja; operasi lainnya dari kiri ke kanan. (Kanan-ke-kiri tidak akan berfungsi.)/dev/null
menjadi Windows yang setara,nul
).Atau untuk menukar output dari kesalahan standar dan output standar, gunakan:
Ini menciptakan deskriptor file baru (3) dan menempatkannya di tempat yang sama dengan 1 (output standar), kemudian menetapkan fd 1 (output standar) ke tempat yang sama dengan fd 2 (kesalahan standar) dan akhirnya menetapkan fd 2 (kesalahan standar) ) ke tempat yang sama dengan fd 3 (output standar).
Kesalahan standar sekarang tersedia sebagai keluaran standar dan keluaran standar lama dipertahankan dalam kesalahan standar. Ini mungkin berlebihan, tetapi semoga memberikan lebih banyak detail pada deskriptor file Bash (ada sembilan tersedia untuk setiap proses).
sumber
3>&-
menutup deskriptor cadangan yang Anda buat dari stdoutstderr
dan yang lain memiliki kombinasi daristderr
danstdout
? Dengan kata lain dapatkahstderr
pergi ke dua file berbeda sekaligus?Di Bash, Anda juga bisa mengarahkan ke subkulit menggunakan subtitusi proses :
Untuk kasus yang dihadapi:
sumber
command 2> >(grep 'something' > grep.log)
grep.log berisi output yang sama seperti ungrepped.log daricommand 2> ungrepped.log
2> >(stderr pipe >&2)
. Kalau tidak, output dari "pipa stderr" akan melalui "pipa stdlog".2> >(...)
, berhasil, saya mencoba2>&1 > >(...)
tetapi tidakawk -f /new_lines.awk <in-content.txt > out-content.txt 2> >(tee new_lines.log 1>&2 )
Dalam contoh ini saya ingin juga melihat apa yang keluar sebagai kesalahan pada konsol saya. Tetapi STDOUT pergi ke file output. Jadi di dalam sub-shell, Anda perlu mengarahkan STDOUT itu kembali ke STDERR di dalam tanda kurung. Sementara itu berfungsi, output STDOUT daritee
perintah berakhir di akhirout-content.txt
file. Itu tampaknya tidak konsisten bagi saya.2>&1 1> >(dest pipe)
Menggabungkan yang terbaik dari jawaban ini, jika Anda melakukannya:
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 di stderr yang berisi string "sesuatu".
Ini memiliki keuntungan unik yaitu tidak membalikkan atau membuang stdout dan stderr, atau menyatukannya, atau menggunakan file sementara.
sumber
command 2> >(grep -v something)
(tanpa1>&2
) sama?tar cfz my.tar.gz mydirectory/ 2> >(grep -v 'changed as we read it' 1>&2)
harusnya bekerja.Jauh lebih mudah untuk memvisualisasikan hal-hal jika Anda berpikir tentang apa yang sebenarnya terjadi dengan "pengalihan" dan "pipa." Arahan ulang dan pipa dalam bash melakukan satu hal: memodifikasi tempat file deskriptor 0, 1, dan 2 menunjuk ke (lihat / proc / [pid] / fd / *).
Ketika sebuah pipa atau "|" operator hadir pada baris perintah, hal pertama yang terjadi adalah bahwa bash menciptakan fifo dan mengarahkan FD1 perintah sisi kiri ke fifo ini, dan mengarahkan FD 0 perintah sisi kanan ke fifo yang sama.
Selanjutnya, operator pengalihan untuk setiap sisi dievaluasi dari kiri ke kanan , dan pengaturan saat ini digunakan setiap kali duplikasi deskriptor terjadi. Ini penting karena sejak pipa dipasang pertama kali, FD1 (sisi kiri) dan FD0 (sisi kanan) sudah berubah dari yang biasanya, dan duplikasi ini akan mencerminkan fakta itu.
Karena itu, ketika Anda mengetikkan sesuatu seperti berikut:
Inilah yang terjadi, secara berurutan:
Jadi, semua output yang "perintah" tulis ke FD 2 (stderr) membuat jalan ke pipa dan dibaca oleh "grep" di sisi lain. Semua output yang "perintah" tulis ke FD 1 (stdout) menuju ke / dev / null.
Jika sebaliknya, Anda menjalankan yang berikut:
Inilah yang terjadi:
Jadi, semua stdout dan stderr dari "command" menuju ke / dev / null. Tidak ada yang masuk ke pipa, dan dengan demikian "grep" akan menutup tanpa menampilkan apa pun di layar.
Perhatikan juga bahwa pengalihan (deskriptor file) dapat berupa read-only (<), only-write (>), atau read-write (<>).
Catatan terakhir. Apakah program menulis sesuatu ke FD1 atau FD2, sepenuhnya tergantung pada programmer. Praktik pemrograman yang baik menentukan bahwa pesan kesalahan harus masuk ke FD 2 dan output normal ke FD 1, tetapi Anda akan sering menemukan pemrograman yang ceroboh yang menggabungkan keduanya atau mengabaikan konvensi.
sumber
Jika Anda menggunakan Bash, gunakan:
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
sumber
|&
sama dengan2>&1
yang menggabungkan stdout dan stderr. Pertanyaan secara eksplisit meminta hasil tanpa stdout.>/dev/null |&
memperluas ke>/dev/null 2>&1 |
dan berarti inode stdout kosong untuk pipa karena tidak ada (# 1 # 2 keduanya terkait dengan / dev / null inode) diikat ke inode stdout (misalnyals -R /tmp/* >/dev/null 2>&1 | grep i
akan memberikan kosong, tetapils -R /tmp/* 2>&1 >/dev/null | grep i
akan membiarkan # 2 yang diikat ke inode stdout akan pipa).( echo out; echo err >&2 ) >/dev/null |& grep "."
tidak memberikan output (di mana kami ingin "err").man bash
mengatakan Jika | & digunakan ... adalah singkatan untuk 2> & 1 |. Pengalihan implisit kesalahan standar ke output standar dilakukan setelah setiap pengalihan ditentukan oleh perintah. Jadi pertama-tama kita mengarahkan FD1 perintah ke nol, lalu kita mengarahkan FD2 perintah ke tempat FD1 menunjuk, yaitu. null, jadi FD0 grep tidak mendapat input. Lihat stackoverflow.com/a/18342079/69663 untuk penjelasan yang lebih mendalam.Bagi mereka yang ingin mengarahkan stdout dan stderr secara permanen ke file, grep on stderr, tetapi tetap stdout untuk menulis pesan ke tty:
sumber
Ini akan mengarahkan command1 stderr ke command2 stdin, sambil membiarkan command1 stdout apa adanya.
Diambil dari LDP
sumber
Saya baru saja menemukan solusi untuk mengirim
stdout
ke satu perintah danstderr
ke yang lain, menggunakan pipa bernama.Ini dia.
Mungkin ide yang bagus untuk menghapus pipa bernama sesudahnya.
sumber
Anda dapat menggunakan shell rc .
Pertama instal paket (kurang dari 1 MB).
Ini contoh bagaimana Anda akan membuang output standar dan pipa standard error untuk grep di
rc
:Anda dapat melakukannya tanpa meninggalkan Bash:
Seperti yang mungkin telah Anda perhatikan, Anda dapat menentukan deskriptor file mana yang ingin Anda perpip dengan menggunakan tanda kurung setelah pipa.
Deskriptor file standar diberi nomor seperti itu:
sumber
Saya coba ikuti, ternyata berhasil juga,
sumber