Computer >> 컴퓨터 >  >> 프로그래밍 >> Bash 프로그래밍

Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기

이 글의 핵심 목표는 Bash에서 스크립트를 직접 실행하는 것source로 불러오는 것 사이에 어떤 차이가 있는지 명확하게 이해하도록 돕는 것입니다. 먼저, 스크립트를 호출하는 다양한 방식에 따라 프로그램이 어떻게 처리되는지부터 살펴보겠습니다.

참고: 스크립트를 만들 때 확장자를 붙이는 것은 필수가 아닙니다. 확장자가 없어도 스크립트는 문제없이 실행됩니다.

쉬뱅(Shebang)이란?

기본적으로 모든 스크립트는 쉬뱅(shebang, #!)이라는 라인으로 시작합니다. Bash에서 #(해시) 기호는 일반적으로 주석으로 해석되지만, shebang은 특별한 의미를 가집니다. shebang은 Bash에게 해당 프로그램을 지정된 인터프리터로 넘겨 실행하도록 지시하는 역할을 합니다.

아래는 간단한 예제 프로그램이며, 인터프리터로 bash를 지정했습니다.

$ cat >> Hello_World.sh
#!/usr/bin/env bash
echo "Hello world"

$ chmod +x Hello_world.sh

스크립트를 실행하는 두 가지 방법

  • 상대 경로 사용: 스크립트가 있는 디렉터리로 이동한 후 ./Hello_world.sh를 입력해 실행합니다.
  • 절대 경로 사용: 파일 시스템 어디에서든 스크립트의 전체 경로를 입력해 실행합니다.
$ ./Hello_world.sh
$ pwd
$ /home/karthick/Hello_world
Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기

Shebang 없이 실행하면 어떻게 될까?

그렇다면 shebang 없이 프로그램을 실행하면 어떤 일이 벌어질까요? shebang이 없으면 프로그램은 현재 실행 중인 셸, 즉 여기서는 Bash(/bin/bash)로 전달됩니다.

예제를 통해 확인해 보겠습니다. shebang 없이 파이썬 스크립트를 만들고 실행하면, bash는 이 프로그램을 파이썬 인터프리터로 넘겨야 한다는 사실을 알지 못하고 현재 셸에서 그대로 실행해 버립니다.

$ cat > run-py.py
echo $SHELL
print("Hello world")

$ chmod +x run-py.py
$ ./run-py.py
Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기

이 경우 프로그램을 실행할 인터프리터를 직접 지정하거나, 항상 권장되는 방법인 shebang 라인을 추가하면 해결됩니다.

# which python3
$(which python3) /home/karthick/run_py.py
Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기

포크(Fork): 자식 프로세스 생성

스크립트를 호출하는 방법을 알았으니, 이제 스크립트를 실행했을 때 실제로 무슨 일이 일어나는지 이해해야 합니다. 위 예제처럼 스크립트를 실행하면 새로운 자식 프로세스가 생성되고(forking), 스크립트는 그 자식 프로세스에 전달됩니다. 아래 명령어를 실행하는 간단한 샘플 스크립트를 통해 스크립트가 자식 프로세스로 전달되는 것을 확인할 수 있습니다.

$ ps -ef --forest | grep -i bash
Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기

하나의 스크립트가 여러 개의 자식 프로세스를 만들 수도 있으며, 그 수는 코드에 따라 달라집니다. 특히 주목할 점은 서브스크립트(자식)에서 생성된 환경 변수는 스크립트가 종료되면 함께 사라진다는 것입니다. 자식 프로세스는 부모 프로세스가 export한 변수에는 접근할 수 있지만, 반대로 부모 프로세스는 자식 프로세스가 만든 변수에는 접근할 수 없습니다.

변수가 동작하는 방식과 변수 내보내기(export)에 대해 더 깊이 알고 싶다면 아래 글들을 참고하세요.

  • 셸 스크립팅에서 '리눅스 변수' 이해하고 작성하기
  • Bash에서 $$와 $BASHPID의 차이 배우기

소싱(Sourcing)이란?

"source"는 셸 내장 명령으로, 인자로 전달된 파일을 읽어 현재 셸 환경에서 코드를 실행합니다. 가장 흔한 활용 사례는 .bashrc.bash_profile의 설정을 수정한 후 source 명령으로 변경 사항을 다시 로드하는 것입니다.

$ type -a source
Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기

source 명령을 실행하는 구문은 두 가지가 있으며, 어느 쪽을 선택할지는 개인 취향에 따라 결정하면 됩니다.

$ source FILE_NAME [ARGUMENTS]
$ . FILE_NAME [ARGUMENTS]

소싱 동작 원리 실습

source가 실제로 어떻게 동작하는지 살펴보겠습니다. 두 개의 셸 스크립트를 만들겠습니다. 첫 번째 스크립트(Module.sh)는 변수와 함수를 담고 있고, 두 번째 스크립트(Main.sh)는 그 변수를 출력하고 함수를 호출합니다.

Module.sh 파일:

#!/usr/bin/env bash

VAR1=$(echo "Welcome to $1")

function f1(){
  echo “Function f1 is called”
}

Main.sh 파일:

#!/usr/bin/env bash

echo $VAR1
f1
Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기

스크립트에 실행 권한을 부여하고 메인 스크립트인 main.sh를 실행해 보겠습니다. 이 스크립트는 현재 셸 환경에서 함수 f1과 변수 VAR1을 찾으려 하지만, 해당 요소들이 존재하지 않아 command not found 오류가 발생합니다.

$ bash main.sh
Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기

이제 스크립트 안에서 source 명령을 사용해 보겠습니다. source는 변수와 함수를 현재 셸 환경에 로드하므로 main.sh에서도 이를 접근할 수 있게 됩니다.

Module.sh 파일:

#!/usr/bin/env bash

VAR1=$(echo "Welcome to $1")

function f1(){
  echo "Function f1 is called"
}

Main.sh 파일:

#!/usr/bin/env bash

source module.sh Tecmint
echo $VAR1
f1
Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기

이제 스크립트를 다시 실행해 결과를 확인해 보세요.

$ bash main.sh
Bash에서 소싱(source)과 포크(fork)의 차이점 완벽 이해하기

source는 Bash에서 셸 스크립트를 작성할 때 모듈화 프로그래밍 방식을 적용하는 데 매우 유용합니다. 코드를 작은 모듈 단위로 나누어 여러 프로그램에서 재사용할 수 있으며, 이를 통해 DRY(Don't Repeat Yourself) 원칙, 즉 같은 코드를 반복하지 않는 원칙을 지킬 수 있습니다.

이것으로 이 글을 마치겠습니다. 지금까지 Bash에서 소싱과 포크의 차이점을 간략하게 살펴보았습니다. 글을 읽고 소중한 피드백을 공유해 주시기 바랍니다.