Dengan bash, bagaimana cara menyalurkan kesalahan standar ke proses lain?

140

Sudah diketahui dengan baik cara menyalurkan output standar dari suatu proses ke input standar proses lain:

proc1 | proc2

Tetapi bagaimana jika saya ingin mengirim kesalahan standar proc1 ke proc2 dan membiarkan keluaran standar pergi ke lokasinya saat ini? Anda akan berpikir bashakan memiliki perintah di sepanjang baris:

proc1 2| proc2

Tapi, sayang, tidak. Apakah ada cara untuk melakukan ini?

paxdiablo
sumber
Anda dapat melakukan pengalihan sederhana seperti itu rc, yang merupakan shell lain. Misalnya: proc1 |[2] proc2. Bukankah itu bagus? Tapi tidak bash.
Rolf

Jawaban:

173

Ada juga substitusi proses . Yang membuat proses menggantikan file.
Anda dapat mengirim stderrke file sebagai berikut:

process1 2> file

Tetapi Anda dapat mengganti proses untuk file sebagai berikut:

process1 2> >(process2)

Berikut adalah contoh konkret yang dikirim stderrke layar dan ditambahkan ke logfile

sh myscript 2> >(tee -a errlog)
Orang Skotlandia
sumber
24
Ini dengan benar menjawab pertanyaan yang dinyatakan dan harus menjadi jawaban yang diterima oleh @paxdiablo
mmlb
Saya mencoba ini. Itu tidak berhasil ( weston --help 2> >(less)), dan itu merusak cangkang saya, saya harus keluar dan masuk kembali.
Rolf
1
@Rolf jika keduanya weston --helpdan lessmengharapkan untuk memiliki interaksi keyboard tetapi hanya 1 dari mereka yang menerimanya, maka Anda mungkin berada dalam situasi yang canggung. Coba lakukan pengujian dengan sesuatu seperti grep. Plus Anda mungkin menemukan bahwa kedua input mouse / keyboard akan tetap ke perintah ke-2 daripada ke weston.
BeowulfNode42
Jika Anda ingin mengalihkan penggunaan stderr dan stdout |&, saya mempelajarinya dari sini
ᐅ devrimbaris
88

Anda dapat menggunakan trik berikut untuk menukar stdout dan stderr. Kemudian Anda hanya menggunakan fungsi pipa biasa.

( proc1 3>&1 1>&2- 2>&3- ) | proc2

Disediakan stdoutdanstderr keduanya menunjuk ke tempat yang sama di awal, ini akan memberi Anda apa yang Anda butuhkan.

Apa yang dilakukan x>ybit adalah mengubah pegangan file xsehingga sekarang mengirimkan informasinya ke tempat pegangan file ysaat ini menunjuk. Untuk kasus khusus kami:

  • 3>&1membuat pegangan baru3 yang akan menampilkan pegangan saat ini1 (stdout asli), hanya untuk menyimpannya di suatu tempat untuk poin terakhir di bawah.
  • 1>&2memodifikasi pegangan 1(stdout) menjadi keluaran ke pegangan saat ini2 (stderr asli).
  • 2>&3-memodifikasi pegangan 2(stderr) menjadi keluaran ke pegangan saat ini3 (stdout asli) kemudian menutup pegangan 3(melalui -di akhir).

Ini secara efektif adalah perintah swap yang Anda lihat dalam algoritma pengurutan:

