본문 바로가기

Linux & Mac

nohup 사용법 ( 터미널 로그아웃 후 프로세스 실행 유지 )

반응형

대부분은 nohup의 목적을 알고 오셨으리라 생각해서 사용 방법부터 간단히 짚어 드린 뒤 자세한 설명을 하겠습니다.

nohup [command] > [output file name] &

[command]에는 보통 스크립트의 구동 명령이 들어 가겠죠. 만약 구동을 원하는 스크립트가 printLoop.sh 라면 아래와 같이 적으시면 됩니다.

nohup sh printLoop.sh > printLoop.out &

위와 같은 코드에서는 printLoop.sh 가 실행되어 모니터로 출력되는 내용이 자동으로 printLoop.out 파일에 저장됩니다. 커맨드의 가장 끝 &는 백그라운드 실행을 의미합니다. 안 해도 상관없지만 nohup을 사용해야 하는 환경이라면 거의 필수적이라고 볼 수 있습니다.

출력이 중요하지 않으시면 아래와 같이 구동 시키셔도 됩니다. 그렇게 하면 구동시킨 위치에 nohup.out 파일이 생성되며 해당 파일에 출력이 저장됩니다.

nohup sh printLoop.sh &

이 구분선 아래로 자세한 설명이 시작됩니다.


주의!!!

2020년 현재 일반 배포되는 리눅스 운영체제에서는 대부분 터미널이 종료되어도 프로세스를 종료시키지 않도록 설정되어 있습니다. 이런 경우 그냥 백그라운드 구동을 시키셔도 같은 효과를 보실 수 있습니다. 이 내역은 아래 링크를 참조 하시기 바랍니다.

2020/09/22 - [ubuntu] - 로그아웃 이후 프로세스 유지 & 종료


리눅스 기반 시스템은 주로 고성능 컴퓨팅 장비가 필요한 일에 이용되는 편이죠.

어떤 프로그램은 5분 이내에 구동되지만 며칠 동안 구동되는 프로그램을 실행해야 할 때도 있습니다.

만약 일반 데스크톱이라면 프로그램을 구동시키고 완료될 때까지 방치하는 방식을 이용합니다. 아래 그림처럼 사용자는 자신의 데스크톱을 이용하니 그냥 끝날 때까지 켜 두면 되죠.

desktop

설명을 더 쉽게 하기 위해서 코드 하나를 만들었습니다. 코드는 아래와 같은 쉘 스크립트이며 파일명을 printLoop.sh입니다. 간략히 설명하자면 이 코드는 0초부터 1분까지 1초 간격으로 화면에 출력합니다.

for i in $(seq 0 1 60)
do
	echo " ${i} sec"
    sleep 1
done

위와 같은 코드를 일반 리눅스 데스크톱에서 돌리면 아래와 같이 돌게 되죠. 적합한 terminal을 열고 커맨드(sh printLoop.sh)를 통해 스크립트를 구동시킵니다. 컴퓨터는 스크립트에 따라 출력을 해서 60초가 출력되면 자동으로 끝납니다. 사용자가 원하는 결과죠. 박수~~ 짝짝짝

그러면 다른 경우를 보죠. 고성능 컴퓨팅 시스템을 이용할 때는 일반 데스크톱과 사용법이 달라집니다. 기본 사용법은 ssh를 이용한 원격 구동입니다. 이러한 환경에서는 문제가 생깁니다. 원하는 프로세스를 무사히 완료하기 위해서는 아래 그림과 같이 터미널로 이용되는 클라이언트의 컴퓨팅 디바이스와 고성능 컴퓨팅 시스템이 모두 켜져 있어야 하고, 네트워크 연결이 계속 유지되어야 합니다.

이러한 경우의 출력입니다. (맥북에서 Ubuntu를 패러렐즈로 구동시키고 ssh로 연결하여 구동한 화면) 왼쪽의 클라이언트 터미널에서 printLoop.sh 스크립트를 구동시켜 결과를 보고 있죠. 간단한 작업이라면 이러한 방식으로 프로그램을 구동시킵니다. 이렇게 구동시킨 경우 사용자는 해당 서버와 계속 대화형 인터페이스를 유지할 수 있는 장점이 있죠.

이 환경에서의 치명적인 문제는 구동 중 터미널이 다운되거나 네트워크 연결이 끊어지면 프로그램은 처음부터 다시 구동되어야 합니다. 

아래 스냅샷은 구동 중 서버에서 강제로 네트워크를 단절시킨 결과입니다.

리눅스의 빨간색 네모에서 네트워크 연결을 끊었음을 확인하실 수 있습니다.

그 결과 클라이언트에서 구동되던 printLoop.sh는 14초에서 disconnect 되어 강제 종료(빨간 화살표) 되었습니다. 네트워크가 끊긴 상황 이기 때문에 Ubuntu의 터미널(보라색 화살표) 에서 disconnect되어 mac의 터미널(녹색 화살표)로 빠져나온 상태입니다.

