Jadi saya ingin menyumbangkan jawaban seperti lesmana, tetapi saya pikir jawaban saya mungkin sedikit lebih sederhana dan sedikit lebih menguntungkan dari solusi Bourne-shell:
# You want to pipe command1 through command2:
exec 4>&1
exitstatus=`{ { command1; printf $? 1>&3; } | command2 1>&4; } 3>&1`
# $exitstatus now has command1's exit status.
Saya pikir ini paling baik dijelaskan dari dalam ke luar - command1 akan menjalankan dan mencetak output regulernya di stdout (file descriptor 1), kemudian setelah selesai, printf akan mengeksekusi dan mencetak kode keluar icommand1 pada stdout-nya, tetapi stdout itu diarahkan ke deskriptor file 3.
Ketika command1 sedang berjalan, stdout-nya sedang dipipakan ke command2 (output printf tidak pernah membuatnya ke command2 karena kita mengirimnya ke file descriptor 3, bukan 1, yang dibaca oleh pipa). Kemudian kita mengarahkan output command2 ke file descriptor 4, sehingga ia juga tetap keluar dari file descriptor 1 - karena kita ingin file descriptor 1 gratis sebentar kemudian, karena kita akan membawa output printf pada file descriptor 3 kembali ke file descriptor 1 - karena itulah substitusi perintah (backticks), akan menangkap dan itulah yang akan ditempatkan ke dalam variabel.
Bit terakhir sihir adalah yang pertama exec 4>&1
kita lakukan sebagai perintah terpisah - itu membuka file descriptor 4 sebagai salinan stdout shell eksternal. Substitusi perintah akan menangkap apa pun yang tertulis pada standar keluar dari perspektif perintah di dalamnya - tetapi karena output command2 akan mengajukan deskriptor 4 sejauh menyangkut substitusi perintah, substitusi perintah tidak menangkapnya - namun begitu mendapat "keluar" dari substitusi perintah itu secara efektif masih pergi ke file deskriptor keseluruhan skrip 1.
(Itu exec 4>&1
harus menjadi perintah terpisah karena banyak shell umum tidak suka ketika Anda mencoba menulis ke deskriptor file di dalam substitusi perintah, yang dibuka di "eksternal" perintah yang menggunakan substitusi. Jadi ini adalah cara portabel paling sederhana untuk melakukannya.)
Anda dapat melihatnya dengan cara yang kurang teknis dan lebih menyenangkan, seolah-olah output dari perintah saling melompati satu sama lain: command1 pipa ke command2, maka output printf melompati perintah 2 sehingga perintah2 tidak menangkapnya, dan kemudian output perintah 2 melompati dan keluar dari substitusi perintah sama seperti printf mendarat tepat pada waktunya untuk ditangkap oleh substitusi sehingga berakhir di variabel, dan output command2 berjalan dengan cara yang menyenangkan ditulis ke output standar, sama seperti dalam pipa normal.
Juga, seperti yang saya mengerti, $?
masih akan berisi kode kembali dari perintah kedua dalam pipa, karena penugasan variabel, penggantian perintah, dan perintah majemuk semuanya secara efektif transparan ke kode pengembalian dari perintah di dalamnya, sehingga status pengembalian dari command2 harus disebarkan - ini, dan tidak harus mendefinisikan fungsi tambahan, itulah mengapa saya pikir ini mungkin solusi yang agak lebih baik daripada yang diusulkan oleh lesmana.
Menurut peringatan lesmana, ada kemungkinan bahwa command1 pada akhirnya akan menggunakan deskriptor file 3 atau 4, jadi agar lebih kuat, Anda akan melakukan:
exec 4>&1
exitstatus=`{ { command1 3>&-; printf $? 1>&3; } 4>&- | command2 1>&4; } 3>&1`
exec 4>&-
Perhatikan bahwa saya menggunakan perintah majemuk dalam contoh saya, tetapi subkulit (menggunakan ( )
alih-alih { }
juga akan berfungsi, meskipun mungkin kurang efisien.)
Perintah mewarisi deskriptor file dari proses yang meluncurkannya, sehingga seluruh baris kedua akan mewarisi deskriptor file empat, dan perintah gabungan diikuti oleh 3>&1
akan mewarisi deskriptor file tiga. Jadi 4>&-
memastikan bahwa perintah inner compound tidak akan mewarisi file descriptor empat, dan 3>&-
tidak akan mewarisi file deskriptor tiga, jadi command1 mendapat lingkungan yang lebih bersih dan lebih standar. Anda juga bisa memindahkan bagian dalam 4>&-
ke sebelah 3>&-
, tapi saya pikir mengapa tidak membatasi ruang lingkupnya sebanyak mungkin.
Saya tidak yakin seberapa sering hal menggunakan deskriptor file tiga dan empat secara langsung - Saya pikir sebagian besar program waktu menggunakan syscalls yang mengembalikan deskriptor file yang tidak digunakan saat ini, tetapi kadang-kadang kode menulis ke deskriptor file 3 secara langsung, saya tebak (saya bisa membayangkan sebuah program memeriksa deskriptor file untuk melihat apakah itu terbuka, dan menggunakannya jika ada, atau berperilaku berbeda sesuai jika tidak). Jadi yang terakhir mungkin terbaik untuk diingat dan digunakan untuk kasus-kasus tujuan umum.