배시(Bash)에서 source와 .은 동일한 기능을 하는 명령어로, 셸 스크립트 파일을 실행하는 데 사용합니다.
source와 .은 파일을 실행하는 명령어입니다. 좀 이상하게 생기긴 했지만 .도 엄연한 하나의 명령어입니다.
다음과 같이 셸 스크립트 파일을 만듭니다. 여기서는 asdf.sh라는 이름으로 만들겠습니다:
echo Hello
다음 명령어로 셸 스크립트를 실행합니다:
source asdf.sh
. asdf.sh
source와 . 모두 asdf.sh를 실행합니다. Hello가 두 번 출력되는 것을 확인할 수 있습니다.
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"
이제 이 파일을 다음처럼 실행합니다 (반드시 bash가 source보다 앞서 등장해야 합니다):
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
bash는 123이 출력되지 않은 반면, source는 123이 출력되었습니다. 여기서 우리는 bash로 인해 실행한 asdf.sh의 경우, 실행이 끝나면 더 이상 변수가 유효하지 않음을 확인할 수 있습니다.
source: 스크립트 안에서 cd를 실행한 결과가 그대로 유지됩니다.
bash: 스크립트 안에서의 cd는 스크립트 안에서 유지되지만, 스크립트 바깥에서는 유지되지 않습니다.
먼저 asdf.sh 파일을 만듭니다. 이 예시에서는 /home/ubuntu에 만들겠습니다. (pwd는 현재 작업 디렉터리를 출력하는 명령어입니다):
echo "In file 1: $(pwd)"
cd ..
echo "In file 2: $(pwd)"
이제 이 파일을 다음처럼 실행합니다. (반드시 bash가 source보다 앞서 등장해야 합니다):
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 |
스크립트 파일 실행 | 새로운 셸 | ❌ 파일 바깥에서 접근 불가 | ❌ 파일 바깥에서 유지 안 됨 |
C 셸(csh)과 본 셸(sh)은 각각 1978년, 1979년 만들어진 오래된 셸입니다. C 셸은 source, 본 셸은 . 명령어만 지원합니다.
배시의 두 명령어는 본 셸과 C 셸로부터 유래한 것으로 보입니다. 이를 통해 배시는 오래된 셸들과의 호환성을 확보할 수 있습니다.
fish 셸의 개발자는 . 명령어에 대해 다른 명령어와 혼동되고, 발견하기 어려우며, .이라는 명령어를 모르는 사람으로 하여금 .을 지칭하거나 소리내어 읽을 수 없다는 문제가 있음을 지적했습니다. 이로 인해 아예 .을 폐기하고 source만을 지원하기로 했습니다1.
Z 셸(zsh)은 조금 독특합니다.
source 명령어의 경우 배시처럼 현재 작업 디렉터리에서만 스크립트 파일을 찾는 것에서 끝나지 않습니다. 스크립트 파일을 찾을 수 없다면 PATH 환경 변수에 존재하는 경로들로부터도 스크립트 파일을 찾습니다2.
특이하게도 .는 source와 동일한 동작을 하지 않고 약간 차이가 있습니다. source와 반대 순서로 먼저 PATH 환경 변수를 찾고 그 다음 현재 작업 디렉터리에서 스크립트 파일을 찾습니다3.
./asdf.sh와 . asdf.sh를 혼동하지 마세요. ./asdf.sh는 bash asdf.sh와 동일합니다.
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.tosourcewould break lots of scripts, I decided to go with soft deprecation - the.command still works, ...
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.
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.