배시(Bash)에서 source.은 동일한 기능을 하는 명령어로, 셸 스크립트 파일을 실행하는 데 사용합니다.

소개 🔗

source.은 파일을 실행하는 명령어입니다. 좀 이상하게 생기긴 했지만 .도 엄연한 하나의 명령어입니다.

예시:

다음과 같이 셸 스크립트 파일을 만듭니다. 여기서는 asdf.sh라는 이름으로 만들겠습니다:

echo Hello

다음 명령어로 셸 스크립트를 실행합니다:

source asdf.sh
. asdf.sh

source. 모두 asdf.sh를 실행합니다. Hello가 두 번 출력되는 것을 확인할 수 있습니다.

source vs bash 🔗

source(또는 .)와 유사한 명령어로 bash가 있습니다. 인자로 파일 이름을 주면 셸 스크립트 파일을 실행합니다. 다음과 같이 사용 방법도 같습니다:

source asdf.sh
bash asdf.h

이 둘의 차이가 무엇일까요?

역할 🔗

두 명령어 모두 셸 스크립트 파일을 실행하는 데 사용할 수 있습니다.

사용 셸 🔗

반면 이 둘은 새로운 셸을 만드는 데 있어 차이를 보입니다.

source: 현재 셸에서 스크립트 파일을 실행합니다.

bash: 새로운 셸을 만들어 스크립트 파일을 실행합니다. 셸에서 선언된 변수나 현재 작업 디렉터리(cd를 통해 이동할 수 있는 그것)의 위치는 해당 셸에서만 유효하며, 셸이 종료되면 모두 사라집니다.

이로 인해 몇 가지 차이가 발생합니다. 대표적으로 환경 변수 유효성cd로 인한 경로 유지에 관한 차이가 있습니다.

환경 변수 유효성 🔗

source: 스크립트 안에서 선언한 환경 변수를 스크립트 바깥에서 접근할 수 있습니다.

bash: 스크립트 안에서 선언한 환경 변수는 스크립트 바깥에서 접근할 수 없으며 스크립트가 끝나면 그대로 소멸합니다. 스크립트 바깥에서의 접근을 원한다면 export 명령어를 통해야 합니다.

예시:

먼저 asdf.sh 파일을 만듭니다:

TEST_VALUE=123
echo "In file: $TEST_VALUE"

이제 이 파일을 다음처럼 실행합니다 (반드시 bashsource보다 앞서 등장해야 합니다):

bash asdf.sh
echo "bash asdf.sh: $TEST_VALUE"
source asdf.sh
echo "source asdf.sh: $TEST_VALUE"

출력 결과:

In file: 123
bash asdf.sh:
In file: 123
source asdf.sh: 123

bash123이 출력되지 않은 반면, source123이 출력되었습니다. 여기서 우리는 bash로 인해 실행한 asdf.sh의 경우, 실행이 끝나면 더 이상 변수가 유효하지 않음을 확인할 수 있습니다.

cd로 인한 경로 유지 🔗

source: 스크립트 안에서 cd를 실행한 결과가 그대로 유지됩니다.

bash: 스크립트 안에서의 cd는 스크립트 안에서 유지되지만, 스크립트 바깥에서는 유지되지 않습니다.

예시:

먼저 asdf.sh 파일을 만듭니다. 이 예시에서는 /home/ubuntu에 만들겠습니다. (pwd는 현재 작업 디렉터리를 출력하는 명령어입니다):

echo "In file 1: $(pwd)"
cd ..
echo "In file 2: $(pwd)"

이제 이 파일을 다음처럼 실행합니다. (반드시 bashsource보다 앞서 등장해야 합니다):

pwd
bash asdf.sh
pwd
source asdf.sh
pwd

출력 결과:

/home/ubuntu
In file 1: /home/ubuntu
In file 2: /home
/home/ubuntu
In file 1: /home/ubuntu
In file 2: /home
/home

bash asdf.sh는 스크립트 파일 내부의 현재 작업 디렉터리를 바꾸었지만, 스크립트 파일 바깥은 연향을 받지 않았습니다. 반면, source는 스크립트 파일 바깥에서도 현재 작업 디렉터리에 영향을 주었습니다.

요약 🔗

  역할 사용 셸 환경 변수 유효성 cd로 인한 경로 유지
source 스크립트 파일 실행 현재 셸 ✔️ 파일 바깥에서 접근 가능 ✔️ 파일 바깥에서 유지됨
bash 스크립트 파일 실행 새로운 셸 ❌ 파일 바깥에서 접근 불가 ❌ 파일 바깥에서 유지 안 됨

source vs . 🔗

두 명령어의 기원: C 셸과 본 셸 🔗

C 셸(csh)과 본 셸(sh)은 각각 1978년, 1979년 만들어진 오래된 셸입니다. C 셸은 source, 본 셸은 . 명령어만 지원합니다.

배시의 두 명령어는 본 셸과 C 셸로부터 유래한 것으로 보입니다. 이를 통해 배시는 오래된 셸들과의 호환성을 확보할 수 있습니다.

source가 더 권장되는가: fish 셸 🔗

fish 셸의 개발자는 . 명령어에 대해 다른 명령어와 혼동되고, 발견하기 어려우며, .이라는 명령어를 모르는 사람으로 하여금 .을 지칭하거나 소리내어 읽을 수 없다는 문제가 있음을 지적했습니다. 이로 인해 아예 .을 폐기하고 source만을 지원하기로 했습니다1.

두 명령어의 기능이 다른 셸: Z 셸 🔗

Z 셸(zsh)은 조금 독특합니다.

source 명령어의 경우 배시처럼 현재 작업 디렉터리에서만 스크립트 파일을 찾는 것에서 끝나지 않습니다. 스크립트 파일을 찾을 수 없다면 PATH 환경 변수에 존재하는 경로들로부터도 스크립트 파일을 찾습니다2.

특이하게도 .source와 동일한 동작을 하지 않고 약간 차이가 있습니다. source와 반대 순서로 먼저 PATH 환경 변수를 찾고 그 다음 현재 작업 디렉터리에서 스크립트 파일을 찾습니다3.

혼동 주의: ./asdf.sh. asdf.sh 🔗

./asdf.sh. asdf.sh를 혼동하지 마세요. ./asdf.shbash asdf.sh와 동일합니다.

참고 🔗

  1. https://github.com/fish-shell/fish-shell/issues/310#issuecomment-22645318

    I think fish simply shouldn’t ever have ., considering it’s confusing (with auto-cd), non-discoverable, and cryptic (if I would see it in code, without knowing about it, I simply couldn’t say anything about it). But considering changing . to source would break lots of scripts, I decided to go with soft deprecation - the . command still works, …

  2. 17 Shell Builtin Commands - zsh

    source file [ arg … ] Same as ‘.’, except that the current directory is always searched and is always searched first, before directories in $path.

  3. 17 Shell Builtin Commands - zsh

    . file [ arg … ] If file does not contain a slash, or if PATH_DIRS is set, the shell looks in the components of $path to find the directory containing file. Files in the current directory are not read unless ‘.’ appears somewhere in $path.