Linux에서 백그라운드 프로세스를 실행하고 제어하는 ​​방법

리눅스 Bash 쉘에서 프로세스 관리하기

리눅스 환경에서 Bash 쉘은 포그라운드 및 백그라운드 프로세스를 효율적으로 제어할 수 있는 강력한 도구입니다. Bash 쉘의 작업 제어 기능과 다양한 신호를 활용하여 명령 실행에 있어 뛰어난 유연성을 확보할 수 있습니다. 이 글에서는 Bash 쉘을 이용한 프로세스 관리 방법에 대해 자세히 알아봅니다.

프로세스의 기본 이해

리눅스 및 유닉스 계열 운영체제에서 프로그램이 작동할 때마다 프로세스가 시작됩니다. 여기서 “프로세스”란 컴퓨터 메모리에서 실행 중인 프로그램의 내부적 표현을 의미합니다. 즉, 활성화된 모든 프로그램은 고유의 프로세스를 갖게 됩니다. 이는 그래픽 데스크톱 환경(GDE)과 같은 시각적인 요소부터 백그라운드에서 작동하는 시스템 데몬까지, 컴퓨터에서 실행되는 거의 모든 것에 적용됩니다. 예를 들어, GNOME 이나 KDE 와 같은 데스크톱 환경과 시스템 데몬들이 이에 해당합니다.

흥미로운 점은, Bash 내장 명령어인 cd, pwd, 그리고 alias 와 같은 명령어들은 실행 시 별도의 프로세스를 생성하지 않는다는 것입니다. 이들은 터미널에서 실행 중인 Bash 쉘 자체의 인스턴스 내에서 직접 실행됩니다. 이러한 내장 명령어들은 프로세스 생성 과정이 생략되므로, 더 빠르고 효율적으로 실행될 수 있습니다. Bash 내장 명령어의 전체 목록을 확인하려면 터미널에 ‘help’를 입력해 보세요.

프로세스는 크게 두 가지 방식으로 실행될 수 있습니다. 포그라운드 프로세스는 터미널을 점유하며 완료될 때까지 다른 작업을 수행할 수 없도록 합니다. 반면, 백그라운드 프로세스는 터미널을 점유하지 않고 사용자가 다른 명령을 입력하거나 작업을 수행할 수 있도록 허용합니다. 백그라운드 프로세스는 화면 출력을 생성하지 않는 경우에 특히 유용합니다.

실제 예시를 통한 이해

간단한 예시로, ‘ping’ 명령을 사용하여 How-To Geek 도메인을 ping 해보겠습니다. 먼저, 포그라운드 프로세스로 실행해 봅시다.

ping www.wdzwdz.com

ping 명령이 실행되는 동안에는 터미널에서 다른 작업을 수행할 수 없습니다. ping 명령을 종료하려면 ‘Ctrl + C’ 키를 눌러야 합니다.

Ctrl+C

Ctrl + C를 누르면 ping 명령이 즉시 중단되고, 간단한 요약 정보를 출력한 후 종료됩니다.

이번에는 ‘Ctrl + Z’ 키를 눌러보겠습니다. 이렇게 하면 프로세스가 종료되는 대신 일시 중지되고, 백그라운드 작업으로 전환됩니다. 터미널 제어권은 다시 사용자에게 반환됩니다.

ping www.wdzwdz.com
Ctrl+Z

‘Ctrl + Z’ 키를 누르면 프로세스가 일시 중지되고, 백그라운드 작업으로 전환됩니다. 이는 마치 자동차를 일시 정지시킨 것과 같습니다. 프로세스는 아직 실행을 완전히 종료한 것은 아니며, 다시 시작되기를 기다리는 상태입니다.

이제 ‘jobs’ 명령을 사용하여 현재 터미널 세션에서 시작된 작업 목록을 확인해 봅시다. 작업은 프로세스와 동일하므로, ‘ps’ 명령을 사용하여 프로세스 정보를 확인할 수도 있습니다. 두 명령의 출력을 비교해 보겠습니다. ‘ps T’ 명령을 사용하면 현재 터미널 창에서 실행 중인 프로세스만 볼 수 있습니다.

jobs
ps T

‘jobs’ 명령은 다음 정보를 제공합니다.

  • [1]: 대괄호 안의 숫자는 작업 번호입니다. 작업 제어 명령을 사용할 때 특정 작업을 참조하는 데 사용됩니다.
  • +: 더하기 기호(+)는 작업 번호를 지정하지 않은 경우, 어떤 작업 제어 명령이 적용되는지 나타냅니다. 이것을 기본 작업이라고 하며, 항상 작업 목록에 가장 최근에 추가된 작업입니다.
  • 중지됨: 프로세스가 현재 실행되지 않고 일시 중지된 상태임을 나타냅니다.
  • ping www.wdzwdz.com: 프로세스를 시작한 명령줄입니다.

