Cách làm truyền thống là dùng lệnh `nohup` (no hang up) khi gọi câu lệnh. Câu lệnh sẽ tiếp tục chạy dù tắt terminal hay thoát khỏi server. Cú pháp:
nohup câu_lệnh_như_bình_thường
Vấn đề ở chỗ: dùng nohup yêu cầu ta phải tính trước chuyện này, phải gõ nohup trước câu lệnh cần chạy, nếu nhỡ quên nohup mà đang chạy dở chừng thì làm sao?
disown là giải pháp
tmux/screen là giải pháp gián tiếp.
disown là gì?
disown là built-in command của các shell hay dùng: bash, zsh, ksh, không phải cài đặt gì cả.$ man bash | grep ' disown' -A4
disown [-ar] [-h] [jobspec ... | pid ... ]
Without options, remove each jobspec from the table of active jobs. If jobspec is not present, and neither the -a nor the -r option is supplied, the current job is used. If the -h option is given, each jobspec is not removed from the table, but is marked so that SIGHUP is not sent to the job if the shell receives a SIGHUP. If no jobspec is supplied, the -a option means to remove or mark all jobs; the -r option without a jobspec argument restricts operation to running jobs. The return value is 0 unless a jobspec does not specify a valid job.
jobs , background job, foreground job
Khi chạy 1 câu lệnh trên bash, câu lệnh đó sẽ giữ quyền điều khiển, ta không thể chạy câu lệnh nào khác cho đến khi câu lệnh đang chạy chạy xong, ví dụ sau chạy wget để tải 1 flle cài OpenBSD
$ wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
--2020-04-04 19:25:55-- https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
Resolving cdn.openbsd.org (cdn.openbsd.org)... 151.101.10.217
Connecting to cdn.openbsd.org (cdn.openbsd.org)|151.101.10.217|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 472317952 (450M) [application/octet-stream]
Saving to: ‘install66.fs’
install66.fs 0%[ ] 1011K 207KB/s eta 42m 1s ^Z
[1]+ Stopped wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
Bấm ctrl Z (^Z) để dừng process đang chạy này lại, trả quyền điều khiển về cho bash. Vậy câu lệnh đang chạy nó đi đâu mất rồi?
bash có chứa một danh sách các chương trình đang chạy này và gọi là `job`.
Gõ lệnh jobs để hiện danh sách các active job:
$ jobsprocess này hiện ở trạng thái "stopped/suspend", nó không chạy mà đang bị "tạm dừng".
[1]+ Stopped wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
Gõ bg kèm số jobs (ở trên có thấy là thấy số 1), vậy gõ bg %1 để chạy job này ở "background".
$ bg %1
[1]+ wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs &
Redirecting output to ‘wget-log’.
Giờ gõ lại `jobs` sẽ thấy chữ "Running" chứ không phải "Stopped", và process được chạy trở lại.
$ jobs
[1]+ Running wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs &
Để chuyển chương trình này về foreground, chiếm lại "sân khấu", gõ fg %1:
$ fg %1
wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
--2020-04-04 19:25:55-- https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
Resolving cdn.openbsd.org (cdn.openbsd.org)... 151.101.10.217
Connecting to cdn.openbsd.org (cdn.openbsd.org)|151.101.10.217|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 472317952 (450M) [application/octet-stream]
Saving to: ‘install66.fs’
2020-04-04 19:47:01 (602 KB/s) - Read error at byte 23899568/472317952 (Success). Retrying.
--2020-04-04 19:47:02-- (try: 2) https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
Connecting to cdn.openbsd.org (cdn.openbsd.org)|151.101.10.217|:443... connected.
HTTP request sent, awaiting response... 206 Partial Content
Length: 472317952 (450M), 448418384 (428M) remaining [application/octet-stream]
Saving to: ‘install66.fs’
install66.fs 5%[+++> ] 23,99M 148KB/s eta 49m 8s ^Z
[1]+ Stopped wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
Một process khi ở trạng thái stopped/suspend, nếu xem trong bảng ps/top, sẽ thấy trạng thái là T to:
$ ps xau | grep wget
hvn 30707 0.0 0.0 49628 6280 pts/0 T 19:25 0:00 wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
T = stopped by job control signal
Một cách khác để thay đổi trạng thái T này sang chạy, là gửi signal: SIGCONT
$ ps xau | grep wget
hvn 30707 0.0 0.0 49628 6280 pts/0 T 19:25 0:00 wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
$ kill -SIGCONT 30707
Redirecting output to ‘wget-log’.
$ ps xau | grep wget
hvn 30707 0.0 0.0 49628 6280 pts/0 S 19:25 0:00 wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
Disown
Gõ disown %1 để bỏ jobs này khỏi list jobs:
$ disown %1
$ jobs
$ ps auwwxf | grep -B2 wget
hvn 14428 0.0 0.0 31816 6064 pts/1 Ss+ 15:22 0:00 | \_ bash
hvn 19332 0.0 0.2 43044 17536 pts/0 Ss 17:57 0:01 | \_ bash
hvn 30707 0.0 0.0 49628 6280 pts/0 S 19:25 0:01 | | \_ wget https://cdn.openbsd.org/pub/OpenBSD/6.6/amd64/install66.fs
Giờ tắt terminal đi, hay thoát khỏi server khi đang SSH thì process này vẫn cứ tiếp tục chạy.
Khi tắt terminal, hay thoát khỏi server, bash shell sẽ nhận được SIGHUP, và mặc định nó sẽ truyền SIGHUP này tới tất cả process con của nó để tắt hết đi. Disown 1 job sẽ bỏ qua job đó và không truyền SIGHUP trong tương lại. Khi thoát khỏi shell, process bash kết thúc, process con bị mất parent trở thành orphan process, thường sẽ được system manager PID 1 nhận làm process con.
http://git.savannah.gnu.org/cgit/bash.git/tree/jobs.c?h=bash-4.4-testing#n1414/* Cause all jobs, running or stopped, to receive a hangup signal. If a job is marked J_NOHUP, don't send the SIGHUP. */ void hangup_all_jobs () { register int i; /* XXX could use js.j_firstj here */ for (i = 0; i < js.j_jobslots; i++) { if (jobs[i]) { if (jobs[i]->flags & J_NOHUP) continue; killpg (jobs[i]->pgrp, SIGHUP); if (STOPPED (i)) killpg (jobs[i]->pgrp, SIGCONT); } } }
https://github.com/att/ast/blob/683bccf3bab8545b6334ab7b7c179e08f5eb89fa/src/cmd/ksh93/sh/jobs.c#L981
reptyr
Ngược lại với disown, reptyr giúp "chiếm" lại quyền điều khiển process sau khi bị disown.$ apt-cache search reptyr
reptyr - Tool for moving running programs between ptys
Screen và Tmux
Thay vì phải nohup,disown, thì một giải pháp khác là luôn chạy lệnh trong tmux/screen. Câu lệnh đầu tiên sau khi SSH vào server là gõ tmux.Tmux hay screen sẽ tiếp tục chạy câu lệnh dù kết nối đến server bị đứt, hay thoát khỏi terminal.
Tham khảo
- man bash
- https://superuser.com/questions/184047/bash-zsh-undoing-disown
Hết
HVN at https://pymi.vn và https://www.familug.org
Đăng ký học Python tại https://pymi.vn
No comments:
Post a Comment