이렇게 터미널이 꺼지거나 네트웍이 끊어지면 열심히 구동시킨 프로세스는 자동 종료됩니다. (&를 이용해서 백그라운드로 구동시켜도 터미널이 disconnect 되면 프로세스는 강제 종료됩니다.) 이런 상황은 의외로 많이 발생하며, 특히 웹 기반 클라우드 서비스 이용 시 자주 발생합니다.

위와 같은 프로세스 종료 문제를 해결하는 프로그램이 nohup입니다. nohup은 프로세스를 구동시킨 터미널이 꺼져도 프로세스를 유지합니다. 아래 그림처럼 프로그램을 구동시킨 뒤, 네트워크를 끊어도 터미널을 꺼도 상관없이 구동됩니다.

구동 방법은 글의 시작에 적어 두었지만 다시 한번 설명하겠습니다. 명령어는 아래와 같습니다. nohup으로 [command]를 구동하는데 결과물(화면 출력물)은 [output file]에 적고 해당 프로세스는 백그라운드에서 실행합니다.

nohup [command] > [output file] &

그런데 여기서 소소한 함정이 두 군데 있습니다. 원래 shell의 명령어인 것이 nohup의 명령어 인척 하고 있죠. 주인공은 '>'와 '&'입니다. 둘 중 그나마 많이 쓰이는 '&'는 백그라운드 실행을 의미합니다. '&'가 꼬리에 붙은 명령어를 실행할 때 터미널은 프로세스가 끝나길 기다리지 않고 바로 다음 명령어 대기 상태가 됩니다. 그리고 '>'는 리다이렉션 명령어입니다. '>'와 자매로 '>>' 도 있죠. ( 사실 더 있지만 나머지는 잘 안 쓰이니까.. ) 이 명령어는 화면에 출력될 프로세스의 출력문을 다른 매체에 저장합니다. 그 매체는 보통 디스크에 기록되는 파일이고, 특이한 경우 프린트나 제3의 출력 매체 일수 있습니다.

글로는 복잡하기만 하니 예제로 설명하도록 하죠. 만약 위 명령어에서 nohup을 제외하면 어떻게 될까요? 명령어는 당연히 아래와 같습니다.

sh printLoop.sh > printLoop.out &

결과는 아래 스냅샷 입니다. "printLoop.sh"를 구동시키지만 터미널은 숫자 하나를 남기고 다음 명령을 받습니다. 이건 명령어에 '&'가 붙어 있기 때문이죠. 프로세스는 백그라운드에서 실행되고, 사용자는 원하는 다른 work을 할 수 있습니다. 프로그램이 구동되는 1분 동안 프로그램의 구동 여부를 확인하는 가장 쉬운 방법은 ps 명령어로 프로세스가 구동 중인지 확인하는 것이죠. 명령어 결과를 보면 23시 45분에 구동을 시작한 프로세스 넘버 6266번 (그렇습니다. 구동 직후 나온 숫자가 프로세스 넘버입니다.) 이 "sh printLoop.sh" 명령을 수행하고 있습니다. 그리고 1분 후 해당 프로세스가 끝났음(노란 박스)을 터미널이 알려줍니다. 프로세스가 끝났다는 통보는 바로 하지 않고 사용자가 다른 웍을 마쳤을 때 알려줍니다.

그런데 약간 이상한 게 있죠. 원래 해당 프로그램은 "0 sec"부터 시작해서 "60 sec"까지 출력하고 끝나야 하는데 그 내용은 어디 있을까요? 그 비밀은 '>'에 있습니다. 위 명령어에서 사용자는 리다이렉션을 이용해 printLoop.out이라는 파일에 결과를 출력하라고 했죠. 그러니 해당 파일을 보면 됩니다. 

원래 화면에 출력되었어야 하는 내용은 printLoop.out 파일이 가지고 있는 것이죠. 추가 팁으로 ">>"를 이용하면 기존 파일이 있는 경우 파일의 끝에 추가하여 기재합니다.

그런데 여기서 이상한 점 nohup을 안 써도 백그라운드에서 잘 구동되고 출력도 볼 수 있는데 왜 써야 하는가? 그건 그지같은 그림으로 설명한 상황 때문입니다. 일반적으로 terminal이 열리고 구동된 프로세스는 해당 terminal이 닫히기 전에 끝나야 하며 그전에 terminal이 닫히면 결과를 신뢰하지 못합니다. ( 컴퓨팅 환경 설정 사항에 따라 다를 수 있습니다. )