‘ps’ 명령은 다음 정보를 제공합니다.

  • PID: 프로세스의 고유한 프로세스 ID입니다.
  • TTY: 프로세스가 실행된 터미널 창(의사 텔레타이프)입니다.
  • STAT: 프로세스의 현재 상태입니다.
  • TIME: 프로세스가 사용한 CPU 시간입니다.
  • COMMAND: 프로세스를 시작한 명령입니다.

‘STAT’ 열의 주요 값은 다음과 같습니다.

  • D: 중단 불가능한 수면 상태. 주로 입력/출력을 대기하는 상태로, 외부에서 강제로 중단할 수 없습니다.
  • I: 유휴 상태.
  • R: 실행 중 상태.
  • S: 중단 가능한 수면 상태.
  • T: 작업 제어 신호에 의해 중지된 상태.
  • Z: 좀비 프로세스. 프로세스가 종료되었지만, 상위 프로세스에 의해 완전히 정리되지 않은 상태.

‘STAT’ 열 값 뒤에 추가적인 정보가 표시될 수도 있습니다.

  • N: 저우선순위 작업.
  • L: 메모리에 잠긴 페이지를 가진 프로세스.
  • S: 세션 리더. 세션 리더는 그룹을 시작한 쉘입니다.
  • +: 포그라운드 그룹의 구성원입니다.
  • l: 다중 스레드 프로세스입니다.

Bash 쉘 자체의 상태는 ‘Ss’로 표시됩니다. 여기서 ‘S’는 쉘이 수면 중이며 인터럽트가 가능함을, ‘s’는 쉘이 세션 리더임을 나타냅니다. ping 명령의 상태는 ‘T’로 표시되며, 이는 작업 제어 신호에 의해 중지되었음을 의미합니다. 이 예에서는 ‘Ctrl + Z’ 키를 사용하여 백그라운드로 전환했습니다. ‘ps T’ 명령의 상태 ‘R+’는 실행 중이며, 포그라운드 그룹의 구성원임을 나타냅니다.

bg 명령

‘bg’ 명령은 백그라운드 프로세스를 재개하는 데 사용됩니다. 이 명령은 작업 번호와 함께 사용하거나 없이 사용할 수 있습니다. 작업 번호를 지정하지 않으면 기본 작업(가장 최근에 백그라운드로 전환된 작업)이 다시 시작됩니다. 프로세스는 여전히 백그라운드에서 실행되므로, 키보드 입력을 받을 수 없습니다.

이제 ‘bg’ 명령을 실행하여 ping 명령을 다시 시작해 보겠습니다.

bg

ping 명령이 다시 실행되고, 터미널에 출력이 표시됩니다. 재개된 명령의 이름이 표시되는 것을 확인할 수 있습니다.

여기서 중요한 점은, 백그라운드 작업은 키보드 입력을 받지 못한다는 것입니다. ‘Ctrl + C’ 키를 눌러도 백그라운드 작업은 영향을 받지 않습니다. 따라서, 현재 상태에서는 백그라운드 작업을 중단할 수 있는 방법이 없습니다.

터미널에 명령어를 입력할 수는 있지만, 백그라운드 작업의 출력 때문에 입력한 내용이 가려지는 상황이 발생합니다. 현재 터미널의 입력은 포그라운드에 적용됩니다.

백그라운드 작업을 중단하려면 먼저 해당 작업을 포그라운드로 가져온 다음 중단해야 합니다.

fg 명령

‘fg’ 명령은 백그라운드 작업을 포그라운드로 가져오는 데 사용됩니다. ‘bg’ 명령과 마찬가지로, 작업 번호와 함께 사용하거나 없이 사용할 수 있습니다. 작업 번호를 지정하면 해당 작업이 포그라운드로 이동하고, 그렇지 않으면 마지막으로 백그라운드로 전환된 작업이 포그라운드로 이동합니다.

‘fg’ 명령을 입력하면 ping 명령이 다시 포그라운드에서 실행됩니다. 입력하는 문자는 ping 명령의 출력과 섞여서 표시될 수 있지만, 정상적으로 명령줄에 입력한 것처럼 쉘에서 처리됩니다.

fg

이제 ping 명령이 다시 포그라운드에서 실행 중이므로, ‘Ctrl + C’ 키를 사용하여 종료할 수 있습니다.

Ctrl+C

신호의 중요성

위에서 살펴본 예시는 백그라운드 프로세스를 실행하는 것이 출력과 입력이 필요 없는 작업에 가장 적합하다는 것을 보여줍니다. 앞선 예시는 다음과 같은 작업을 수행했습니다.

  • 프로세스를 백그라운드로 전환.
  • 백그라운드에서 실행 중인 프로세스를 다시 시작.
  • 프로세스를 다시 포그라운드로 가져오기.
  • 프로세스를 종료.

‘Ctrl + C’와 ‘Ctrl + Z’는 프로세스에 특정 신호를 보내는 단축키입니다. 이들은 ‘kill’ 명령의 간편한 형태이며, 총 64개의 신호를 사용할 수 있습니다. ‘kill -l’ 명령을 사용하여 사용 가능한 신호 목록을 확인할 수 있습니다. ‘kill’ 명령 외에도, 시스템 내부의 다른 프로세스에 의해 자동으로 신호가 발생하기도 합니다.