temp   = value1;
value1 = value2;
value2 = temp;
paxdiablo
sumber
3
Apa nilai menggunakan di 1>&2-sini daripada hanya 1>&2? Saya tidak mengerti mengapa kami ingin menutup fd 2, jika kami hanya akan membuka kembali / menetapkan ulang segera.
dubiousjim
1
@dubiousjim, tidak ada keuntungan dalam kasus khusus itu, saya rasa saya melakukannya hanya untuk konsisten - menutup pegangan file 3 adalah ide yang baik untuk membebaskannya.
paxdiablo
Poin bagus, @ovgolovin, saya tidak percaya tidak ada yang mengambilnya dalam tujuh bulan sejak saya melakukan pengeditan itu. Diperbaiki sesuai saran Anda.
paxdiablo
mencoba membuat gcc's make (yang diwarnai pada sistem saya) untuk bekerja dengan ini "(make 3> & 1 1> & 2- 2> & 3-) | less -R" sedangkan "(ls -al 3> & 1 1> & 2- 2> & 3-) | less -R "berfungsi seperti yang diharapkan.
tidak
Sepertinya penjelasan Anda kembali ke depan untuk dua pengalihan kedua. 1> & 2- set pegangan file 2 (stderr asli) untuk menangani 1 (stdout asli) 2> & 3- set pegangan file 3 (stdout yang disalin) untuk menangani 2 (stderr asli). Tolong koreksi saya jika saya salah. btw, saya akan menebak bahwa tanda hubung pada 2 adalah untuk mencegah data stderr baru dikirim ke buffer ini saat sedang diisi dengan data dari stdout.
aghsmith
71

Bash 4 memiliki fitur ini:

Jika `| & 'digunakan, kesalahan standar dari command1 terhubung ke input standar perintah2 melalui pipa; ini adalah singkatan dari 2> & 1 |. Pengalihan implisit dari kesalahan standar ini dilakukan setelah pengalihan apa pun yang ditentukan oleh perintah.

zsh juga memiliki fitur ini.

-

Dengan shell lain / lama, masukkan saja ini secara eksplisit sebagai

Perintah Pertama 2> & 1 | Perintah Lain

Dijeda sampai pemberitahuan lebih lanjut.
sumber
14
Dari membaca dokumen, itu melakukan kesalahan standar dan keluaran yang bertentangan dengan hanya stderr, tetapi senang mengetahuinya. Saatnya untuk mulai melihat bash 4, kurasa.
paxdiablo
Manual bash saat ini berbunyi "Jika | & digunakan, kesalahan standar perintah, selain keluaran standarnya, terhubung ke masukan standar perintah2 ". Ini secara eksplisit bukan yang diinginkan OP.
Peter - Kembalikan Monica
@ PeterA.Schneider: OP mengatakan "biarkan output standar pergi ke lokasi saat ini" yang mungkin ambigu.
Dijeda sampai pemberitahuan lebih lanjut.
Saya gagal melihat ambiguitas. Saran Anda (1) menggabungkan dua aliran. (2) OtherCommandmenulis data gabungan di suatu tempat, mungkin di tempat lain. Jadi ini bukan data yang sama, dan berpotensi pergi ke tempat lain. Itu berkebalikan dengan keinginan OP, bukan?
Peter - Kembalikan Monica
@ PeterA.Schneider: Di mana lagi lokasi keluaran standar saat ini? Jika proc1output ke stdout dan ke stderr dan Anda ingin stderr pergi ke stdin proc2(yang mana stdout proc1 akan berjalan), maka jawaban saya menyelesaikannya. Aku memberikan OP apa yang dia minta untuk, mungkin tidak apa yang dimaksudkan untuk meminta. Disinilah potensi ambiguitas. OP menerima jawaban yang menukar stdout dan stderr yang bukan yang dia minta.
Dijeda sampai pemberitahuan lebih lanjut.
28

Pertukaran itu bagus karena menyelesaikan masalah. Kalau-kalau Anda bahkan tidak memerlukan stdout asli, Anda dapat melakukannya dengan cara ini:

proc1 2>&1 1>/dev/null | proc2

Urutan itu penting; Anda tidak ingin:

proc1 >/dev/null 2>&1 | proc1

Karena ini akan mengarahkan semuanya ke /dev/null!

kccqzy.dll
sumber
0

Tak satu pun dari ini benar-benar bekerja dengan baik. Cara terbaik yang saya temukan untuk melakukan apa yang Anda inginkan adalah:

(command < input > output) 2>&1 | less

Ini hanya berfungsi untuk kasus di mana commandtidak memerlukan input keyboard. misalnya:

(gzip -d < file.gz > file) 2>&1 | less

akan mengurangi kesalahan gzip

sbingner
sumber