GNU/Linux >> Belajar Linux >  >> Linux

mengapa bash while loop tidak keluar saat menyalurkan ke subperintah yang diakhiri?

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.


Linux
  1. Skrip Linux:3 cara untuk while loop di Bash

  2. Mengapa Bash Prompt Disadap Saat Saya Menelusuri Riwayat??

  3. Kode Keluar Default Saat Proses Dihentikan?

  1. Contoh Bash For Loop dan While Loop

  2. Cara mendapatkan status keluar satu lingkaran di bash

  3. Bash:Ulangi hingga status keluar perintah sama dengan 0

  1. Mengapa Skrip Bash Tidak Keluar Setelah Eksekusi?

  2. Mengapa Bash `(())` tidak berfungsi di dalam `[[]]`?

  3. Mengapa vfork() dimaksudkan untuk digunakan ketika proses anak memanggil exec() atau exit() segera setelah pembuatan?