Trong quá trình làm việc với Linux, một vấn đề thường gặp là làm sao để các tiến trình vẫn tiếp tục chạy ngay cả khi bạn đã đăng xuất hoặc đóng terminal. Lệnh nohup mang đến một giải pháp đơn giản, giúp tiến trình tiếp tục chạy mà không bị gián đoạn bằng cách làm cho chúng miễn nhiễm với tín hiệu treo terminal (SIGHUP).

Trong bài viết này, chúng ta sẽ tìm hiểu lệnh nohup là gì, cách sử dụng, cách nó tương tác với session, và so sánh với các công cụ khác để quản lý hiệu quả các tiến trình chạy nền dài hạn.
Lệnh Nohup là gì?
Nohup, viết tắt của no hang up, là một lệnh trong hệ thống Linux giúp giữ tiến trình tiếp tục chạy ngay cả khi đã thoát khỏi shell hoặc terminal. Nohup ngăn không cho tiến trình hoặc job nhận tín hiệu SIGHUP (Signal Hang UP), tín hiệu được gửi đến tiến trình khi terminal bị đóng hoặc thoát.
Cú pháp lệnh Nohup
Cú pháp lệnh nohup như sau:
nohup command arguments
hoặc
nohup options
Bây giờ hãy xem cách áp dụng lệnh này.
Cách kiểm tra phiên bản Nohup
Bạn có thể bắt đầu bằng cách kiểm tra phiên bản của nohup bằng cú pháp sau:
nohup --version

Kiểm tra phiên bản lệnh nohup
Khởi chạy tiến trình bằng Nohup
Để giữ cho tiến trình hoặc job tiếp tục chạy, bạn cần thêm nohup trước lệnh như dưới đây. Job sẽ tiếp tục chạy trong shell và không bị dừng khi thoát khỏi shell hoặc terminal.
Ví dụ này sử dụng một script bash đơn giản:
./hello.sh
#!/bin/bash
echo "Hello World!"
Bây giờ chạy script này với nohup:
nohup ./hello.sh

Lệnh nohup với các lệnh thông thường
Từ kết quả trên, đầu ra của lệnh đã được lưu vào nohup.out. Để xác nhận, chạy:
cat nohup.out

Nội dung tệp nohup.out
Ngoài ra, bạn có thể chuyển hướng đầu ra sang một tệp khác:
nohup ./hello.sh > output.txt
Một lần nữa, để xem nội dung tệp, chạy:
cat output.txt

Chuyển hướng đầu ra của Nohup sang tệp văn bản
Để chuyển hướng lỗi chuẩn đến cùng vị trí với đầu ra chuẩn, sử dụng thuộc tính > filename 2>&1:
nohup ./hello.sh > myoutput.txt 2>&1

Chuyển hướng cả đầu ra chuẩn và lỗi chuẩn
Khởi chạy tiến trình chạy nền với Nohup
Để khởi chạy tiến trình ở chế độ nền, bạn hãy thêm ký hiệu & ở cuối lệnh. Trong ví dụ này, chúng ta sẽ ping google.com và gửi tiến trình vào chế độ nền:
nohup ping google.com &

Chạy tiến trình bằng Nohup ở chế độ nền
Để kiểm tra tiến trình khi quay lại shell, dùng lệnh pgrep:
pgrep -a ping

Pgrep hiển thị tiến trình ping
Nếu bạn muốn dừng hoặc kết thúc tiến trình đang chạy, dùng lệnh kill theo PID (process ID) của tiến trình:
kill 2565

