리눅스 jobs 명령어 사용법 - fg, bg, Ctrl+Z로 터미널 작업 관리하기
이 명령어를 언제 쓰는가
설정 파일을 vim으로 열어 편집하던 중에 다른 경로를 확인해야 할 때가 있다. vim을 저장하고 나갔다가 다시 여는 대신 Ctrl+Z로 잠깐 멈춰 두고, 확인이 끝나면 fg로 돌아오면 된다. 이때 멈춰 둔 작업 목록을 보는 것이 jobs다.
백그라운드로 돌린 스크립트가 아직 도는지 확인할 때도 쓴다. jobs는 외부 프로그램이 아니라 셸 빌트인이라, 현재 셸이 직접 띄운 작업만 알고 있다. 이 성질이 편리함과 함정을 동시에 만든다.
기본 형식
jobs [-l|-p|-r|-s] [%잡번호]
잡을 가리킬 때는 PID가 아니라 %1 같은 잡 번호를 쓴다. %+는 가장 최근 잡(목록에서 +로 표시), %-는 그 직전 잡이다. %vim처럼 이름으로도 지정할 수 있고, %?worker는 명령줄에 그 문자열이 들어간 잡을 찾는다.
자주 쓰는 옵션과 관련 명령
| 옵션 / 명령 | 의미 | 예시 |
|---|---|---|
| jobs -l | PID까지 함께 표시 | jobs -l |
| jobs -p | PID만 출력. 파이프로 넘길 때 | kill $(jobs -p) |
| jobs -r | 실행 중인 잡만 | jobs -r |
| jobs -s | 정지된 잡만 | jobs -s |
| Ctrl+Z | 포그라운드 작업에 SIGTSTP를 보내 정지 | vim 편집 중 Ctrl+Z |
| fg %N | 해당 잡을 포그라운드로 가져온다 | fg %1 |
| bg %N | 정지된 잡을 백그라운드에서 재개 | bg %2 |
| disown %N | 잡을 셸 관리 목록에서 뗀다 | disown -h %2 |
| wait | 백그라운드 잡이 끝날 때까지 기다린다 | wait %1 |
실전 예제
1) 편집 중에 잠깐 빠져나갔다가 돌아온다. 가장 많이 쓰는 패턴이다.
# vim /etc/nginx/nginx.conf 편집 중 Ctrl+Z
jobs -l
tail -20 /var/log/nginx/error.log
fg %1
[1]+ 4821 Stopped vim /etc/nginx/nginx.conf
2) 포그라운드에서 시작해 버린 긴 작업을 백그라운드로 넘긴다. 몇 분 걸릴 줄 알았는데 몇 시간짜리였을 때 쓴다.
# Ctrl+Z 로 정지시킨 뒤
bg %1
jobs -l
[1]+ 5033 Running ./reindex.sh &
3) 여러 작업을 동시에 돌리고 전부 끝나기를 기다린다. 병렬 처리 스크립트의 기본형이다. wait를 인자 없이 쓰면 모든 백그라운드 잡을 기다린다.
./dump_db.sh shopdb > /tmp/shopdb.log 2>&1 &
./dump_db.sh userdb > /tmp/userdb.log 2>&1 &
jobs -l
wait
echo "모든 덤프 완료"
4) 로그아웃해도 살아남게 만든다. nohup 없이 띄운 뒤 뒤늦게 조치하는 방법이다. -h는 잡을 목록에 남겨 두되 SIGHUP만 안 받게 한다.
jobs -l
disown -h %2
함정과 주의점
jobs는 그 셸에서만 보인다. 다른 터미널을 열거나 SSH로 다시 접속하면 목록이 비어 있다. 아까 백그라운드로 돌린 작업이 사라진 게 아니라 새 셸이 그 잡을 모를 뿐이다. 이럴 때는 ps -ef | grep이나 pgrep -a로 찾아야 한다. 또 비대화형 셸 스크립트에서는 잡 컨트롤이 기본적으로 꺼져 있다. jobs, wait %1, kill %1은 스크립트 안에서도 그대로 동작하지만, fg와 bg는 no job control in this shell 에러를 낸다(set -m으로 켤 수는 있다). 또 서브셸은 부모의 잡 목록을 물려받지 않아서 ( wait %1 )은 no such job이 된다. 스크립트에서는 $!로 PID를 받아 다루는 것이 정석이다.
정지된 잡을 두고 나가면 죽는다. Stopped 상태인 잡이 있을 때 exit를 치면 bash가 "There are stopped jobs."라고 한 번 막아 준다. 여기서 다시 exit를 치면 그냥 나가 버리고, 잡은 SIGHUP을 받고 종료된다. 저장하지 않은 vim 편집 내용이 이렇게 날아간다.
Ctrl+Z로 멈춘 프로세스는 자원을 놓지 않는다. CPU는 안 쓰지만 열어 둔 파일, 소켓, DB 커넥션, 트랜잭션 락은 그대로 붙잡고 있다. 운영 DB에 붙은 mysql 클라이언트를 Ctrl+Z로 멈춰 두고 잊어버리면, 그 세션이 잡고 있던 락 때문에 다른 쿼리가 줄줄이 밀린다. 잠깐 빠져나올 게 아니라면 제대로 종료한다.
백그라운드 잡의 출력은 터미널에 그대로 섞여 나온다. bg로 보낸 작업이 화면에 로그를 뿌리면 지금 치는 명령과 뒤엉킨다. 백그라운드로 보낼 작업은 처음부터 출력을 파일로 리다이렉트해 두는 편이 낫다.
함께 보면 좋은 명령어
- nohup — 처음부터 세션과 무관하게 돌릴 작정이라면 잡 컨트롤보다 이쪽이 맞다.
- tmux — 세션 자체를 서버에 남긴다. 잡 컨트롤의 한계(셸이 죽으면 끝)를 근본적으로 없앤다.
- pgrep — 다른 터미널에서 그 작업을 다시 찾아야 할 때 쓴다.