다음은 자주 사용되는 신호들입니다.

  • SIGHUP (신호 1): 터미널이 닫힐 때, 해당 터미널에서 실행 중인 프로세스에 자동으로 전송됩니다.
  • SIGINT (신호 2): ‘Ctrl + C’ 키를 누르면 프로세스에 전송되어, 프로세스가 중단되고 종료를 시도합니다.
  • SIGQUIT (신호 3): ‘Ctrl + D’와 같은 종료 신호를 보내면, 해당 프로세스에 전송됩니다.
  • SIGKILL (신호 9): 프로세스를 즉시 강제로 종료합니다. 프로세스는 종료 작업을 진행할 수 없습니다.
  • SIGTERM (신호 15): ‘kill’ 명령이 기본적으로 보내는 신호로, 표준 프로그램 종료 신호입니다.
  • SIGTSTP (신호 20): ‘Ctrl + Z’ 키를 누를 때 프로세스에 전송되어, 프로세스를 중지하고 백그라운드로 전환합니다.

키 조합이 할당되지 않은 신호를 보내려면 ‘kill’ 명령을 사용해야 합니다.

추가적인 작업 제어

‘Ctrl + Z’ 키를 사용하여 백그라운드로 이동한 프로세스는 중지된 상태로 남아 있습니다. 다시 실행하려면 ‘bg’ 명령을 사용해야 합니다. 프로그램을 백그라운드 프로세스로 바로 시작하는 간단한 방법은 명령어 끝에 앰퍼샌드(&)를 추가하는 것입니다.

백그라운드 프로세스가 터미널 창에 출력을 생성하지 않는 것이 가장 좋지만, 여기서는 설명을 위해 출력을 생성하는 예시를 사용하겠습니다. 다음 명령은 백그라운드 프로세스로 무한 루프를 실행합니다.

while true; do echo "긱 루프 프로세스 방법"; sleep 3; done &

터미널은 프로세스의 작업 번호와 프로세스 ID를 알려줍니다. 이 예시에서 작업 번호는 1이고, 프로세스 ID는 1979입니다. 이 식별자들을 사용하여 프로세스를 제어할 수 있습니다.

무한 루프의 출력이 터미널에 나타나기 시작합니다. 명령줄을 사용할 수 있지만, 실행하는 모든 명령어는 루프 프로세스의 출력과 섞여서 표시됩니다.

프로세스를 중단하려면, ‘jobs’ 명령을 사용하여 작업 번호를 확인한 다음 ‘kill’ 명령을 사용할 수 있습니다. ‘jobs’ 명령은 우리 프로세스의 작업 번호가 1이라고 알려줍니다. 이 작업 번호를 ‘kill’ 명령에 사용하려면 앞에 퍼센트 기호(%)를 붙여야 합니다.

jobs
kill %1

‘kill’ 명령은 프로세스에 SIGTERM 신호(신호 번호 15)를 보내어 종료를 시도합니다. ‘Enter’ 키를 누르면 작업 상태가 표시됩니다. 프로세스가 “종료됨”으로 표시됩니다. 프로세스가 ‘kill’ 명령에 응답하지 않으면, ‘kill’ 명령을 SIGKILL 신호(신호 번호 9)와 함께 사용하여 강제로 종료할 수 있습니다. ‘kill 9 %1’과 같이 명령을 입력하면 됩니다.

kill 9 %1

정리

지금까지 배운 내용들을 정리하면 다음과 같습니다.

  • Ctrl + C: 포그라운드 프로세스에 SIGINT 신호(신호 2)를 보내어 종료를 시도합니다.
  • Ctrl + D: 포그라운드 프로세스에 SIGQUIT 신호(신호 3)를 보내어 종료를 시도합니다.
  • Ctrl + Z: 프로세스에 SIGTSTP 신호(신호 20)를 보내어 중지(일시 중단)시키고 백그라운드 프로세스로 만듭니다.
  • jobs: 백그라운드 작업 목록을 표시하고 작업 번호를 제공합니다.
  • bg job_number: 백그라운드 프로세스를 재개합니다. 작업 번호를 지정하지 않으면, 마지막으로 백그라운드로 전환된 프로세스를 사용합니다.
  • fg job_number: 백그라운드 프로세스를 포그라운드로 가져와 다시 시작합니다. 작업 번호를 지정하지 않으면, 마지막으로 백그라운드로 전환된 프로세스를 사용합니다.
  • 명령어 &: 명령어 끝에 앰퍼샌드를 추가하여 해당 명령어를 백그라운드 작업으로 실행합니다.
  • kill %job_number: 프로세스에 SIGTERM 신호(신호 15)를 보내어 프로세스를 종료합니다.
  • kill 9 %job_number: 프로세스에 SIGKILL 신호(신호 9)를 보내어 즉시 강제로 종료합니다.