Đ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_cthành null. Điều này có lẽ không cần thiết trong một kịch bản.
trap command signumbáo cho shell được thiết lập để bắt số tín hiệu signum
và thực thi commandkhi 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_cthành 1. (SIGINT có giá trị số là 2, vì vậy bạn có thể nói trap "pressed_ctrl_c=1" 2nế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
traplệnh một lần nữa. Lần này commandlà 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,
foosẽ 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
waitlệnh thành công, đi đến ifcâ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 echolệ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 waitcho 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 waitlệnh sẽ chấm dứt thành công khi subshell chấm dứt; tức là khi foolệnh kết thúc ( waitLệnh sẽ chấm dứt thành công ngay cả khi footrả về lỗi.) Khi waitlệ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 đó, fooquá trình này đang bỏ qua chúng. Vì vậy, khi bạn gõ Ctrl+ C, shell sẽ đặt pressed_ctrl_cthành 1 và hủy bỏ lệnh (đầu tiên) wait. Vì waitlệnh đầu tiên thất bại, chúng tôi chuyển sang lệnh thứ hai. Hãy nhớ rằng, foolớp con vẫn đang chạy, vì vậy điều này waitvẫ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ỏ waitlệ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 foochạ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.