Aku tahu bagaimana menggunakan tee
untuk menulis output ( STDOUT
) dari aaa.sh
ke bbb.out
, sementara masih menampilkan di terminal:
./aaa.sh | tee bbb.out
Bagaimana saya sekarang juga menulis STDERR
ke file bernama ccc.out
, sementara masih ditampilkan?
Jawaban:
Saya berasumsi Anda ingin tetap melihat STDERR dan STDOUT di terminal. Anda bisa mencari jawaban Josh Kelley, tetapi saya menemukan
tail
latar belakang yang menghasilkan file log Anda sangat rapuh dan kasar. Perhatikan bagaimana Anda perlu menyimpan FD exra dan melakukan pembersihan setelah itu dengan membunuhnya dan secara teknis harus melakukan itu dalamtrap '...' EXIT
.Ada cara yang lebih baik untuk melakukan hal ini, dan Anda sudah menemukannya:
tee
.Hanya, alih-alih hanya menggunakannya untuk stdout Anda, miliki tee untuk stdout dan satu untuk stderr. Bagaimana Anda akan mencapai ini? Substitusi proses dan pengalihan file:
Mari kita bagi dan jelaskan:
>(...)
(substitusi proses) membuat FIFO dan mari kitatee
dengarkan. Kemudian, ia menggunakan>
(pengalihan file) untuk mengarahkan kembali STDOUTcommand
ke FIFO yang pertama kali Andatee
dengarkan.Hal yang sama untuk yang kedua:
Kami menggunakan subtitusi proses lagi untuk membuat
tee
proses yang membaca dari STDIN dan memasukkannya ke dalamstderr.log
.tee
mengembalikan inputnya kembali ke STDOUT, tetapi karena inputnya adalah STDERR kami, kami ingin mengarahkan kembalitee
STDOUT ke STDERR kami. Kemudian kami menggunakan pengalihan file untuk mengarahkan kembalicommand
STDERR ke input FIFO (tee
STDIN).Lihat http://mywiki.wooledge.org/BashGuide/InputAndOutput
Substitusi proses adalah salah satu dari hal-hal yang sangat menyenangkan yang Anda dapatkan sebagai bonus dengan memilih
bash
sebagai pengganti shell Andash
(POSIX atau Bourne).Di
sh
, Anda harus melakukan hal-hal secara manual:sumber
$ echo "HANG" > >(tee stdout.log) 2> >(tee stderr.log >&2)
yang berhasil, tetapi menunggu input. Apakah ada alasan sederhana mengapa ini terjadi?/bin/bash 2> err
dan/bin/bash -i 2> err
(echo "Test Out";>&2 echo "Test Err") > >(tee stdout.log) 2> >(tee stderr.log >&2)
mengapa tidak secara sederhana:
Ini hanya dialihkan
stderr
kestdout
, jadi tee menggema untuk login dan ke layar. Mungkin saya kehilangan sesuatu, karena beberapa solusi lain tampaknya sangat rumit.Catatan: Karena bash versi 4 Anda dapat menggunakan
|&
singkatan untuk2>&1 |
:sumber
./aaa.sh |& tee aaa.log
berfungsi (dalam bash).set -o pipefail
diikuti oleh;
atau&&
jika saya tidak salah.Ini mungkin berguna untuk orang yang menemukan ini melalui google. Hapus komentar contoh yang ingin Anda coba. Tentu saja, jangan ragu untuk mengganti nama file output.
sumber
exec >
artinya, pindahkan target deskriptor file ke tujuan tertentu. Defaultnya adalah 1, jadi,exec > /dev/null
pindahkan output dari stdout ke / dev / null mulai sekarang di sesi ini. Deskriptor file saat ini untuk sesi ini dapat dilihat dengan melakukanls -l /dev/fd/
. Cobalah! Kemudian lihat apa yang terjadi ketika Anda menerbitkanexec 2>/tmp/stderr.log.
Selain itu,exec 3>&1
berarti, membuat deskriptor file baru dengan nomor 3, dan mengarahkannya ke target deskriptor file 1. Pada contoh, target adalah layar ketika perintah dikeluarkan.Untuk mengarahkan ulang stderr ke file, tampilkan stdout ke layar, dan juga simpan stdout ke file:
EDIT : Untuk menampilkan stderr dan stdout ke layar dan juga menyimpan keduanya ke file, Anda dapat menggunakan pengalihan I / O bash :
sumber
Dengan kata lain, Anda ingin mem-pipe stdout ke satu filter (
tee bbb.out
) dan stderr ke filter lain (tee ccc.out
). Tidak ada cara standar untuk menyalurkan apa pun selain stdout ke perintah lain, tetapi Anda dapat menyiasatinya dengan menyulap file deskriptor.Lihat juga Bagaimana cara menerima aliran kesalahan standar (stderr)? dan Kapan Anda akan menggunakan deskriptor file tambahan?
Di bash (dan ksh dan zsh), tetapi tidak di shell POSIX lain seperti tanda hubung, Anda dapat menggunakan subtitusi proses :
Hati-hati bahwa dalam bash, perintah ini kembali segera setelah
./aaa.sh
selesai, bahkan jikatee
perintah masih dijalankan (ksh dan zsh menunggu subproses). Ini mungkin masalah jika Anda melakukan sesuatu seperti./aaa.sh > >(tee bbb.out) 2> >(tee ccc.out); process_logs bbb.out ccc.out
. Dalam hal ini, gunakan juggling deskriptor file atau ksh / zsh sebagai gantinya.sumber
sh
, berguna untuk pekerjaan cron, di mana proses substitusi tidak tersedia.Jika menggunakan bash:
Kredit (tidak menjawab dari atas kepala saya) ada di sini: http://www.cygwin.com/ml/cygwin/2003-06/msg00772.html
sumber
Dalam kasus saya, skrip menjalankan perintah sambil mengarahkan stdout dan stderr ke file, seperti:
Saya perlu memperbaruinya sehingga ketika ada kegagalan, mengambil beberapa tindakan berdasarkan pesan kesalahan. Tentu saja saya bisa menghapus dup
2>&1
dan menangkap stderr dari skrip, tetapi kemudian pesan kesalahan tidak akan masuk ke file log untuk referensi. Sementara jawaban yang diterima dari @lhunath seharusnya melakukan hal yang sama, itu mengarahkanstdout
danstderr
ke file yang berbeda, yang bukan yang saya inginkan, tetapi membantu saya untuk menemukan solusi tepat yang saya butuhkan:Dengan di atas, log akan memiliki salinan keduanya
stdout
danstderr
dan saya dapat mengambilstderr
dari skrip saya tanpa harus khawatirstdout
.sumber
Berikut ini akan bekerja untuk KornShell (ksh) di mana proses substitusi tidak tersedia,
Trik sebenarnya di sini, adalah urutan
2>&1 1>&3
yang dalam kasus kami mengarahkan ulangstderr
kestdout
dan mengarahkanstdout
ke deskripsi3
. Pada titik inistderr
danstdout
belum digabungkan.Akibatnya,
stderr
(asstdin
) dilewatkan ketee
tempat ia masukstderr.log
dan juga pengalihan ke deskriptor 3.Dan deskriptor
3
mencatatnyacombined.log
sepanjang waktu. Jadicombined.log
mengandung keduanyastdout
danstderr
.sumber
Jika Anda menggunakan zsh , Anda dapat menggunakan beberapa pengalihan, sehingga Anda bahkan tidak perlu
tee
:Di sini Anda hanya mengarahkan setiap aliran ke dirinya sendiri dan file target.
Contoh lengkap
Perhatikan bahwa ini membutuhkan
MULTIOS
opsi yang akan ditetapkan (yang merupakan default).sumber