Kill tiến trình theo PID
So sánh chi tiết giữa nohup, screen và tmux
Nohup
Là một tiện ích cơ bản, chủ yếu được dùng để chạy các lệnh cần duy trì ngay cả sau khi người dùng đã đăng xuất.
Hoạt động bằng cách làm cho lệnh miễn nhiễm với tín hiệu SIGHUP, tín hiệu vốn thường được gửi đến tiến trình khi terminal bị đóng hoặc người dùng thoát khỏi phiên làm việc.
nohup tự động chuyển hướng đầu ra chuẩn (stdout) và lỗi chuẩn (stderr) của lệnh sang tệp nohup.out nếu chưa được chỉ định.
Công cụ này có cách dùng cực kỳ đơn giản, có gánh nặng xử lý rất thấp, phù hợp với các tác vụ đơn giản, chạy dài hạn.
Sự đơn giản cũng đồng nghĩa với hạn chế: Không có tính khả năng tương tác hay quản lý session. Sau khi khởi chạy, bạn không thể trực tiếp quản lý tiến trình ngoài việc để nó chạy hoặc kill thủ công.
Screen
Cung cấp một giải pháp nâng cao hơn cho việc quản lý session terminal, cho phép người dùng tạo và quản lý nhiều cửa sổ terminal trong một session duy nhất.
Một tính năng quan trọng của screen là khả năng tách rời (detach) session và gắn lại (reattach) từ vị trí khác nhằm đảm bảo các tiến trình bên trong session vẫn chạy ngay cả khi kết nối terminal bị gián đoạn.
Screen hỗ trợ duy trì session sống sót qua các lần gián đoạn mạng hoặc mất kết nối, từ đó giảm thiểu nguy cơ mất tiến trình khi chạy các tác vụ dài hạn.
Nhược điểm: Hệ thống phím tắt và cách quản lý cửa sổ của screen khá rườm rà và thiếu trực quan, dễ gây trở ngại cho người mới bắt đầu và họ phải mất nhiều thời gian làm quen hơn so với các công cụ hiện đại.
Tmux
Được coi là một terminal multiplexer hiện đại và mạnh mẽ, tmux áp dụng mô hình client-server để quản lý session terminal.
Tmux tổ chức công việc thành các session, mỗi session có thể chứa nhiều cửa sổ, và mỗi cửa sổ có thể được chia nhỏ thành nhiều khung (pane). Cấu trúc này mang lại khả năng kiểm soát chi tiết đối với môi trường terminal.
Tmux hỗ trợ mức độ tương tác cao, cho phép người dùng dễ dàng chuyển đổi giữa các cửa sổ và khung, điều chỉnh bố cục, và quản lý session hiệu quả. Các tính năng bao gồm tùy chỉnh phím tắt, quản lý cửa sổ và khung trực quan, cùng khả năng scripting mạnh mẽ. Nhờ đó,Tmux trở thành công cụ đa năng cho các quy trình làm việc phức tạp.
Mặc dù tmux thường được đánh giá cao về tính năng và khả năng sử dụng, nhưng không phải lúc nào nó cũng được cài sẵn trên các hệ thống cũ, và việc làm quen ban đầu có thể khó hơn so với nohup. Tuy vậy, về lâu dài, giá trị mà tmux mang lại thường xứng đáng với nỗ lực đã bỏ ra.
Nohup tương tác với session của người dùng như thế nào?
Trường hợp 1: Mất kết nối SSH (rớt mạng, client bị crash)
Nếu kết nối SSH bị ngắt đột ngột do lỗi mạng hoặc do client SSH bị crash, tiến trình sshd trên server sẽ gửi tín hiệu SIGHUP đến shell đăng nhập của người dùng. Shell lại tiếp tục truyền tín hiệu này cho các tiến trình con, buộc chúng phải dừng lại theo cấu hình mặc định.
Tuy nhiên, nếu lệnh được khởi chạy bằng nohup, tiến trình sẽ được cấu hình để bỏ qua SIGHUP. Nhờ vậy, dù session bị ngắt và tín hiệu vẫn được phát đi, tiến trình vẫn tiếp tục chạy ổn định trên server. Đầu ra, thay vì bị mất khi terminal đóng, sẽ được ghi lại an toàn trong nohup.out hoặc tệp khác do người dùng chỉ định. Đây chính là một trong những trường hợp sử dụng điển hình và quan trọng nhất của nohup.
Trường hợp 2: Người dùng đăng xuất bình thường (gõ exit hoặc logout)
Khi người dùng đăng xuất bằng các lệnh như exit hoặc logout, shell đăng nhập sẽ bắt đầu chu trình kết thúc. Trong quá trình này, shell thường gửi tín hiệu SIGHUP đến toàn bộ tiến trình con, bao gồm cả các job chạy nền. Với những tiến trình không được bảo vệ, tín hiệu này sẽ buộc chúng dừng lại ngay lập tức.
Ngược lại, nếu tiến trình được khởi chạy với nohup, nó sẽ bỏ qua tín hiệu SIGHUP. Vì thế, ngay cả khi người dùng đã đăng xuất và parent shell đã kết thúc, tiến trình vẫn tiếp tục tồn tại và chạy nền. Đầu ra và lỗi của tiến trình vẫn được ghi vào nohup.out hoặc tệp log mà người dùng chỉ định.
Trường hợp 3: Đóng cửa sổ Terminal emulator (xterm, gnome-terminal…)
Hành vi của nohup khi đóng cửa sổ terminal phụ thuộc vào nơi lệnh được thực thi.
Nếu lệnh chạy trên server từ xa qua SSH trong cửa sổ terminal đó, việc đóng cửa sổ sẽ chấm dứt client SSH cục bộ. Khi đó, server SSH sẽ gửi tín hiệu SIGHUP đến shell từ xa và các tiến trình con, tương tự như trường hợp mất kết nối SSH trực tiếp. Trong tình huống này, tiến trình trên server sẽ bỏ qua tín hiệu SIGHUP và tiếp tục chạy.
Trong trường hợp lệnh nohup chạy trực tiếp trong shell cục bộ (không thông qua SSH), việc đóng cửa sổ terminal thường gửi tín hiệu SIGHUP đến shell cục bộ, và shell này sẽ truyền tiếp cho các tiến trình con. Ngay cả khi đó, tiến trình vẫn bỏ qua tín hiệu SIGHUP và tiếp tục hoạt động. Tiến trình có thể bị đổi PPID thành 1 (init) hoặc một tiến trình hệ thống khác nhận nuôi tiến trình mồ côi, nhưng lệnh vẫn tồn tại.
Trường hợp 4: Hệ thống shutdown hoặc reboot
Khi hệ thống tắt máy hoặc khởi động lại theo quy trình, hệ điều hành sẽ khởi động một chuỗi thao tác để kết thúc tất cả các tiến trình đang chạy. Thông thường, tín hiệu SIGTERM sẽ được gửi đi trước cho phép các tiến trình có cơ hội thoát một cách an toàn, sau đó gửi tín hiệu SIGKILL nếu chúng không kịp kết thúc.
Trong trường hợp này, nohup không thể bảo vệ tiến trình vì nó không miễn nhiễm với các tín hiệu hệ thống như SIGTERM hay SIGKILL. Do đó, tiến trình khởi chạy bằng nohup vẫn sẽ bị dừng cùng với toàn bộ tiến trình khác khi máy chủ shutdown hoặc reboot.
Nếu muốn tiến trình tự động khởi động lại sau khi hệ thống bật lại, bạn cần sử dụng các cơ chế mạnh hơn như dịch vụ systemd, job của upstart, hoặc chức năng @reboot trong cron, thay vì chỉ dựa vào nohup.
Trường hợp 5: Tiến trình bị kill thủ công
nohup chỉ có thể miễn nhiễm với tín hiệu SIGHUP. Nếu các tín hiệu khác, như SIGTERM (mặc định khi dùng kill) hoặc SIGKILL (tín hiệu không thể bỏ qua, khi dùng kill -9), được gửi trực tiếp đến PID của tiến trình thì tiến trình đó sẽ kết thúc. Do đó, nohup không có khả năng chống lại các lệnh kill thủ công hoặc killall sử dụng tín hiệu khác SIGHUP.
Trường hợp 6: Chạy nohup mà không có & (ở foreground)
Nếu nohup được dùng để khởi chạy lệnh mà không có ký tự & ở cuối, chẳng hạn nohup ./my_script.sh, thì script ./my_script.sh vẫn được cấu hình để bỏ qua tín hiệu SIGHUP. Luồng đầu ra chuẩn và lỗi chuẩn của nó sẽ được chuyển hướng vào nohup.out nếu còn gắn với terminal.
Tuy nhiên, điểm khác biệt quan trọng là terminal vẫn gắn liền với lệnh nohup, và shell prompt sẽ không xuất hiện trở lại cho đến khi ./my_script.sh hoàn tất. Nếu session terminal bị đóng hoặc ngắt kết nối trong khi lệnh vẫn đang chạy, script ./my_script.sh vẫn bỏ qua tín hiệu SIGHUP và tiếp tục thực thi (có thể được gán lại cho tiến trình init).
Mặc dù script vẫn tồn tại, nhưng cách vận hành này ít được sử dụng vì nó chiếm dụng terminal. Để tách tiến trình sau khi đã khởi chạy, có thể dùng tổ hợp Ctrl+Z, sau đó chạy bg rồi disown. Dù vậy, nohup vốn đã đảm bảo khả năng miễn nhiễm quan trọng với tín hiệu SIGHUP cho lệnh.
Trường hợp 7: Shell bị thoát do giới hạn session hoặc timeout
Trong một số môi trường server, hệ thống được cấu hình với giới hạn session hoặc thời gian chờ, chẳng hạn thông qua biến TMOUT trong bash hoặc thiết lập timeout trong SSH. Khi hết thời gian quy định, session sẽ tự động kết thúc, thường kèm theo việc gửi tín hiệu SIGHUP đến shell của người dùng.
Tuy nhiên, các tiến trình được khởi chạy bằng nohup sẽ bỏ qua tín hiệu này và tiếp tục chạy bình thường. Nhờ khả năng miễn nhiễm với SIGHUP, tiến trình vẫn duy trì hoạt động giống như trong trường hợp người dùng logout hoặc mất kết nối, đảm bảo tác vụ không bị gián đoạn bởi cơ chế timeout.
Trường hợp 8: Nếu không thể ghi ra tệp nohup.out
Khi nohup cố gắng chuyển hướng đầu ra chuẩn và lỗi chuẩn, hành vi mặc định là ghi nối tiếp vào tệp nohup.out trong thư mục hiện tại. Nếu thao tác này thất bại, chẳng hạn do không có quyền ghi, nohup sẽ thử tạo hoặc ghi vào tệp $HOME/nohup.out.
Nếu cả hai nỗ lực đều không thành công, lệnh nohup có thể thoát với lỗi và không khởi chạy lệnh mục tiêu. Trong một số trường hợp khác, tiến trình có thể vẫn được khởi chạy, nhưng đầu ra và lỗi sẽ không được ghi lại, coi như bị bỏ đi (tương tự như khi chuyển hướng vào /dev/null).
Trong những tình huống này, nohup thường in thông báo lỗi ra stderr (tức terminal, nếu chưa được chuyển hướng) để cảnh báo rằng nó không thể mở tệp nohup.out.
Hiểu về lỗi silent khi dùng nohup
Mặc dù nohup hiếm khi gặp sự cố mà không báo lỗi, chẳng hạn khi không thể ghi vào tệp đầu ra, nhưng các lệnh chạy thông qua nó vẫn có thể kết thúc bất ngờ, khiến người dùng lầm tưởng rằng có lỗi silent failure.
Nguyên nhân thường gặp
Thực tế, nguyên nhân thường không nằm ở nohup mà do lệnh được khởi chạy đã tự thoát sớm. Một số nguyên nhân phổ biến có thể kể đến như:
- Lệnh gặp lỗi nội bộ ngay khi bắt đầu, chẳng hạn cấu hình sai hoặc thiếu dependency.
- Nếu là script shell thì tiến trình có thể dừng do lỗi không được xử lý, đặc biệt khi dùng tùy chọn
set -e. - Lệnh không tìm thấy các lệnh cần thiết khác do biến môi trường
PATHbị giới hạn.
Môi trường thực thi hạn chế
So với shell tương tác của người dùng, môi trường mà nohup sử dụng để thực thi lệnh thường rất khác biệt và hạn chế hơn, khiến lệnh dễ gặp lỗi nếu phụ thuộc vào biến môi trường nhất định hoặc đường dẫn không tồn tại.
Các yếu tố khác
Ngoài ra, một lệnh có thể chạy trong một khoảng thời gian rồi dừng do cạn kiệt tài nguyên, chẳng hạn hết bộ nhớ (kích hoạt OOM killer) hoặc đầy dung lượng đĩa. Nó cũng có thể thoát nếu bất ngờ yêu cầu nhập liệu tương tác, trong khi nohup đã chuyển hướng đầu vào từ /dev/null.
Bên cạnh đó, các vấn đề về quyền truy cập mà lệnh gặp phải trong quá trình chạy, khác với quyền ban đầu của nohup, cũng có thể khiến tiến trình bị dừng lại.
Cách nhận biết và xử lý
Trong những trường hợp silent failure như thế này, nohup thực chất vẫn tách tiến trình thành công và bảo vệ nó khỏi tín hiệu SIGHUP, nguyên nhân dừng là do chính lệnh đó. Silent xuất hiện từ góc nhìn của người dùng sau khi ngắt kết nối, vì thông báo lỗi thường đã được ghi lại trong nohup.out (hoặc tệp đầu ra được chỉ định). Vì vậy, bước đầu tiên để xử lý là kiểm tra kỹ tệp đầu ra cùng các log hệ thống liên quan, vốn thường chứa thông tin giải thích lý do lệnh kết thúc bất ngờ.
Thực hành logging đúng cách với nohup
Ghi log hiệu quả với nohup không chỉ dừng lại ở tệp mặc định nohup.out, mà còn cần đảm bảo các tiến trình chạy nền có thể được theo dõi và debug khi cần.
- Mặc dù
nohupmặc định ghi log vàonohup.out(hoặc$HOME/nohup.out) nhưng bạn vẫn có thể chuyển hướng đầu ra để kiểm soát tốt hơn.
- Tách luồng: để dễ dàng theo dõi lỗi, hãy tách
stdoutvàstderrvào các tệp khác nhau, ví dụ:nohup ./my_cmd > app.log 2> app.err &. - Gộp luồng: để gom toàn bộ đầu ra vào một tệp duy nhất, có thể dùng:
nohup ./my_cmd > combined.log 2>&1 &.
- Mô tả tên tệp rõ ràng, có thể kèm timestamp (ví dụ:
app_$(date +%F).log), để dễ nhận diện log. Lưu các tệp log vào thư mục chuyên biệt như/var/log/my_app/hoặc thư mụclogs/trong dự án, đồng thời đảm bảo tiến trình có đủ quyền ghi. - Điều quan trọng nhất là ứng dụng (
./my_cmd) phải tạo log có cấu trúc, kèm timestamp, mức độ chi tiết và cấp độ log phù hợp (INFO,DEBUG,ERROR).Nohupchỉ đóng vai trò ghi lại đầu ra này, còn chất lượng log hoàn toàn phụ thuộc vào ứng dụng. Nohupkhông có khả năng tự xoay vòng log (log rotation). Đối với các tiến trình chạy dài hạn, để tránh việc log chiếm dụng quá nhiều dung lượng đĩa, bạn nên triển khai cơ chế log rotation. Việc này có thể được thực hiện ngay trong ứng dụng hoặc thông qua các công cụ bên ngoài nhưlogrotateđể quản lý các tệp log donohupghi lại.- Nên thường xuyên xem lại log bằng các công cụ như
tail -f(theo dõi trực tiếp),lesshoặcgrepđể kiểm tra lỗi và đảm bảo ứng dụng hoạt động hiệu quả.
Nếu tập trung vào cách ứng dụng ghi log và cách nohup thu thập đầu ra, bạn có thể xây dựng chiến lược logging hiệu quả.
Câu hỏi thường gặp (FAQs)
1. nohup làm gì trong Linux?
Nohup (viết tắt của no hang up) là lệnh trong Linux cho phép tiến trình tiếp tục chạy sau khi đăng xuất hoặc đóng terminal, bằng cách bỏ qua tín hiệu SIGHUP vốn được gửi khi terminal bị ngắt kết nối.
2. Có cần dùng & với nohup không?
Mặc dù nohup giúp lệnh miễn nhiễm với tín hiệu SIGHUP nhưng nó không tự động đưa lệnh vào chế độ chạy nền.
- Khi chạy lệnh
nohup your_command, terminal sẽ vẫn gắn với tiến trình và prompt sẽ không xuất hiện trở lại cho đến khi lệnh kết thúc. Tuy nhiên, nếu session terminal bị đóng,your_commandvẫn tiếp tục chạy. - Cách sử dụng phổ biến hơn là
nohup your_command &. Ký tự&yêu cầu shell đưa lệnh vào chế độ chạy nền, nhờ đó terminal được giải phóng ngay lập tức.
Như vậy, không bắt buộc phải dùng ký tự & để nohup bảo vệ tiến trình khỏi tín hiệu SIGHUP, thay vào đó, chúng ta chỉ dùng & để lấy lại quyền điều khiển terminal.
3. Đầu ra của lệnh nohup sẽ đi đâu?
Theo mặc định, nohup sẽ chuyển hướng đầu ra chuẩn (stdout) và lỗi chuẩn (stderr) của lệnh vào một tệp.
- Trước tiên, nó sẽ cố gắng ghi vào tệp
nohup.outtrong thư mục hiện tại. - Nếu không thể tạo
nohup.outtại đó (ví dụ do thiếu quyền ghi), nó sẽ thử tạo và sử dụng$HOME/nohup.out(tệpnohup.outtrong thư mục home). - Người dùng cũng có thể, và thường nên, chuyển hướng đầu ra tới một tệp cụ thể theo ý muốn, chẳng hạn:
nohup ./my_script.sh > my_output.log 2> my_errors.log &
Hoặc gộp cả hai vào một tệp:
nohup ./my_script.sh > all_my_output.log 2>&1 &
4. Sự khác nhau giữa nohup và tmux là gì?
Mặc dù cùng cho phép tiến trình tiếp tục chạy sau khi ngắt kết nối, nhưng nohup và tmux có mục đích chính rất khác nhau trong việc quản lý tiến trình.
nohupchủ yếu để chạy một lệnh đơn, thường là không tương tác, ở chế độ nền và đảm bảo nó tiếp tục chạy sau khi bạn đăng xuất, với đầu ra thường được ghi vào tệp (nhưnohup.out). Đây là công cụ kiểu “chạy rồi quên”, không có session duy trì để quay lại.tmuxlà một terminal multiplexer tạo ra session tương tác, bền vững. Các session này có thể chứa nhiều cửa sổ và khung, cho phép bạn chạy nhiều lệnh và ứng dụng, xem trực tiếp đầu ra, và tương tác với chúng. Bạn có thể tách khỏi sessiontmux(giữ nguyên tiến trình chạy) và gắn lại sau đó.
Kết luận
Tóm lại, nohup là một tiện ích Linux không thể thiếu để đảm bảo các lệnh quan trọng tiếp tục tồn tại vượt ra ngoài vòng đời của session terminal. Bằng cách bỏ qua tín hiệu SIGHUP và cung cấp cơ chế chuyển hướng đầu ra, nó mang lại một phương pháp đơn giản nhưng mạnh mẽ để chạy các tiến trình nền hiệu quả, góp phần tạo sự ổn định và liên tục cho các tác vụ dài hạn quan trọng.
Bạn đã sẵn sàng khám phá sâu hơn vào thế giới các lệnh Linux và quản lý tiến trình chưa? Hãy mở rộng kiến thức và nâng cao kỹ năng dòng lệnh của mình với những hướng dẫn sau:
- Cách sử dụng Job Control của Bash để quản lý tiến trình foreground và background
- 50+ lệnh Linux thiết yếu: Hướng dẫn toàn diện
- Làm chủ lệnh Grep trong Linux/Unix: Hướng dẫn cho người mới bắt đầu
- Các lệnh quản lý tiến trình trong Linux