nohup & 으로 백그라운드 프로세스를 실행시킬 때 발생하는 일

어떤 프로그램을 실행시킬 때 백그라운드로 돌리고 싶다면, 명령어 뒤에다 &를 붙여 사용한다.(사실 개인적으로는 그냥 tmux를 키는 편)

예를 들어 텍스트편집기인 gedit 을 그냥 터미널에서 실행시키면 프로그램이 켜지고 터미널은 프로그램이 종료되기 전까지 대기중임을 확인할 수 있다.

만약에 gedit &와 같이 백그라운드로 실행시킬 경우, 똑같이 프로그램이 켜지지만 터미널에서는 [1] 1234처럼 PID 를 출력하고 쉘 프롬프트로 돌아온다.

그러나 이 터미널에서 실행시킨 프로그램은, 쉘의 stdin, stdout, stderr 를 상속받으며 터미널에 붙게 되고, 따라서 백그라운드로 돌아가고 있다고 할지라도, 터미널이 종료될 경우 해당 프로세스들도 강제로 종료된다.

# 백그라운드로 실행 후
gedit&
# gedit 프로세스가 동작 중임을 확인
ps -ef | grep gedit

# gedit 을 백그라운드로 실행한 터미널을 종료하면, gedit 프로그램도 같이 종료됨
# 새로운 터미널을 켜서 확인해보면 gedit 프로세스가 나오지 않음
ps -ef | grep gedit

터미널이 종료될 때 해당 터미널에 붙어있는 백그라운드 프로세스가 종료된다면, 서버에 ssh 로 접속한 뒤 어떤 프로그램을 백그라운드로 실행시킨 뒤 서버에서 빠져나오면 해당 프로세스가 종료되게 된다.

우리는 이것을 원한 것은 아니기 때문에, 터미널과 프로세스를 떼어놓을 필요가 있는데 이것이 nohup이다.


nohup 으로 시그널 받지 않기

어떤 이벤트가 발생했을 때 발생시키는 신호를 시그널이라고 한다.

터미널에서 Ctrl + C 를 누르면 키보드인터럽트가 발생하면서 종료되는 것도 SIGINT라는 시그널을 받았기 때문에 운영체제에서 프로그램을 종료시킨 것이다.

이처럼, 터미널이 종료될 때 발생하는 시그널도 있는데 이를 SIGHUB이라고 한다.

쉘은 SIGHUB 을 받으면 이 신호를 프로세스들로 보내서 프로세스를 종료시키고, 그렇기 때문에 실행 중이던 백그라운드 프로세스도 SIGHUB 을 받아 종료되는 것이다.

nohup 이 바로 프로세스를 터미널과 분리시키는 역할을 하는 명령어다.

터미널과 분리되기 때문에 터미널로부터 입력을 받아오던 stdin 과, 터미널에 출력하던 stderr 나 stdout 역시 닫힌다.

그러나 프로그램에서 나오는 stderr 와 stdout 값들은 어딘가에 쓰여져야 하기 때문에, 따로 재지정을 해주지 않으면 nohup.out파일로 자동으로 redirection 시켜준다.

nohup 을 사용할 경우 터미널을 종료해도 프로세스가 죽지 않는 것을 확인할 수 있다.

nohup gedit & 2> /dev/null 1>output.txt
ps -ef | grep gedit

# 터미널 종료해도 gedit 프로그램이 종료되지 않음
# 새로운 터미널을 켜서 확인해봐도 여전히 프로세스는 살아있음
ps -ef | grep gedit

그렇기 때문에 (강제로)프로세스를 끝내기 위해서는 PID를 확인 후 kill -9 PID처럼 직접 죽여야 한다.(kill 명령어도 SIGKILL 이라는 시그널을 보낸다는 것!)