이번에는 위와 같은 구동을 하되 구동후 서버의 인터넷 연결을 차단했습니다. 아래 스냅숏의 보라색 상자에서 서버의 인터넷이 차단됨을 확인하실 수 있습니다. 그 결과 노란 상자와 같이 클라이언트는 브로큰 파이프로 접속이 자동으로 끊어졌습니다. 

그 결과 저장된 printLoop.out 파일은 아래 스냅샷과 같습니다. 60초까지 진행하지 못하고 연결이 끊어져 39초까지만 출력된 결과를 볼 수 있습니다.

nohup은 이와 같이 클라이언트와 서버 간의 불안정성 문제를 해결해 줍니다. 확실한 비교를 위해 이번엔 두 개의 터미널에서 nohup을 사용한 경우와 백그라운드에서 구동시킨 경우의 차이를 보여 드립니다.

아래 스냅샷에서는 위의 터미널에서 nohup을 이용하고 아래 터미널에서는 백그라운드 구동을 시켰습니다. 보라색 네모를 보면 두 프로세스의 시간 차이는 1초 차이가 발생합니다. 그 후 서버 측에서 노란색 네모와 같이 연결을 끊어 버렸습니다.

두 프로그램의 구동 결과는 아래 스냅샷과 같습니다. 왼쪽은 백그라운드 구동 결과이고, 오른쪽은 nohup을 이용한 결과입니다. 백그라운드 구동 결과에서는 서버의 네트워크 다운으로 인해 39초 까지 구동후 비정상 종료되었습니다. 반면 오른쪽 nohup을 사용한 결과에서는 60초까지 정상 구동후 종료되었음을 확인하실 수 있습니다.

터미널에서 구동된 프로세스는 ctrl + c와 같은 시그널 전송 키를 이용해서, 프로세스를 강제 종료시킬 수 있죠. 하지만 백그라운드로 실행시킨 프로세스는 특정 키로 시그널을 전송할 수 없죠. 그래서 kill을 이용해 강제 종료시키게 됩니다. 그러기 위해서는 프로세스 아이디부터 확인해야 합니다. 다양한 방법이 있지만 보통 ps 커맨드를 이용해 확인하죠. 명령어는 아래와 같습니다.

ps는 프로세스의 정보를 보여주는 명령어고, grep은 출력될 내역에서 뒤에 따라오는 문구를 찾아 검색하는 명령입니다. 그냥 "ps -ef"를 입력하면 사용자가 구동시킨 프로세스와 리눅스가 구동시킨 프로세스가 같이 출력되기 때문에 특정 문구를 검색해서 보여달라고 요청하는 것이지요. 이때 [process name]은 전체 이름을 넣지 않고 "sh"나 "print"와 같은 문구만 넣으셔도 됩니다. "nohup"은 프로세스 이름으로 등록되지 않아서 검색해도 소용없습니다.

ps -ef | grep [process name]

위 명령어로 프로세스의 아이디를 확인하셨다면, 아래 명령어로 정지 시그널을 주시면 됩니다.

kill [process id]

프로세스를 정지시키는 예제는 아래 스냅샷과 같습니다. 먼저 백그라운드로 구동된 프로세스의 프로세스 아이디는 프로세스 구동 뒤 즉시 출력(보라색 상자)됩니다. "ps"와 "grep" 명령어로 관련 프로세스를 검색해 보면 노란색 상자와 같이 13431번 프로세스 아이디로 구동 중인 프로세스가 있죠. 이에 대해 붉은색 상자와 같이 kill 명령어로 정지시키면 됩니다. 

이 방법은 정석적인 프로세스 종료 방법 이죠. 쉽게 하는 법은 다음글로 갈무리 합니다.

2020/10/23 - [Mac] - 프로세스 관리툴 : 리눅스에서 프로그램 강제 종료하기 (htop)

 

프로세스 관리툴 : 리눅스에서 프로그램 강제 종료하기 (htop)

컴퓨터를 이용하다보면 다양한 이유로 컴퓨터가 느려질수 있죠. 그 이유 중 가장 높은 확률로 발생하는 문제는 특정 프로세스가 CPU를 과도하게 이용하거나, 메모리를 너무 많이 써서 SWAP을 이용

sbinroom.tistory.com

이상 nohup을 이용하는 예제였습니다. 마무리로 nohup의 장단점을 정리하겠습니다.

장점

터미널의 상태에 관계없이 프로세스를 구동시킬 수 있음.

특별한 추가 자원 소모가 없음.

단점

대화형 인터페이스가 차단됨.

프로세스 종료가 어려움 (kill 명령어 이용)

이상 마치겠습니다. 아래 내역은 제가 보여드린 서버의 환경 설정 내용입니다. 왼쪽은 터미널 종료 시 프로세스를 죽이도록 설정한 내용이고, 오른쪽은 /etc/ssh/sshd_config의 연결 유지 설정입니다. ( 특별한 설명은 제외함 )

반응형