Làm cách nào để bắt đầu một quy trình ở trạng thái treo trong Linux?


19

Thực tế, tôi cần một quy trình ứng xử, như thể tôi đã nhấn Ctrl+Zngay sau khi nó bắt đầu.

Hy vọng rằng, có thể làm điều đó bằng cách sử dụng một kịch bản shell.

(Ngoài ra, việc biết kết quả PID sẽ rất tuyệt, vì vậy tôi có thể tiếp tục quá trình sau đó.)

Câu trả lời:


7

Sau khi bắt đầu một quy trình, bạn có thể gửi SIGSTOP để tạm dừng nó. Để tiếp tục, gửi SIGCONT. Tôi nghĩ rằng kịch bản nhỏ này có thể giúp bạn

#!/bin/bash
$@ &
PID=$!
kill -STOP $PID
echo $PID
wait $PID

Nó chạy tiến trình (lệnh gửi dưới dạng tham số), tạm dừng nó, in id tiến trình và đợi cho đến khi kết thúc.


1
Tôi đã sửa đổi nó để tiếp tục ở cuối: [enter] #!/bin/bash [enter] $@ & [enter] PID=$! [enter] kill -STOP $PID [enter] echo "Suspended: $PID, press ENTER to continue it" [enter] read [enter] kill -CONT $PID [enter] wait $PID [enter]echo
java.is.for.desktop

7
Chỉ để bạn biết, quy trình con có thể kết thúc trước khi bạn có cơ hội gửi tín hiệu STOP đến nó.
MikeyB

16
Một ngày khác tại các cuộc đua.
ctrl-alt-delor

23

Từ môi trường nào bạn đang tạo ra quá trình?

Nếu bạn đang thực hiện nó từ một môi trường như mã C, bạn có thể rẽ nhánh () và sau đó ở trẻ, gửi SIGSTOP cho chính bạn trước lệnh exec (), ngăn chặn việc thực thi thêm.

Một giải pháp chung chung hơn (có lẽ là tốt nhất) sẽ là tạo ra một sơ khai làm như vậy. Vì vậy, chương trình còn sơ khai sẽ:

  • Lấy các đối số bao gồm tên và đối số của chương trình thực
  • gửi một SIGSTOP cho chính nó
  • exec () chương trình thực với các đối số thích hợp

Điều này sẽ đảm bảo rằng bạn tránh mọi loại điều kiện cuộc đua phải làm với quá trình xử lý mới đi quá xa trước khi bạn có thể gửi tín hiệu đến nó.


Một ví dụ cho shell:

#!/bin/bash
kill -STOP $$
exec "$@"

Và sử dụng codez ở trên:

michael@challenger:~$ ./stopcall.sh ls -al stopcall.sh

[1]+  Stopped                 ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ jobs -l
[1]+ 23143 Stopped (signal)        ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ kill -CONT 23143; sleep 1
-rwxr-xr-x 1 michael users 36 2011-07-24 22:48 stopcall.sh
[1]+  Done                    ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ 

Các jobs -lchỉ ra PID. Nhưng nếu bạn đang thực hiện nó từ một vỏ, bạn không cần trực tiếp PID. Bạn chỉ có thể làm: kill -CONT %1(giả sử bạn chỉ có một công việc).

Làm điều đó với nhiều hơn một công việc? Còn lại như một bài tập cho người đọc :)


Tôi đã hy vọng thực hiện điều này từ một tập lệnh shell ...
java.is.for.desktop

Tuyệt vời, vì bạn muốn thực hiện điều này từ tập lệnh shell, hãy sử dụng chương trình sơ khai.
MikeyB

20

Câu trả lời của MikeyB là chính xác. Từ câu hỏi này trên superuser, đây là một phiên bản ngắn gọn hơn:

( kill -SIGSTOP $BASHPID; exec my_command ) &

Để hiểu điều này, người ta cần hiểu cách các quá trình được bắt đầu trên unix: lệnh execgọi hệ thống thay thế chương trình hiện đang chạy bằng một chương trình mới , bảo toàn bộ PID hiện có. Vì vậy, cách mà một quy trình độc lập được tạo ra là trước tiên fork, và sau đó exec, thay thế chương trình đang chạy trong quy trình con bằng chương trình mong muốn.

Các thành phần của lệnh shell này là:

  1. Các dấu ngoặc đơn (...)bắt đầu một lớp vỏ con: một phiên bản khác của BASH.
  2. Các killlệnh gửi các tín hiệu STOP để quá trình này, trong đó đặt nó vào tình trạng bị đình chỉ.
  3. Ngay khi bạn cho phép quá trình tiếp tục (bằng cách gửi CONTtín hiệu), execlệnh sẽ khiến nó tự thay thế bằng chương trình bạn muốn. my_commandgiữ nguyên bản gốc của lớp vỏ phụ.
  4. Bạn có thể sử dụng $!biến để có được PID của quá trình.

2
Tôi thích cái này, vì nó về cơ bản là chính xác (chỉ là tôi phải sử dụng -s STOPthay vì -SIGSTOP). Vẫn tự hỏi: tại sao nó phải $BASHPIDthay thế $$? (Tôi có thể không thực sự hiểu sự khác biệt).
Hibou57

1
Đối với $$vs $BASHPID, tôi kiểm tra cái sau là PID của shell phụ, trong khi không phải cái trước. Có một vấn đề buồn cười: áp dụng mẹo trong tập lệnh bash, thường là thất bại và tôi phải làm một cái gì đó như thế này: PID=$!; ps -p $PID; kill -s CONT $PID;Không thành công nếu tôi xóa ps -p $PIDphần: quá trình dường như biến mất (bị giết?) Mà không có thông báo lỗi ở bất cứ đâu . Nó ổn từ một vỏ tương tác, vấn đề chỉ là từ kịch bản. Điều đó quá bí ẩn.
Hibou57

Tôi đã cố gắng sử dụng giải pháp này để liệt kê các mô tả tệp của my_command. ( goo.gl/cNbUE8 ) nhưng các mô tả vẫn giống nhau không có gì my_command.
rasty.g

Để biết các tùy chọn thay thế $BASHPIDcho các vỏ khác ngoài bash, xem tại đây
Jakob
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.