가끔 crontab 에 등록된 shell script 가 동작을 하지 않고 에러가 났을 경우, 서버내에서 다시 실행해야할때, nohup 을 씁니다.

nohup이란 리눅스, 유닉스에서 쉘스크립트파일을 데몬형태로 실행시키는 프로그램으로, 터미널 세션이 끊겨도 실행을 멈추지 않고 동작하도록 합니다. shell script 를 실행하고 터미널을 종료하면 프로세스 또한 종료되므로, 터미널 세션을 끊겨도 사용해야할 경우에 사용합니다.

보통 명령어는 이렇습니다.

$ nohup shell.sh &
$ nohup sh -- ./shell.sh &

실제 full 경로를 입력하거나 해당 경로에 가서, ./shell 을 실행합니다. 종료하는 방법은 강제로 프로세스를 kill 하는 방법밖에 없습니다. (kill -9 PID)

참고로 위와 같이 nohup과 &을 같이 쓰는 형태로 암기하고 있었는데, &는 프로세스를 실행할 때 백그라운드에서 동작하도록 만드는 명령어로 비슷하지만 다른 명령어입니다.

nohup 으로 실행하면 hang-up signal 이 와도 동작하기 때문에 터미널 연결이 끊어져도 실행을 멈추지 않습니다. & 으로만 실행해도 터미널이 끊어져도 실행이 멈추지는 않는 데, & 은 백그라운드로 돌린다는 의미이며, 기본적으로는 nohup 이 아닐 경우 터미널이 끊어지면 실행도 끊어집니다. 하지만 요즘 옵션에 nohup 과 같은 동작을 하게 설정이 되어 있어서 & 만으로도 nohup 과 같은 동작을 보인다고 합니다.

$ nohup shell.sh > /dev/null

그래서 위와같이 & 대신에 > /dev/null 을 더 자주 쓰게 됩니다. /dev/null 은 주로 불필요한 출력 스트림을 버리는 곳으로 사용됩니다. /dev/null 을 사용하지 않을 경우, nohup.out 이라는 파일이 호출한 위치에 파일을 생성시키는데, 해당 파일을 생성하지 않게 합니다.

행의 극복

nohup으로 백그라운드 처리된 작업들은 원격 SSH 세션을 로그오프할 때 일반적으로 이들의 종료를 막기 위해 사용되며, 이 상황에서 발생할 수 있는 또 다른 문제는 ssh가 로그오프(행)을 거부하는 것인데, 그 이유는 백그라운드 작업들에 대한 데이터 손실을 거부하기 때문이다. 이 문제는 3개의 모든 입출력 스트림을 리다이렉션 처리함으로써 극복할 수 있다고 합니다.

$ nohup ./myprogram > foo.out 2> foo.err < /dev/null &

SSH 세션을 닫으면 무조건 의존 프로세스들에 HUP 신호를 보내지 않게 된다. 이는 의사 터미널의 할당 여부에 따라 달라진다고 하는데,

program < /dev/null program

형태일 때, file descriptor 0 즉 STDIN을 통해 입력인수(옵션에 입력 매개 변수가 있거나 입력 파일이 될 수 있음)를 취하는 것을 의미하는데, /dev/null은 아무것도 포함되어 있지 않으므로, 읽을 때 EOF (End of File)에 알릴 것이므로 /dev/null에서 입력을받는 프로그램은 기본적으로 아무 것도 입력 인수로 리디렉션하지 않습니다.

alias start='nohup java -jar healthcheck.jar /tmp 2>> /dev/null >> /dev/null &'

/tmp 란 폴더를 두어서 별도의 로그관리를 하겠다는 의미이나 에러로그를 /dev/null 에 받게 하기 때문에, 결국 /tmp 폴더에는 별다른 로그가 쌓이지 않게 됩니다.

alias start='nohup java -jar healthcheck.jar >> /dev/null &'

만약 이렇게 한다면 jar 파일 자체의 모든 out 스트림을 /dev/null 에 보내기 때문에 , 아예 동작을 하지 않거나 한번만 동작하고 더이상 실행이 안될 수 있습니다. (nohup을 했기 때문에 프로세스는 계속 떠있습니다. ㅠㅜ)


참조