Điều này dường như làm việc:
#!/bin/sh
pressed_ctrl_c=
trap "pressed_ctrl_c=1" INT
while true
do
(trap "" INT; foo)&
wait || wait
if [ "$pressed_ctrl_c" ]
then
# echo
break
fi
done
- Khởi tạo
pressed_ctrl_c
thành null. Điều này có lẽ không cần thiết trong một kịch bản.
trap command signum
báo cho shell được thiết lập để bắt số tín hiệu signum
và thực thi command
khi bắt được một tín hiệu . Đây là từ viết tắt của cụm từ SIGINT, viết tắt của cụm từ SIGINT, viết tắt của tiếng Anh, đó là thuật ngữ kỹ thuật cho tín hiệu được tạo bởi Ctrl+ C, vì vậy, khi bạn nhập Ctrl+ C, trình bao đặt pressed_ctrl_c
thành 1. (SIGINT có giá trị số là 2, vì vậy bạn có thể nói trap "pressed_ctrl_c=1" 2
nếu bạn muốn tiết kiệm khi gõ.)
- Trong vòng lặp, chúng ta có một dòng lệnh trong ngoặc đơn. Điều này tạo ra một vỏ phụ.
- Chúng tôi sử dụng
trap
lệnh một lần nữa. Lần này command
là một chuỗi null; Điều này nói với vỏ để bỏ qua số tín hiệu signum
. Vì đây là bên trong dấu ngoặc đơn, nó chỉ ảnh hưởng đến lớp con.
- Chạy đi
foo
. Vì nó được chạy từ subshell,
foo
sẽ bỏ qua Ctrl+ C, tức là, nó sẽ tiếp tục chạy ngay cả khi bạn gõ nó.
- Đặt subshell trong nền nền.
- Càng và chờ nó hoàn thành.
- Nếu
wait
lệnh thành công, đi đến if
câu lệnh. Nếu thất bại, thực hiện một cái khác. (Tôi sẽ quay lại vấn đề này.)
- Nếu
$pressed_ctrl_c
được đặt, thoát ra khỏi vòng lặp. Tùy chọn bỏ ghi echo
lệnh nếu Ctrl+ Cxuất hiện trên thiết bị đầu cuối của bạn ^C
và bạn muốn chuyển sang dòng tiếp theo.
Chúng tôi chạy một lệnh trong nền, và sau đó ngay lập tức wait
cho nó. Điều này rất giống với việc chạy lệnh ở nền trước (ít nhất, khi được thực hiện trong một tập lệnh). Các wait
lệnh sẽ chấm dứt thành công khi subshell chấm dứt; tức là khi foo
lệnh kết thúc ( wait
Lệnh sẽ chấm dứt thành công ngay cả khi foo
trả về lỗi.) Khi wait
lệnh đầu tiên kết thúc thành công, chúng ta bỏ qua lệnh thứ hai và đi đến if
.
Lớp vỏ đang chạy vòng lặp đang bị gián đoạn, nhưng lớp vỏ, và do đó, foo
quá trình này đang bỏ qua chúng. Vì vậy, khi bạn gõ Ctrl+ C, shell sẽ đặt pressed_ctrl_c
thành 1 và hủy bỏ lệnh (đầu tiên) wait
. Vì wait
lệnh đầu tiên thất bại, chúng tôi chuyển sang lệnh thứ hai. Hãy nhớ rằng, foo
lớp con vẫn đang chạy, vì vậy điều này wait
vẫn còn một việc phải làm (nghĩa là nó sẽ đợi cho foo
đến khi kết thúc.)
Cuối cùng, nếu biến đã được đặt để chỉ ra rằng dấu Ctrl+ Cđã được nhấn trong khi foo
đang chạy, ngắt đầu ra vòng lặp.
Nếu bạn nhấn Ctrl+ Chai lần, cái thứ hai sẽ ngắt và hủy bỏ wait
lệnh thứ hai . Điều này sẽ khiến tập lệnh của bạn chấm dứt và đưa bạn trở lại dấu nhắc shell của bạn, trong khi vẫn foo
chạy trong nền. Bạn có thể giảm thiểu điều này bằng cách nói wait || wait || wait || wait
; mở rộng nó như xa như bạn muốn. Bạn sẽ cần gõ Ctrl+ Cmột lần cho mỗi lần wait
để kết thúc tập lệnh sớm.
Ôi!
Một vấn đề với điều này là các quy trình được đặt vào nền bởi một tập lệnh có đầu vào tiêu chuẩn của chúng được đặt thành /dev/null
. Nếu bạn foo
đọc từ bàn phím, ở trên sẽ cần sửa đổi.