Saya mencoba memahami bagaimana status keluar dikomunikasikan ketika pipa digunakan. Misalkan saya menggunakan which
untuk mencari program yang tidak ada:
which lss
echo $?
1
Karena which
gagal mencari lss
saya mendapat status keluar dari 1. Ini baik-baik saja. Namun ketika saya coba yang berikut ini:
which lss | echo $?
0
Ini menunjukkan bahwa perintah terakhir yang dijalankan telah keluar secara normal. Satu-satunya cara saya dapat memahami ini adalah bahwa mungkin PIPE juga menghasilkan status keluar. Apakah ini cara yang tepat untuk memahaminya?
bash
shell-script
pipe
exit
sshekhar1980
sumber
sumber
which lss | echo $?
,echo
dimulai sebelumwhich
telah keluar; shell yang menghasilkan baris perintah untukecho
tidak memiliki cara yang mungkin untuk mengetahui apa status keluarwhich
nantinya.Jawaban:
Status keluar dari pipa adalah status keluar dari perintah terakhir dalam pipa (kecuali jika opsi shell
pipefail
diatur dalam shell yang mendukungnya, dalam hal ini status keluar akan menjadi dari perintah terakhir dalam pipa yang keluar dengan status bukan nol).Tidak mungkin untuk mengeluarkan status keluar dari pipa dari dalam pipa, karena tidak ada cara untuk mengetahui apa nilai itu sampai pipa benar-benar selesai dieksekusi.
Pipa
tidak masuk akal karena
echo
tidak membaca input standarnya (pipa digunakan untuk melewatkan data antara output dari satu perintah ke input yang berikutnya). Ituecho
juga tidak akan mencetak status keluar dari pipa, tetapi status keluar dari perintah dijalankan segera sebelum pipa.Ini adalah contoh yang lebih baik:
Ini berarti bahwa saluran pipa juga dapat digunakan dengan
if
:sumber
Status keluar dari pipa adalah status keluar dari perintah sebelah kanan. Status keluar dari perintah sebelah kiri diabaikan.
(Catatan yang
which lss | echo $?
tidak menunjukkan ini. Anda akan menjalankanwhich lss | true; echo $?
untuk menunjukkan ini. Dalamwhich lss | echo $?
,echo $?
melaporkan status perintah terakhir sebelum pipa ini.)Alasan shell berperilaku seperti ini adalah bahwa ada skenario yang cukup umum di mana kesalahan di sisi kiri harus diabaikan. Jika sisi kanan keluar (atau lebih umum menutup input standarnya) ketika sisi kiri masih menulis, maka sisi kiri menerima sinyal SIGPIPE. Dalam hal ini, biasanya tidak ada yang salah: sisi kanan tidak peduli dengan data; jika peran sisi kiri semata-mata untuk menghasilkan data ini maka tidak masalah untuk menghentikannya.
Namun, jika sisi kiri mati karena alasan lain selain SIGPIPE, atau jika pekerjaan sisi kiri tidak hanya menghasilkan data pada output standar, maka kesalahan di sisi kiri adalah kesalahan asli yang harus dilaporkan.
Di sh polos, satu-satunya solusi adalah dengan menggunakan pipa bernama.
Dalam ksh, bash, dan zsh, Anda dapat menginstruksikan shell untuk membuat pipa keluar dengan status bukan nol jika ada komponen pipa keluar dengan status bukan nol. Anda perlu mengatur
pipefail
opsi:set -o pipefail
shopt -s pipefail
setopt pipefail
(atausetopt pipe_fail
)Di mksh, bash dan zsh, Anda bisa mendapatkan status setiap komponen pipa menggunakan variabel
PIPESTATUS
(bash, mksh) ataupipestatus
(zsh), yang merupakan larik yang berisi status semua perintah dalam pipa terakhir (generalisasi dari$?
).sumber
Ya, PIPE menghasilkan status keluar; jika Anda ingin kode keluar dari perintah sebelum PIPE, Anda dapat menggunakan
$PIPESTATUS
Menurut T&J Stack Overflow ini , untuk mencetak status keluar dari sebuah perintah saat Anda menggunakan pipa, Anda dapat melakukannya:
Atau atur pipefail dengan perintah
set -o pipefail
(untuk membatalkannya , lakukanset +o pipefail
), dan gunakan$?
sebagai ganti$PIPESTATUS
.Perintah-perintah ini hanya berfungsi setelah Anda menjalankannya setidaknya satu kali; itu berarti
PIPESTATUS
hanya berfungsi ketika Anda menjalankannya setelah perintah dengan pipa, seperti ini:Anda akan mendapatkan 10 untuk
${PIPESTATUS[0]}
dan 1 untuk${PIPESTATUS[1]}
. Lihat U&L Q&A ini untuk informasi lebih lanjut.sumber
PIPESTATUS
berisi status keluar dari perintah di pipa terakhir, contoh pertama Anda tidak lebih masuk akal daripadasomecmd | echo $?
, yang ditangani Kusalananda dalam jawaban mereka.false; true | echo $PIPESTATUS
mencetak1
untuk status keluar darifalse
.|exho
benar-benar membingungkanShell mengevaluasi baris perintah sebelum pipa dieksekusi. Begitu
$?
juga dengan nilai dari perintah terakhir yang dieksekusi sebelum pipeline. Apakahecho
itu dimulai sebelum atau sesudahwhich
tidak relevan.Sekarang jika pertanyaan Anda secara khusus tentang penyebaran status keluar, Anda dapat mempelajari perilaku default seperti ini:
Seperti yang Anda lihat, status keluar dari sebuah pipa adalah status keluar dari perintah terakhirnya.
sumber