Itu karena pilihan dalam implementasi.
Menjalankan skrip yang sama pada Solaris dengan ksh93
menghasilkan perilaku yang berbeda:
$ while /usr/bin/true ; do echo "ok" | cat ; done | exit 1
cat: write error [Broken pipe]
Apa yang memicu masalah adalah pipa bagian dalam, tanpanya, loop akan keluar dari shell/OS apa pun:
$ while /usr/bin/true ; do echo "ok" ; done | exit 1
$
cat
mendapatkan sinyal SIGPIPE di bawah bash tetapi shell tetap mengulang loop.
Process 5659 suspended
[pid 28801] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
[pid 28801] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28801 detached
Process 28800 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Process 28802 attached
Process 28803 attached
[pid 28803] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
Process 5659 suspended
[pid 28803] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28803 detached
Process 28802 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Process 28804 attached
Process 28805 attached (waiting for parent)
Process 28805 resumed (parent 5659 ready)
Process 5659 suspended
[pid 28805] execve("/bin/cat", ["cat"], [/* 63 vars */]) = 0
[pid 28805] --- SIGPIPE (Broken pipe) @ 0 (0) ---
Process 5659 resumed
Process 28805 detached
Process 28804 detached
--- SIGCHLD (Child exited) @ 0 (0) ---
Bash dokumentasi menyatakan:
Shell menunggu semua perintah dalam pipeline untuk menghentikan sebelum mengembalikan nilai.
Ksh dokumentasi menyatakan:
Setiap perintah, kecuali mungkin yang terakhir, dijalankan sebagai proses terpisah; shell menunggu perintah terakhir untuk mengakhiri.
POSIX menyatakan:
Jika pipeline tidak berada di latar belakang (lihat Daftar Asinkron), shell akan menunggu perintah terakhir ditentukan dalam pipeline untuk diselesaikan, dan mungkin juga menunggu semua perintah untuk menyelesaikan.
Masalah ini telah mengganggu saya selama bertahun-tahun. Terima kasih kepada jilliagre atas dorongan ke arah yang benar.
Ulangi sedikit pertanyaan, di kotak linux saya, ini berhenti seperti yang diharapkan:
while true ; do echo "ok"; done | head
Tetapi jika saya menambahkan pipa, itu tidak berhenti seperti yang diharapkan:
while true ; do echo "ok" | cat; done | head
Itu membuat saya frustrasi selama bertahun-tahun. Dengan mempertimbangkan jawaban yang ditulis oleh jilliagre, saya menemukan perbaikan yang luar biasa ini:
while true ; do echo "ok" | cat || exit; done | head
Q.E.D. ...
Yah, tidak cukup. Ini sesuatu yang sedikit lebih rumit:
i=0
while true; do
i=`expr $i + 1`
echo "$i" | grep '0$' || exit
done | head
Ini tidak bekerja dengan benar. Saya menambahkan || exit
jadi ia tahu cara mengakhiri lebih awal, tetapi echo
pertama tidak cocok dengan grep
jadi loop berhenti segera. Dalam hal ini, Anda benar-benar tidak tertarik dengan status keluar dari grep
. Solusi saya adalah menambahkan cat
lainnya . Jadi, inilah skrip buatan yang disebut "puluhan":
#!/bin/bash
i=0
while true; do
i=`expr $i + 1`
echo "$i" | grep '0$' | cat || exit
done
Ini berakhir dengan benar ketika dijalankan sebagai tens | head
. Terima kasih Tuhan.