Lệnh nohup: cách dùng, nohup.out và giữ tiến trình chạy tiếp khi đóng terminal
Để công việc vẫn chạy tiếp khi bạn đóng terminal hoặc mất kết nối SSH, hãy chạy nó bằng lệnh nohup. nohup chạy lệnh trong trạng thái bỏ qua tín hiệu ngắt kết nối (SIGHUP) được gửi đến khi terminal đóng. Khi chạy cùng lúc một sleep có nohup và một sleep không có nohup trên máy chủ AlmaLinux 9 rồi đóng terminal, chỉ tiến trình chạy bằng nohup còn lại và tiếp tục chạy.
Kết quả bên dưới được chạy trên máy chủ AlmaLinux 9.8 (tài khoản root) và máy chủ Debian 12 (tài khoản thường). Thay cho công việc chạy lâu, sleep được dùng, và khi dừng chỉ chỉ định PID nhận được lúc khởi chạy. Thời gian được in theo UTC.
1️⃣ Cách dùng lệnh nohup
nohup được đặt trước lệnh cần chạy, và dấu & ở cuối lệnh chỉ định chạy nền. Theo tài liệu chính thức của GNU, bản thân nohup không đưa lệnh xuống chạy nền, nên nếu bỏ & thì dấu nhắc lệnh chỉ quay lại khi lệnh chạy xong.
nohup sleep 300 &[1] 3431609
nohup: ignoring input and appending output to 'nohup.out'[1] là số hiệu tác vụ, còn 3431609 là PID của tiến trình vừa chạy. Thông báo xuất hiện tiếp theo cho biết tiến trình không nhận đầu vào từ bàn phím và đầu ra sẽ được ghi nối vào tệp nohup.out.
PID của tác vụ vừa chạy được giữ trong $!, vì vậy hãy kiểm tra bằng [echo $!] ngay sau khi chạy và ghi lại; khi xem trạng thái hay dừng tác vụ, bạn dùng đúng số đó.
echo $!3431609Khi đóng terminal, shell nhận tín hiệu ngắt kết nối và gửi cùng tín hiệu đó đến các tác vụ mà nó đã chạy (theo tài liệu chính thức của Bash). Để kiểm chứng điều này, trong một terminal mới đã chạy cùng lúc [nohup sleep 300 &] và, không có nohup, [sleep 301 &].
sleep 301 &[2] 3432892jobs -l[1]- 3432883 Running nohup sleep 300 &
[2]+ 3432892 Running sleep 301 &Khi cả hai tác vụ đang ở trạng thái Running, cửa sổ terminal được đóng lại, rồi hai PID được kiểm tra bằng ps từ một shell khác.
ps -p 3432883,3432892 -o pid,stat,etime,cmd PID STAT ELAPSED CMD
3432883 S 00:05 sleep 300Chỉ còn sleep 300 chạy bằng nohup; sleep 301 chạy không có nohup đã kết thúc cùng lúc với việc đóng terminal.
Tiến trình chạy bằng nohup giống như chiếc điện thoại đang bật chế độ Không làm phiền.
nohup là lệnh thuộc gói coreutils. Phiên bản đã cài được xem ở dòng đầu tiên của --version. Máy chủ AlmaLinux 9.8 là 8.32, máy chủ Debian 12 là 9.1.
nohup --version | head -1nohup (GNU coreutils) 8.32nohup --version | head -1nohup (GNU coreutils) 9.12️⃣ nohup.out và chuyển hướng đầu ra
Nếu bạn không chỉ định đầu ra đi đâu, nohup ghi nối đầu ra của lệnh vào nohup.out trong thư mục hiện tại. nohup.out vừa được tạo có kích thước 0 và quyền -rw-------, chỉ người dùng đã tạo mới đọc và ghi được.
ls -l nohup.out-rw------- 1 root root 0 Oct 28 23:04 nohup.outTài liệu chính thức của GNU giải thích rằng nohup tạo nohup.out sao cho chỉ người dùng đã tạo mới đọc và ghi được, bất kể thiết lập umask. Nếu không ghi được vào thư mục hiện tại, nohup ghi vào $HOME/nohup.out trong thư mục home, và nếu cả ở đó cũng không ghi được thì không chạy lệnh.
Khi chạy bằng nohup một lệnh có đầu ra, đầu ra vẫn còn trong nohup.out sau khi lệnh kết thúc.
nohup sh -c 'echo start; sleep 2; echo end' &[1] 3431985
nohup: ignoring input and appending output to 'nohup.out'cat nohup.outstart
end
[1]+ Done nohup sh -c 'echo start; sleep 2; echo end'Done ở dòng cuối là thông báo của shell rằng tác vụ đã xong. nohup.out không được tạo mới mỗi lần chạy mà được ghi nối vào cuối cùng một tệp, nên nếu chạy nhiều tác vụ từ cùng một thư mục, đầu ra sẽ lẫn vào một tệp.
Để tách log cho từng tác vụ, hãy chỉ định tệp đầu ra bằng > và gửi cả đầu ra lỗi vào cùng tệp đó bằng 2>&1.
nohup sh -c 'echo start; sleep 300' > job.log 2>&1 &[1] 3432059cat job.lognohup: ignoring input
startKhi thêm cả 2>&1, terminal chỉ hiện số hiệu tác vụ và PID, còn thông báo của nohup [nohup: ignoring input] được ghi ở dòng đầu của tệp log.
Nếu chỉ thêm > mà bỏ 2>&1, terminal hiện thông báo rằng đầu ra lỗi được chuyển sang tệp của đầu ra chuẩn.
nohup sleep 300 > job2.log &[2] 3432097
nohup: ignoring input and redirecting stderr to stdoutĐầu ra của các tác vụ không cần giữ lại thì gửi vào /dev/null. Trường hợp này terminal cũng chỉ hiện số hiệu tác vụ và PID.
nohup sleep 300 > /dev/null 2>&1 &[3] 3432137Bảng dưới đây cho thấy đầu ra đã đi đâu và thông báo nào hiện ra trên terminal với bốn cách chạy.
| Cách chạy | Đầu ra đi đâu | Thông báo trên terminal |
|---|---|---|
| nohup lệnh & | nohup.out trong thư mục hiện tại | nohup: ignoring input and appending output to 'nohup.out' |
| nohup lệnh > tệp & | Tệp đã chỉ định (gồm cả đầu ra lỗi) | nohup: ignoring input and redirecting stderr to stdout |
| nohup lệnh > tệp 2>&1 & | Tệp đã chỉ định | Không có (thông báo nằm ở dòng đầu tệp) |
| nohup lệnh > /dev/null 2>&1 & | Bỏ đi | Không có |
3️⃣ Kiểm tra và dừng tiến trình nohup
Danh sách jobs chỉ hiện các tác vụ chạy từ shell hiện tại, nên sau khi đóng terminal và kết nối lại, hãy kiểm tra tiến trình nohup bằng ps -p với PID. Khi vẫn còn ở cùng shell, jobs -l hiện số hiệu tác vụ, PID và trạng thái cùng lúc.
jobs -l[1]+ 3431609 Running nohup sleep 300 &Nếu ghi PID sau ps -p và chọn cột bằng -o, chỉ dòng của tiến trình đó hiện ra. S trong STAT là trạng thái ngủ chờ sự kiện, còn ELAPSED là thời gian đã trôi qua kể từ khi bắt đầu.
ps -p 3431609 -o pid,stat,etime,cmd PID STAT ELAPSED CMD
3431609 S 00:03 sleep 300Để dừng, hãy dùng kill kèm PID phía sau.
kill 3431609kill không in ra gì, và khi chạy jobs tiếp theo, tác vụ đó hiện là Terminated rồi biến khỏi danh sách.
jobs[1]+ Terminated nohup sleep 300Chạy lại ps với cùng PID thì chỉ hiện dòng tiêu đề, xác nhận rằng tiến trình đã kết thúc.
ps -p 3431609 -o pid,stat,etime,cmd PID STAT ELAPSED CMDnohup chỉ bỏ qua tín hiệu ngắt kết nối, nên dù gửi trực tiếp cùng tín hiệu đó bằng [kill -HUP] thì tiến trình cũng không kết thúc. kill -HUP đã được gửi đến sleep 305 chạy bằng nohup và sleep 306 chạy không có nohup.
kill -HUP 3437119 3437128Kiểm tra tiếp bằng jobs -l thì chỉ tác vụ nohup còn Running, còn sleep 306 đã kết thúc với Hangup.
jobs -l[1]- 3437119 Running nohup sleep 305 &
[2]+ 3437128 Hangup sleep 306Nếu không chỉ định tín hiệu cho kill, nó gửi SIGTERM, nên tác vụ chạy bằng nohup cũng kết thúc bằng [kill PID].
4️⃣ So sánh lệnh nohup với disown và các tùy chọn
🔲 So sánh nohup và disown
disown là lệnh tích hợp của bash dùng cho các tác vụ đã chạy: dùng khi muốn tách về sau một tác vụ chạy bằng & mà không có nohup khỏi tín hiệu ngắt kết nối của terminal. disown không chuyển đầu ra sang nohup.out, nên với tác vụ có đầu ra, hãy chỉ định nơi nhận đầu ra bằng > tệp ngay khi chạy.
Theo tài liệu chính thức của Bash, dùng disown không kèm tùy chọn thì tác vụ bị đưa ra khỏi danh sách jobs, còn disown -h giữ tác vụ trong danh sách và chỉ không gửi tín hiệu ngắt kết nối đến nó. Trước tiên chạy sleep 302 rồi chạy disown.
sleep 302 &[1] 3433230disowndisown không in ra gì, và jobs -l chạy ngay sau đó cũng trả về kết quả trống.
jobs -lTiếp theo chạy sleep 303 và chạy disown -h cho tác vụ số %1.
sleep 303 &[1] 3433343disown -h %1Kiểm tra bằng jobs -l thì tác vụ vẫn còn trong danh sách.
jobs -l[1]+ 3433343 Running sleep 303 &Thêm một sleep 304 nữa không xử lý gì, đóng terminal rồi kiểm tra ba PID từ một shell khác.
sleep 304 &[2] 3433474ps -p 3433230,3433343,3433474 -o pid,stat,etime,cmd PID STAT ELAPSED CMD
3433230 S 00:11 sleep 302
3433343 S 00:08 sleep 303Hai tác vụ dùng disown và disown -h vẫn còn, chỉ sleep 304 không xử lý gì là kết thúc. So sánh bốn cách như sau.
| Cách | Khi dùng | Danh sách jobs | Sau khi đóng terminal | Đầu ra |
|---|---|---|---|---|
| nohup lệnh & | Khi chạy | Còn | Còn | nohup.out hoặc tệp đã chỉ định |
| lệnh & rồi disown | Sau khi chạy | Được bỏ qua | Còn | Không đổi |
| lệnh & rồi disown -h | Sau khi chạy | Còn | Còn | Không đổi |
| Chỉ lệnh & | — | Còn | Đã kết thúc | Không đổi |
Với công việc cần gọi lại màn hình phiên làm việc để gõ tiếp, bộ ghép kênh terminal như tmux là phù hợp; còn công việc chạy một lần và chỉ nhận kết quả qua tệp thì nohup là đủ.
🔲 Tùy chọn của lệnh nohup
📌 Tùy chọn chính: kết quả chạy trong bài này
| Tùy chọn | Chức năng | Kết quả trong bài này | |
|---|---|---|---|
| --version | In thông tin phiên bản rồi thoát | Máy chủ AlmaLinux 9.8: nohup (GNU coreutils) 8.32, máy chủ Debian 12: nohup (GNU coreutils) 9.1 |
📎 Tùy chọn khác: theo tài liệu hướng dẫn chính thức
| Tùy chọn | Chức năng | |
|---|---|---|
| --help | In trợ giúp rồi thoát |
🔲 Trình mô phỏng lệnh nohup
Trong trình mô phỏng bên dưới, bạn có thể chạy tác vụ bằng nohup, đóng terminal và kết nối lại bằng chip 🔌, rồi tự xem tiến trình nào còn lại.
🔢 FAQ & nội dung đề xuất
Lên lịch tác vụ
Linux: thiết lập crontab
Cách thiết lập crontab, trình lập lịch của Linux dùng để đăng ký các công việc lặp lại theo giờ định sẵn như sao lưu hay dọn log.
Tiến trình
Lệnh top trong Linux (kiểm tra mức dùng CPU và bộ nhớ)
Lệnh top xem mức dùng CPU và bộ nhớ theo từng tiến trình theo thời gian thực.
ℹ️ Thông báo tiếp thị liên kết
Nội dung trên trang này có chứa liên kết affiliate (tiếp thị liên kết). Khi khách truy cập mua sản phẩm hoặc dịch vụ qua các liên kết này, trang sẽ nhận hoa hồng từ bên bán. Trong quá trình đó, số tiền người mua phải trả (sẽ giảm khi có chương trình khuyến mãi ↓) không hề tăng lên. Giá, khuyến mãi và tình trạng hàng được đăng theo thời điểm viết bài và có thể khác với thực tế, vì vậy hãy kiểm tra lại lần cuối với bên bán trước khi mua. Việc chọn và đánh giá sản phẩm dựa trên tiêu chí riêng của trang; việc có nhận hoa hồng hay không không ảnh hưởng đến thứ tự giới thiệu hay nội dung đánh giá.