Bắt đầu một quá trình nền từ một kịch bản và quản lý nó khi kịch bản kết thúc


15

Tôi muốn chạy và cấu hình một quy trình tương tự như một daemon từ một tập lệnh.
Shell của tôi là zsh được mô phỏng theo Cygwin và daemon là SFK , một máy chủ FTP cơ bản.

Đối với những gì quan trọng ở đây, kịch bản startserv.shcó thể được soạn thảo như sau:

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
$cmd &

Sau khi chạy tập lệnh startserv.sh, nó dừng (kết thúc?) Mà không hiển thị bất kỳ dấu nhắc nào, sau đó:

  • CTRL+ Ckết thúc cả kịch bản và quá trình công việc nền;

  • Đánh Entervào kịch bản kết thúc quá trình vẫn còn trong nền.

Dù sao tôi chỉ có thể nhìn thấy nó qua psvà không jobs, vì vậy, khi tôi muốn đóng quá trình, tôi phải gửi một kill -9tín hiệu tàn bạo , đó là điều tôi muốn tránh để ủng hộ CTRL+ C.

Một thay thế sẽ được chạy toàn bộ kịch bản trong nền. 'Sẽ là', nhưng readlệnh không thể nhận được đầu vào của người dùng nếu tập lệnh được chạy dưới dạng startserv.sh &.

Lưu ý rằng tôi cần một máy chủ phù du, không phải là một trình nền thực sự : nghĩa là tôi muốn quá trình máy chủ chạy ở chế độ nền, sau khi tập lệnh kết thúc, để thực hiện các tác vụ shell tương tác đơn giản (với một máy khách ảo), nhưng tôi không ' t cần quá trình để tồn tại vỏ; do đó nohupcó vẻ không phù hợp.


lấy id quá trình của tiến trình đang chạy trong nền bằng cách sử dụng bgproc="$!"và sau đó command "$bgproc" thực hiện hành động thích hợp. Xem thêm stackoverflow.com/questions/1908610/ Mạnh
Valentin Bajrami

bạn cũng có thể tạo một tập tin PID. Sau đó đọc tệp đó để xem số quá trình đó là gì và đi từ đó.
jgr208

Câu trả lời:


18

Đánh Entervào kịch bản kết thúc quá trình vẫn còn trong nền.

Hầu hết! Trên thực tế, kịch bản đã thoát khi bạn nhấn Enter. Tuy nhiên, đó là cách bạn có thể lấy lại lời nhắc của mình (vì vỏ của bạn in lại $PS1tất cả).

Lý do tại sao nhấn Ctrl+ Cchấm dứt cả hai là vì hai trong số chúng được liên kết. Khi bạn thực thi tập lệnh của mình, trình bao của bạn sẽ khởi tạo một lớp con để chạy tập lệnh này. Khi bạn chấm dứt lớp con này, quá trình nền của bạn sẽ chết, có thể là do SIGHUPtín hiệu.

Phân tách tập lệnh, quá trình nền và lớp con

Sử dụng nohup, bạn có thể thoát khỏi sự bất tiện nhỏ này.

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

Sự disownthay thế

Nếu bạn có thể chuyển từ /bin/shsang /bin/bash, bạn cũng có thể thử disown. Để biết thêm, chỉ cần gõ help disownmột bashví dụ.

disown -h $cmd &

Giết quá trình nền "độc đáo"

Bây giờ, khi nói đến việc giết chết quá trình của bạn, bạn hoàn toàn có thể thực hiện " Ctrl+ C" bằng cách sử dụng kill. Chỉ cần không gửi một tàn bạo SIGKILL. Thay vào đó, bạn có thể sử dụng:

$ kill -2 [PID]
$ kill -15 [PID]

Điều này sẽ gửi một SIGINT(2) hoặc SIGTERM(15) tốt đẹp cho quá trình của bạn. Bạn cũng có thể muốn in giá trị PID sau khi bắt đầu quá trình:

...
nohup $cmd &
echo $!

... Hoặc thậm chí tốt hơn, làm cho tập lệnh chờ a SIGINTvà gửi nó trở lại quá trình nền (điều này sẽ giữ cho tập lệnh của bạn ở phía trước) :

#!/bin/sh
read -s -p "Enter Password: " pw
user=testuser
share=/fshare
cmd="sfk ftpserv -user=$user -pw=$pw -usedir $share=$share"
nohup $cmd &

# Storing the background process' PID.
bg_pid=$!

# Trapping SIGINTs so we can send them back to $bg_pid.
trap "kill -2 $bg_pid" 2

# In the meantime, wait for $bg_pid to end.
wait $bg_pid

Nếu SIGINTkhông đủ, chỉ cần sử dụng SIGTERMthay thế (15):

trap "kill -15 $bg_pid" 2 15

Bằng cách này, khi tập lệnh của bạn nhận được SIGINT( Ctrl+ C, kill -2) hoặc một SIGTERMlúc trong waitquá trình nền, nó sẽ chuyển tiếp các tín hiệu đến nó. Nếu các tín hiệu này giết chết sfkthể hiện, thì waitcuộc gọi sẽ trở lại, do đó cũng chấm dứt tập lệnh của bạn :)


1
+1 Rất nhiều thông tin. Vì tập lệnh chạy trong một lớp con, có khả năng truy cập từ tập lệnh vào bảng công việc của trình bao cha của tập lệnh không? Đó là danh sách các công việc phát hành jobstrong thiết bị đầu cuối sau khi tập lệnh kết thúc (thay vì ps).
antonio

1
Các công việc được liên kết với shell hiện tại của bạn, chúng không được truyền từ shell này sang shell khác. Khi subshell của bạn chết, công việc của nó không được phục hồi. Bằng cách in PID của quy trình nền của bạn, bạn đảm bảo rằng bạn có thể nhận được thông tin về nó một cách dễ dàng ngay cả khi lớp con đã kết thúc ( pid -p).
John WH Smith

giải thích hay, tuy nhiên nếu tập lệnh của bạn chứa nhiều lệnh hơn, chúng sẽ không bao giờ được thực thi (vì wait). Nếu bạn loại bỏ sự chờ đợi, thì việc xử lý tín hiệu bị hỏng: /
Chefarov
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.