Tôi đang sử dụng `&`: tại sao quá trình không chạy trong nền?


24

Tôi biết rằng tôi có thể nối thêm &một lệnh để chạy tiến trình trong nền.

Tôi đang SSH vào hộp Ubuntu 12.04 và chạy chương trình python với $python program.py &- nhưng khi tôi đóng cửa sổ thiết bị đầu cuối, tôi nhận được một thông báo nói rằng việc đóng thiết bị đầu cuối sẽ giết quá trình đang chạy.

Tại sao lại thế này? Tôi đang sử dụng ký hiệu và để chạy quá trình trong nền. Làm cách nào tôi có thể chạy nó bất kể tôi có SSH không?



màn hình cài đặt apt-get, màn hình người đàn ông
captcha

Câu trả lời:


51

Khi bạn đóng một cửa sổ đầu cuối, trình giả lập thiết bị đầu cuối sẽ gửi SIGHUP tới tiến trình mà nó đang chạy, trình bao của bạn. Vỏ của bạn sau đó chuyển tiếp SIGHUP tới mọi thứ nó đang chạy. Trên hệ thống cục bộ của bạn, đây là ssh. Sau đó, ssh chuyển tiếp SIGHUP tới những gì nó đang chạy, vỏ từ xa. Vì vậy, shell từ xa của bạn sau đó gửi SIGHUP cho tất cả các quy trình của nó, chương trình nền của bạn.

Có 2 cách xung quanh điều này.

  1. Phân tách chương trình nền từ vỏ của bạn.
    1. Sử dụng disownlệnh sau khi nền quá trình của bạn. Điều này sẽ làm cho vỏ quên nó.
    2. Tiền tố lệnh của bạn với nohup( nohup $python program.py &). Điều này thực hiện điều tương tự, nhưng bằng cách sử dụng một quá trình trung gian. Về cơ bản, nó bỏ qua tín hiệu SIGHUP, sau đó rẽ nhánh và thực thi chương trình của bạn kế thừa cài đặt và sau đó thoát. Bởi vì nó rẽ nhánh, chương trình được khởi chạy không phải là con của vỏ và vỏ không biết về nó. Và trừ khi nó cài đặt một trình xử lý tín hiệu cho SIGHUP, dù sao thì nó vẫn giữ hành động bỏ qua.
  2. Sử dụng logoutthay vì đóng cửa sổ terminal. Khi bạn sử dụng logout, đây không phải là SIGHUP và vì vậy, vỏ sẽ không gửi SIGHUP cho bất kỳ đứa con nào của nó.

Ngoài ra, bạn phải đảm bảo rằng chương trình của bạn không ghi vào thiết bị đầu cuối thông qua STDOUT hoặc STDERR, vì cả hai sẽ không còn tồn tại khi thiết bị đầu cuối thoát. Nếu bạn không chuyển hướng chúng đến một cái gì đó giống như /dev/null, chương trình vẫn sẽ chạy, nhưng nếu nó cố gắng viết cho chúng, nó sẽ nhận được SIGPIPE và hành động mặc định của SIGPIPE là giết tiến trình).


4
Về mặt kỹ thuật, sshchết khiến kết nối bị rớt, kết nối bị rớt khiến sshdđầu bên kia chết. Sshd đó điều khiển phía chủ của thiết bị đầu cuối giả mà vỏ từ xa chạy, khi nó chết, đó là một cúp máy (giống như rút phích cắm trên thiết bị đầu cuối thực), vì vậy hệ thống sẽ gửi SIGHUP đến vỏ từ xa.
Stéphane Chazelas

@ StéphaneChazelas Đó là một điều tôi chưa bao giờ tìm hiểu. Nếu đó là kernel làm việc đó, làm thế nào để xác định quá trình nào để SIGHUP? Rõ ràng nó không SIGHUP mọi thứ với một bộ mô tả tệp mở cho TTY đó, vì các chương trình sẽ vẫn chạy miễn là chúng không cố gắng sử dụng nó. Vì vậy, nó có chọn chương trình hiện đang đọc từ STDIN (vì mỗi lần chỉ có thể đọc từ STDIN) không?
Patrick

4
Đừng bận tâm, trả lời câu hỏi của riêng tôi. POSIX IEEE 1003.1 chương 11, Nếu giao diện đầu cuối được phát hiện bởi giao diện đầu cuối cho thiết bị đầu cuối điều khiển ... tín hiệu SIGHUP sẽ được gửi đến quá trình điều khiển .
Patrick

2
Cũng lưu ý rằng nohuptạo một nohup.outtệp có đầu ra của chương trình bạn bắt đầu với nó. Có thể khó chịu khi xóa tệp đó mỗi khi bạn sử dụng nohup để khởi động ứng dụng theo cách này (hoặc bạn cần chuyển hướng đầu ra của nó sang /dev/null).
Ruslan

1
Thay vì nohup python program.py &tôi khuyên bạn nên sử dụng setsid python program.pythay vào đó, điều này ngay lập tức từ chối chương trình.
Hitechcomputergeek

14

Quá trình đang chạy trong nền trong thiết bị đầu cuối, nhưng đầu ra từ stdout(và stderr) vẫn đang được gửi đến thiết bị đầu cuối. Để ngăn chặn điều này, hãy thêm > /dev/null 2>&1trước khi &chuyển hướng cả hai đầu ra sang /dev/null- thêm disowncũng đảm bảo quá trình không bị hủy sau khi bạn đóng thiết bị đầu cuối:

COMMAND > /dev/null 2>&1 & disown

Trong trường hợp của bạn, điều này sẽ là:

python program.py > /dev/null 2>&1 & disown

3

Các &lệnh tách điều hành để chạy song song, cũng giống như ;tách các lệnh để chạy trong loạt. Cả hai loại lệnh vẫn sẽ chạy như một phần tử con của quá trình shell .

Vì vậy, khi bạn đóng cái vỏ bắt đầu những đứa trẻ đó, những đứa trẻ cũng sẽ bị đóng lại.

Những gì bạn dường như muốn là một quy trình daemon , khó khăn hơn đáng kể bởi vì nó cần phải phân tách hoàn toàn khỏi quy trình cha mẹ. Vỏ thường không có cách đơn giản để làm điều đó.


1

Khi bạn đăng xuất, các quy trình nền liên quan đến phiên đăng nhập cũng thường bị hủy. Nếu bạn muốn ngắt kết nối chúng khỏi phiên, hãy chạy chúng với nohup.

nohup python program.py &

1

Sau khi lệnh kết thúc bằng ampersand ( &), tại dấu nhắc lệnh chạy lệnh bg:

bash> python program.py &  
bash> bg  

Điều này sẽ đặt lệnh "&" xuống nền

bash> jobs  

Điều này sẽ liệt kê các công việc đang chạy trong nền

bash> fg 1   

Điều này sẽ đưa Công việc số 1 lên tiền cảnh

Một cách khác, (để có thể đăng xuất)

bash> at now  
bash> /full/path/python /full/path/program.py  
bash> ^d   `(# That is, Control-D, to run the command, Control-C to cancel)`  

Nhiều dòng có thể được nộp cho cơ atlệnh, trước ^ d (Control-D)
thấy man at.

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.